From b25a25b23bf97bbae61214d4d1ef6472fa0e96cb Mon Sep 17 00:00:00 2001 From: Лач Date: Mon, 01 Jun 2020 18:38:51 +0000 Subject: [PATCH] perf(evaluator): cache LazyVal/obj fields --- --- 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, this_entries: Rc>, + value_cache: RefCell>, } pub struct ObjValue(pub(crate) Rc); 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 { - // 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 { match (self.0.this_entries.get(key), &self.0.super_obj) { --- 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 Val>, + pub cached: RefCell>, +} +#[derive(Clone)] +pub struct LazyVal(Rc); +impl LazyVal { + pub fn new(f: Box 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, "<>")?; @@ -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) } -- gitstuff