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
1use 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};
1010
11struct 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 result
34 }
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}
1252
13#[derive(Debug, PartialEq, Clone)]53#[derive(Debug, PartialEq, Clone)]
14pub struct FuncDesc {54pub struct FuncDesc {
64104
65#[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 self
84 }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}
141181
142pub 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