difftreelog
perf mutate context if operating on only strong ref
in: master
4 files changed
crates/jrsonnet-evaluator/src/ctx.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/ctx.rs
+++ b/crates/jrsonnet-evaluator/src/ctx.rs
@@ -75,36 +75,56 @@
ctx.unwrap()
}
- pub fn with_var(&self, name: Rc<str>, value: Val) -> Result<Context> {
+ pub fn with_var(self, name: Rc<str>, value: Val) -> Context {
let mut new_bindings = HashMap::with_capacity(1);
new_bindings.insert(name, resolved_lazy_val!(value));
self.extend(new_bindings, None, None, None)
}
pub fn extend(
- &self,
+ self,
new_bindings: HashMap<Rc<str>, LazyVal>,
new_dollar: Option<ObjValue>,
new_this: Option<ObjValue>,
new_super_obj: Option<ObjValue>,
- ) -> Result<Context> {
- let dollar = new_dollar.or_else(|| self.0.dollar.clone());
- let this = new_this.or_else(|| self.0.this.clone());
- let super_obj = new_super_obj.or_else(|| self.0.super_obj.clone());
- let bindings = if new_bindings.is_empty() {
- self.0.bindings.clone()
- } else {
- self.0.bindings.extend(new_bindings)
- };
- Ok(Context(Rc::new(ContextInternals {
- dollar,
- this,
- super_obj,
- bindings,
- })))
+ ) -> Context {
+ match Rc::try_unwrap(self.0) {
+ Ok(mut ctx) => {
+ // Extended context aren't used by anything else, we can freely mutate it without cloning
+ if let Some(dollar) = new_dollar {
+ ctx.dollar = Some(dollar);
+ }
+ if let Some(this) = new_this {
+ ctx.this = Some(this);
+ }
+ if let Some(super_obj) = new_super_obj {
+ ctx.super_obj = Some(super_obj);
+ }
+ if !new_bindings.is_empty() {
+ ctx.bindings = ctx.bindings.extend(new_bindings);
+ }
+ Context(Rc::new(ctx))
+ }
+ Err(ctx) => {
+ let dollar = new_dollar.or_else(|| ctx.dollar.clone());
+ let this = new_this.or_else(|| ctx.this.clone());
+ let super_obj = new_super_obj.or_else(|| ctx.super_obj.clone());
+ let bindings = if new_bindings.is_empty() {
+ ctx.bindings.clone()
+ } else {
+ ctx.bindings.clone().extend(new_bindings)
+ };
+ Context(Rc::new(ContextInternals {
+ dollar,
+ this,
+ super_obj,
+ bindings,
+ }))
+ }
+ }
}
pub fn extend_unbound(
- &self,
+ self,
new_bindings: HashMap<Rc<str>, LazyBinding>,
new_dollar: Option<ObjValue>,
new_this: Option<ObjValue>,
@@ -116,7 +136,7 @@
for (k, v) in new_bindings.into_iter() {
new.insert(k, v.evaluate(this.clone(), super_obj.clone())?);
}
- self.extend(new, new_dollar, this, super_obj)
+ Ok(self.extend(new, new_dollar, this, super_obj))
}
pub fn into_weak(self) -> WeakContext {
WeakContext(Rc::downgrade(&self.0))
crates/jrsonnet-evaluator/src/evaluate.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/evaluate.rs
+++ b/crates/jrsonnet-evaluator/src/evaluate.rs
@@ -209,7 +209,7 @@
for item in list.iter() {
let item = item.unwrap_if_lazy()?;
out.push(evaluate_comp(
- context.with_var(var.clone(), item.clone())?,
+ context.clone().with_var(var.clone(), item.clone()),
value,
&specs[1..],
)?);
@@ -227,7 +227,7 @@
let future_this = FutureObjValue::new();
let context_creator = context_creator!(
closure!(clone context, clone new_bindings, |this: Option<ObjValue>, super_obj: Option<ObjValue>| {
- Ok(context.extend_unbound(
+ Ok(context.clone().extend_unbound(
new_bindings.clone().unwrap(),
context.dollar().clone().or_else(||this.clone()),
Some(this.unwrap()),
@@ -332,7 +332,7 @@
let new_bindings = FutureNewBindings::new();
let context_creator = context_creator!(
closure!(clone context, clone new_bindings, |this: Option<ObjValue>, super_obj: Option<ObjValue>| {
- Ok(context.extend_unbound(
+ Ok(context.clone().extend_unbound(
new_bindings.clone().unwrap(),
context.dollar().clone().or_else(||this.clone()),
None,
@@ -354,7 +354,7 @@
let key = evaluate(ctx.clone(), &obj.key)?;
let value = LazyBinding::Bindable(Rc::new(
closure!(clone ctx, clone obj.value, |this, _super_obj| {
- Ok(LazyVal::new_resolved(evaluate(ctx.extend(HashMap::new(), None, this, None)?, &value)?))
+ Ok(LazyVal::new_resolved(evaluate(ctx.clone().extend(HashMap::new(), None, this, None), &value)?))
}),
));
crates/jrsonnet-evaluator/src/function.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/function.rs
+++ b/crates/jrsonnet-evaluator/src/function.rs
@@ -57,7 +57,7 @@
out.insert(p.0.clone(), val);
}
- Ok(body_ctx.unwrap_or(ctx).extend(out, None, None, None)?)
+ Ok(body_ctx.unwrap_or(ctx).extend(out, None, None, None))
}
pub fn parse_function_call_map(
@@ -106,7 +106,7 @@
out.insert(p.0.clone(), val);
}
- Ok(body_ctx.unwrap_or(ctx).extend(out, None, None, None)?)
+ Ok(body_ctx.unwrap_or(ctx).extend(out, None, None, None))
}
pub(crate) fn place_args(
@@ -135,7 +135,7 @@
out.insert(p.0.clone(), resolved_lazy_val!(val));
}
- Ok(body_ctx.unwrap_or(ctx).extend(out, None, None, None)?)
+ Ok(body_ctx.unwrap_or(ctx).extend(out, None, None, None))
}
#[macro_export]
crates/jrsonnet-evaluator/src/map.rsdiffbeforeafterboth10pub struct LayeredHashMap<K: Hash, V>(Rc<LayeredHashMapInternals<K, V>>);10pub struct LayeredHashMap<K: Hash, V>(Rc<LayeredHashMapInternals<K, V>>);111112impl<K: Hash + Eq, V> LayeredHashMap<K, V> {12impl<K: Hash + Eq, V> LayeredHashMap<K, V> {13 pub fn extend(&self, new_layer: HashMap<K, V>) -> Self {13 pub fn extend(self, new_layer: HashMap<K, V>) -> Self {14 let super_map = self.clone();14 match Rc::try_unwrap(self.0) {15 Ok(mut map) => {16 map.current.extend(new_layer);17 LayeredHashMap(Rc::new(map))18 }15 LayeredHashMap(Rc::new(LayeredHashMapInternals {19 Err(this) => LayeredHashMap(Rc::new(LayeredHashMapInternals {16 parent: Some(super_map),20 parent: Some(LayeredHashMap(this)),17 current: new_layer,21 current: new_layer,18 }))22 })),23 }19 }24 }202521 pub fn get<Q: ?Sized>(&self, key: &Q) -> Option<&V>26 pub fn get<Q: ?Sized>(&self, key: &Q) -> Option<&V>