git.delta.rocks / jrsonnet / refs/commits / b25a25b23bf9

difftreelog

perf(evaluator) cache LazyVal/obj fields

Лач2020-06-01parent: #11818aa.patch.diff
in: master

2 files changed

modifiedcrates/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) {
modifiedcrates/jsonnet-evaluator/src/val.rsdiffbeforeafterboth
before · crates/jsonnet-evaluator/src/val.rs
1use crate::{2	lazy_binding, rc_fn_helper, Context, FunctionDefault, FunctionRhs, LazyBinding, ObjValue,3};4use closure::closure;5use jsonnet_parser::{LiteralType, ParamsDesc};6use std::{7	collections::HashMap,8	fmt::{Debug, Display},9};1011rc_fn_helper!(LazyVal, lazy_val, dyn Fn() -> Val);1213#[derive(Debug, PartialEq, Clone)]14pub struct FuncDesc {15	pub ctx: Context,16	pub params: ParamsDesc,17	pub eval_rhs: FunctionRhs,18	pub eval_default: FunctionDefault,19}20impl FuncDesc {21	// TODO: Check for unset variables22	pub fn evaluate(&self, args: Vec<(Option<String>, Val)>) -> Val {23		let mut new_bindings: HashMap<String, LazyBinding> = HashMap::new();24		let future_ctx = Context::new_future();2526		// self.params27		// 	.with_defaults()28		// 	.into_iter()29		// 	.for_each(|Param(name, default)| {30		// 		let default = Rc::new(*default.unwrap());31		// 		new_bindings.insert(32		// 			name,33		// 			binding!(move |_, _| Val::Lazy(lazy_val!(|| self34		// 				.eval_default35		// 				.036		// 				.default(future_ctx.unwrap(), *default.clone())))),37		// 		);38		// 	});39		for (name, val) in args.clone().into_iter().filter(|e| e.0.is_some()) {40			new_bindings.insert(41				name.as_ref().unwrap().clone(),42				lazy_binding!(43					closure!(clone val, |_, _| lazy_val!(closure!(clone val, || val.clone())))44				),45			);46		}47		for (i, param) in self.params.0.iter().enumerate() {48			if let Some((None, val)) = args.get(i) {49				new_bindings.insert(50					param.0.clone(),51					lazy_binding!(52						closure!(clone val, |_, _| lazy_val!(closure!(clone val, || val.clone())))53					),54				);55			}56		}57		let ctx = self58			.ctx59			.extend(new_bindings, None, None, None)60			.into_future(future_ctx);61		self.eval_rhs.0(ctx)62	}63}6465#[derive(Debug, PartialEq, Clone)]66pub enum Val {67	Literal(LiteralType),68	Str(String),69	Num(f64),70	Lazy(LazyVal),71	Arr(Vec<Val>),72	Obj(ObjValue),73	Func(FuncDesc),7475	// Library functions implemented in native76	Intristic(String, String),77}78impl Val {79	pub fn unwrap_if_lazy(self) -> Self {80		if let Val::Lazy(v) = self {81			v.0().unwrap_if_lazy()82		} else {83			self84		}85	}86	pub fn type_of(&self) -> &'static str {87		match self {88			Val::Str(..) => "string",89			Val::Num(..) => "number",90			Val::Arr(..) => "array",91			Val::Obj(..) => "object",92			Val::Func(..) => "function",93			_ => panic!("no native type found"),94		}95	}96}97impl Display for Val {98	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {99		match self {100			Val::Literal(v) => write!(f, "{}", v)?,101			Val::Str(str) => write!(f, "\"{}\"", str)?,102			Val::Num(n) => write!(f, "{}", n)?,103			Val::Arr(values) => {104				write!(f, "[")?;105				let mut first = true;106				for value in values {107					if first {108						first = false;109					} else {110						write!(f, ",")?;111					}112					write!(f, "{}", value)?;113				}114				write!(f, "]")?;115			}116			Val::Obj(value) => {117				write!(f, "{{")?;118				let mut first = true;119				for field in value.fields() {120					if first {121						first = false;122					} else {123						write!(f, ",")?;124					}125					write!(f, "\"{}\":", field)?;126					write!(f, "{}", value.get(&field).unwrap())?;127				}128				write!(f, "}}")?;129			}130			Val::Lazy(lazy) => {131				write!(f, "{}", lazy.0())?;132			}133			Val::Func(_) => {134				write!(f, "<<FUNC>>")?;135			}136			v => panic!("no json equivalent for {:?}", v),137		};138		Ok(())139	}140}141142pub fn bool_val(v: bool) -> Val {143	if v {144		Val::Literal(LiteralType::True)145	} else {146		Val::Literal(LiteralType::False)147	}148}