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
before · crates/jsonnet-evaluator/src/obj.rs
1use crate::{evaluate_binary_op, Binding, Val};2use jsonnet_parser::{BinaryOpType, Visibility};3use std::{4	collections::{BTreeMap, BTreeSet},5	fmt::Debug,6	rc::Rc,7};89#[derive(Debug)]10pub struct ObjMember {11	pub add: bool,12	pub visibility: Visibility,13	pub invoke: Binding,14}1516#[derive(Debug)]17pub struct ObjValueInternals {18	super_obj: Option<ObjValue>,19	this_entries: Rc<BTreeMap<String, ObjMember>>,20}21pub struct ObjValue(pub(crate) Rc<ObjValueInternals>);22impl Debug for ObjValue {23	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {24		if let Some(super_obj) = self.0.super_obj.as_ref() {25			if f.alternate() {26				write!(f, "{:#?}", super_obj)?;27			} else {28				write!(f, "{:?}", super_obj)?;29			}30			write!(f, " + ")?;31		}32		let mut debug = f.debug_struct("ObjValue");33		debug.field("$ptr", &Rc::as_ptr(&self.0));34		for (name, member) in self.0.this_entries.iter() {35			debug.field(name, member);36		}37		debug.finish_non_exhaustive()38		// .field("fields", &self.fields())39		// .finish_non_exhaustive()40	}41}4243impl ObjValue {44	pub fn new(45		super_obj: Option<ObjValue>,46		this_entries: Rc<BTreeMap<String, ObjMember>>,47	) -> ObjValue {48		ObjValue(Rc::new(ObjValueInternals {49			super_obj,50			this_entries,51		}))52	}53	pub fn with_super(&self, super_obj: ObjValue) -> ObjValue {54		match &self.0.super_obj {55			None => ObjValue::new(Some(super_obj), self.0.this_entries.clone()),56			Some(v) => ObjValue::new(Some(v.with_super(super_obj)), self.0.this_entries.clone()),57		}58	}59	pub fn fields(&self) -> BTreeSet<String> {60		let mut fields = BTreeSet::new();61		self.0.this_entries.keys().for_each(|k| {62			fields.insert(k.clone());63		});64		if self.0.super_obj.is_some() {65			for field in self.0.super_obj.clone().unwrap().fields() {66				fields.insert(field);67			}68		}69		fields70	}71	pub fn get(&self, key: &str) -> Option<Val> {72		// TODO: Cache get_raw result73		self.get_raw(key, self)74	}75	fn get_raw(&self, key: &str, real_this: &ObjValue) -> Option<Val> {76		match (self.0.this_entries.get(key), &self.0.super_obj) {77			(Some(k), None) => Some(k.invoke.0(78				Some(real_this.clone()),79				self.0.super_obj.clone(),80			)),81			(Some(k), Some(s)) => {82				let our = k.invoke.0(Some(real_this.clone()), self.0.super_obj.clone());83				if k.add {84					s.get_raw(key, real_this).map_or(Some(our.clone()), |v| {85						Some(evaluate_binary_op(&v, BinaryOpType::Add, &our))86					})87				} else {88					Some(our)89				}90			}91			(None, Some(s)) => s.get_raw(key, real_this),92			(None, None) => None,93		}94	}95}96impl Clone for ObjValue {97	fn clone(&self) -> Self {98		ObjValue(self.0.clone())99	}100}101impl PartialEq for ObjValue {102	fn eq(&self, other: &Self) -> bool {103		Rc::ptr_eq(&self.0, &other.0)104	}105}
modifiedcrates/jsonnet-evaluator/src/val.rsdiffbeforeafterboth
--- a/crates/jsonnet-evaluator/src/val.rs
+++ b/crates/jsonnet-evaluator/src/val.rs
@@ -1,14 +1,54 @@
-use crate::{
-	lazy_binding, rc_fn_helper, Context, FunctionDefault, FunctionRhs, LazyBinding, ObjValue,
-};
+use crate::{lazy_binding, Context, FunctionDefault, FunctionRhs, LazyBinding, ObjValue};
 use closure::closure;
-use jsonnet_parser::{LiteralType, ParamsDesc};
+use jsonnet_parser::ParamsDesc;
 use std::{
+	cell::RefCell,
 	collections::HashMap,
 	fmt::{Debug, Display},
+	rc::Rc,
 };
 
-rc_fn_helper!(LazyVal, lazy_val, dyn Fn() -> Val);
+struct LazyValInternals {
+	pub f: Box<dyn Fn() -> Val>,
+	pub cached: RefCell<Option<Val>>,
+}
+#[derive(Clone)]
+pub struct LazyVal(Rc<LazyValInternals>);
+impl LazyVal {
+	pub fn new(f: Box<dyn Fn() -> Val>) -> Self {
+		LazyVal(Rc::new(LazyValInternals {
+			f,
+			cached: RefCell::new(None),
+		}))
+	}
+	pub fn evaluate(&self) -> Val {
+		{
+			let cached = self.0.cached.borrow();
+			if cached.is_some() {
+				return cached.clone().unwrap();
+			}
+		}
+		let result = (self.0.f)();
+		self.0.cached.borrow_mut().replace(result.clone());
+		result
+	}
+}
+#[macro_export]
+macro_rules! lazy_val {
+	($f: expr) => {
+		$crate::LazyVal::new(Box::new($f))
+	};
+}
+impl Debug for LazyVal {
+	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+		write!(f, "Lazy")
+	}
+}
+impl PartialEq for LazyVal {
+	fn eq(&self, other: &Self) -> bool {
+		Rc::ptr_eq(&self.0, &other.0)
+	}
+}
 
 #[derive(Debug, PartialEq, Clone)]
 pub struct FuncDesc {
@@ -64,7 +104,8 @@
 
 #[derive(Debug, PartialEq, Clone)]
 pub enum Val {
-	Literal(LiteralType),
+	Bool(bool),
+	Null,
 	Str(String),
 	Num(f64),
 	Lazy(LazyVal),
@@ -78,7 +119,7 @@
 impl Val {
 	pub fn unwrap_if_lazy(self) -> Self {
 		if let Val::Lazy(v) = self {
-			v.0().unwrap_if_lazy()
+			v.evaluate().unwrap_if_lazy()
 		} else {
 			self
 		}
@@ -97,7 +138,6 @@
 impl Display for Val {
 	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 		match self {
-			Val::Literal(v) => write!(f, "{}", v)?,
 			Val::Str(str) => write!(f, "\"{}\"", str)?,
 			Val::Num(n) => write!(f, "{}", n)?,
 			Val::Arr(values) => {
@@ -128,7 +168,7 @@
 				write!(f, "}}")?;
 			}
 			Val::Lazy(lazy) => {
-				write!(f, "{}", lazy.0())?;
+				write!(f, "{}", lazy.evaluate())?;
 			}
 			Val::Func(_) => {
 				write!(f, "<<FUNC>>")?;
@@ -140,9 +180,5 @@
 }
 
 pub fn bool_val(v: bool) -> Val {
-	if v {
-		Val::Literal(LiteralType::True)
-	} else {
-		Val::Literal(LiteralType::False)
-	}
+	Val::Bool(v)
 }