difftreelog
perf(evaluator) cache LazyVal/obj fields
in: master
2 files changed
crates/jsonnet-evaluator/src/obj.rsdiffbeforeafterboth--- a/crates/jsonnet-evaluator/src/obj.rs
+++ b/crates/jsonnet-evaluator/src/obj.rs
@@ -1,7 +1,8 @@
use crate::{evaluate_binary_op, Binding, Val};
use jsonnet_parser::{BinaryOpType, Visibility};
use std::{
- collections::{BTreeMap, BTreeSet},
+ cell::RefCell,
+ collections::{BTreeMap, BTreeSet, HashMap},
fmt::Debug,
rc::Rc,
};
@@ -17,6 +18,7 @@
pub struct ObjValueInternals {
super_obj: Option<ObjValue>,
this_entries: Rc<BTreeMap<String, ObjMember>>,
+ value_cache: RefCell<HashMap<String, Val>>,
}
pub struct ObjValue(pub(crate) Rc<ObjValueInternals>);
impl Debug for ObjValue {
@@ -48,6 +50,7 @@
ObjValue(Rc::new(ObjValueInternals {
super_obj,
this_entries,
+ value_cache: RefCell::new(HashMap::new()),
}))
}
pub fn with_super(&self, super_obj: ObjValue) -> ObjValue {
@@ -69,8 +72,14 @@
fields
}
pub fn get(&self, key: &str) -> Option<Val> {
- // TODO: Cache get_raw result
- self.get_raw(key, self)
+ if let Some(v) = self.0.value_cache.borrow().get(key) {
+ return Some(v.clone());
+ }
+ let v = self.get_raw(key, self).map(|v| v.unwrap_if_lazy());
+ if let Some(v) = v.clone() {
+ self.0.value_cache.borrow_mut().insert(key.to_owned(), v);
+ }
+ v
}
fn get_raw(&self, key: &str, real_this: &ObjValue) -> Option<Val> {
match (self.0.this_entries.get(key), &self.0.super_obj) {
crates/jsonnet-evaluator/src/val.rsdiffbeforeafterboth1use crate::{1use crate::{lazy_binding, Context, FunctionDefault, FunctionRhs, LazyBinding, ObjValue};2 lazy_binding, rc_fn_helper, Context, FunctionDefault, FunctionRhs, LazyBinding, ObjValue,3};4use closure::closure;2use closure::closure;5use jsonnet_parser::{LiteralType, ParamsDesc};3use jsonnet_parser::ParamsDesc;6use std::{4use std::{5 cell::RefCell,7 collections::HashMap,6 collections::HashMap,8 fmt::{Debug, Display},7 fmt::{Debug, Display},8 rc::Rc,9};9};101011struct LazyValInternals {12 pub f: Box<dyn Fn() -> Val>,13 pub cached: RefCell<Option<Val>>,14}15#[derive(Clone)]16pub struct LazyVal(Rc<LazyValInternals>);17impl LazyVal {11rc_fn_helper!(LazyVal, lazy_val, dyn Fn() -> Val);18 pub fn new(f: Box<dyn Fn() -> Val>) -> Self {19 LazyVal(Rc::new(LazyValInternals {20 f,21 cached: RefCell::new(None),22 }))23 }24 pub fn evaluate(&self) -> Val {25 {26 let cached = self.0.cached.borrow();27 if cached.is_some() {28 return cached.clone().unwrap();29 }30 }31 let result = (self.0.f)();32 self.0.cached.borrow_mut().replace(result.clone());33 result34 }35}36#[macro_export]37macro_rules! lazy_val {38 ($f: expr) => {39 $crate::LazyVal::new(Box::new($f))40 };41}42impl Debug for LazyVal {43 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {44 write!(f, "Lazy")45 }46}47impl PartialEq for LazyVal {48 fn eq(&self, other: &Self) -> bool {49 Rc::ptr_eq(&self.0, &other.0)50 }51}125213#[derive(Debug, PartialEq, Clone)]53#[derive(Debug, PartialEq, Clone)]14pub struct FuncDesc {54pub struct FuncDesc {6410465#[derive(Debug, PartialEq, Clone)]105#[derive(Debug, PartialEq, Clone)]66pub enum Val {106pub enum Val {67 Literal(LiteralType),107 Bool(bool),108 Null,68 Str(String),109 Str(String),69 Num(f64),110 Num(f64),70 Lazy(LazyVal),111 Lazy(LazyVal),78impl Val {119impl Val {79 pub fn unwrap_if_lazy(self) -> Self {120 pub fn unwrap_if_lazy(self) -> Self {80 if let Val::Lazy(v) = self {121 if let Val::Lazy(v) = self {81 v.0().unwrap_if_lazy()122 v.evaluate().unwrap_if_lazy()82 } else {123 } else {83 self124 self84 }125 }97impl Display for Val {138impl Display for Val {98 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {139 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {99 match self {140 match self {100 Val::Literal(v) => write!(f, "{}", v)?,101 Val::Str(str) => write!(f, "\"{}\"", str)?,141 Val::Str(str) => write!(f, "\"{}\"", str)?,102 Val::Num(n) => write!(f, "{}", n)?,142 Val::Num(n) => write!(f, "{}", n)?,103 Val::Arr(values) => {143 Val::Arr(values) => {128 write!(f, "}}")?;168 write!(f, "}}")?;129 }169 }130 Val::Lazy(lazy) => {170 Val::Lazy(lazy) => {131 write!(f, "{}", lazy.0())?;171 write!(f, "{}", lazy.evaluate())?;132 }172 }133 Val::Func(_) => {173 Val::Func(_) => {134 write!(f, "<<FUNC>>")?;174 write!(f, "<<FUNC>>")?;140}180}141181142pub fn bool_val(v: bool) -> Val {182pub fn bool_val(v: bool) -> Val {143 if v {144 Val::Literal(LiteralType::True)183 Val::Bool(v)145 } else {146 Val::Literal(LiteralType::False)147 }148}184}149185