difftreelog
perf use fxhash
in: master
8 files changed
Cargo.lockdiffbeforeafterboth--- a/Cargo.lock
+++ b/Cargo.lock
@@ -172,6 +172,7 @@
"jrsonnet-stdlib",
"md5",
"pathdiff",
+ "rustc-hash",
"serde",
"serde_json",
"structdump",
@@ -322,6 +323,12 @@
]
[[package]]
+name = "rustc-hash"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
+
+[[package]]
name = "ryu"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
crates/jrsonnet-evaluator/Cargo.tomldiffbeforeafterboth--- a/crates/jrsonnet-evaluator/Cargo.toml
+++ b/crates/jrsonnet-evaluator/Cargo.toml
@@ -9,7 +9,7 @@
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[features]
-default = ["serialized-stdlib", "faster", "explaining-traces"]
+default = ["serialized-stdlib", "faster", "explaining-traces", "serde-json"]
# Serializes standard library AST instead of parsing them every run
serialized-stdlib = ["serde", "bincode", "jrsonnet-parser/deserialize"]
# Allow to convert Val into serde_json::Value and backwards
@@ -35,6 +35,7 @@
md5 = "0.7.0"
base64 = "0.12.3"
+rustc-hash = "1.1.0"
# Serialized stdlib
[dependencies.serde]
crates/jrsonnet-evaluator/src/builtin/mod.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/builtin/mod.rs
+++ b/crates/jrsonnet-evaluator/src/builtin/mod.rs
@@ -158,7 +158,7 @@
("std", "native") => parse_args!(context, "std.native", args, 1, [
0, x: [Val::Str]!!Val::Str, vec![ValType::Str];
], {
- Ok(with_state(|s| s.settings().ext_natives.get(&x).cloned()).map(|v| Val::Func(FuncVal::NativeExt(x.clone(), v))).ok_or_else(
+ Ok(with_state(|s| s.settings().ext_natives.get(&x).cloned()).map(|v| Val::Func(Rc::new(FuncVal::NativeExt(x.clone(), v)))).ok_or_else(
|| UndefinedExternalFunction(x),
)?)
})?,
@@ -212,7 +212,7 @@
if arr.len() <= 1 {
return Ok(Val::Arr(arr))
}
- Ok(Val::Arr(sort::sort(context, arr, keyF)?))
+ Ok(Val::Arr(sort::sort(context, arr, &keyF)?))
})?,
// faster
("std", "format") => parse_args!(context, "std.format", args, 2, [
crates/jrsonnet-evaluator/src/ctx.rsdiffbeforeafterboth1use crate::{2 error::Error::*, future_wrapper, map::LayeredHashMap, rc_fn_helper, resolved_lazy_val,3 LazyBinding, LazyVal, ObjValue, Result, Val,4};5use std::{cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc};67rc_fn_helper!(8 ContextCreator,9 context_creator,10 dyn Fn(Option<ObjValue>, Option<ObjValue>) -> Result<Context>11);1213future_wrapper!(Context, FutureContext);1415struct ContextInternals {16 dollar: Option<ObjValue>,17 this: Option<ObjValue>,18 super_obj: Option<ObjValue>,19 bindings: LayeredHashMap<Rc<str>, LazyVal>,20}21impl Debug for ContextInternals {22 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {23 f.debug_struct("Context")24 .field("this", &self.this.as_ref().map(|e| Rc::as_ptr(&e.0)))25 .field("bindings", &self.bindings)26 .finish()27 }28}2930#[derive(Debug, Clone)]31pub struct Context(Rc<ContextInternals>);32impl Context {33 pub fn new_future() -> FutureContext {34 FutureContext(Rc::new(RefCell::new(None)))35 }3637 pub fn dollar(&self) -> &Option<ObjValue> {38 &self.0.dollar39 }4041 pub fn this(&self) -> &Option<ObjValue> {42 &self.0.this43 }4445 pub fn super_obj(&self) -> &Option<ObjValue> {46 &self.0.super_obj47 }4849 pub fn new() -> Context {50 Context(Rc::new(ContextInternals {51 dollar: None,52 this: None,53 super_obj: None,54 bindings: LayeredHashMap::default(),55 }))56 }5758 pub fn binding(&self, name: Rc<str>) -> Result<LazyVal> {59 Ok(self60 .061 .bindings62 .get(&name)63 .cloned()64 .ok_or_else(|| UnknownVariable(name))?)65 }66 pub fn into_future(self, ctx: FutureContext) -> Context {67 {68 ctx.0.borrow_mut().replace(self);69 }70 ctx.unwrap()71 }7273 pub fn with_var(self, name: Rc<str>, value: Val) -> Context {74 let mut new_bindings = HashMap::with_capacity(1);75 new_bindings.insert(name, resolved_lazy_val!(value));76 self.extend(new_bindings, None, None, None)77 }7879 pub fn extend(80 self,81 new_bindings: HashMap<Rc<str>, LazyVal>,82 new_dollar: Option<ObjValue>,83 new_this: Option<ObjValue>,84 new_super_obj: Option<ObjValue>,85 ) -> Context {86 match Rc::try_unwrap(self.0) {87 Ok(mut ctx) => {88 // Extended context aren't used by anything else, we can freely mutate it without cloning89 if let Some(dollar) = new_dollar {90 ctx.dollar = Some(dollar);91 }92 if let Some(this) = new_this {93 ctx.this = Some(this);94 }95 if let Some(super_obj) = new_super_obj {96 ctx.super_obj = Some(super_obj);97 }98 if !new_bindings.is_empty() {99 ctx.bindings = ctx.bindings.extend(new_bindings);100 }101 Context(Rc::new(ctx))102 }103 Err(ctx) => {104 let dollar = new_dollar.or_else(|| ctx.dollar.clone());105 let this = new_this.or_else(|| ctx.this.clone());106 let super_obj = new_super_obj.or_else(|| ctx.super_obj.clone());107 let bindings = if new_bindings.is_empty() {108 ctx.bindings.clone()109 } else {110 ctx.bindings.clone().extend(new_bindings)111 };112 Context(Rc::new(ContextInternals {113 dollar,114 this,115 super_obj,116 bindings,117 }))118 }119 }120 }121 pub fn extend_unbound(122 self,123 new_bindings: HashMap<Rc<str>, LazyBinding>,124 new_dollar: Option<ObjValue>,125 new_this: Option<ObjValue>,126 new_super_obj: Option<ObjValue>,127 ) -> Result<Context> {128 let this = new_this.or_else(|| self.0.this.clone());129 let super_obj = new_super_obj.or_else(|| self.0.super_obj.clone());130 let mut new = HashMap::with_capacity(new_bindings.len());131 for (k, v) in new_bindings.into_iter() {132 new.insert(k, v.evaluate(this.clone(), super_obj.clone())?);133 }134 Ok(self.extend(new, new_dollar, this, super_obj))135 }136 #[cfg(feature = "unstable")]137 pub fn into_weak(self) -> WeakContext {138 WeakContext(Rc::downgrade(&self.0))139 }140}141142impl Default for Context {143 fn default() -> Self {144 Self::new()145 }146}147148impl PartialEq for Context {149 fn eq(&self, other: &Self) -> bool {150 Rc::ptr_eq(&self.0, &other.0)151 }152}153154#[cfg(feature = "unstable")]155#[derive(Debug, Clone)]156pub struct WeakContext(std::rc::Weak<ContextInternals>);157#[cfg(feature = "unstable")]158impl WeakContext {159 pub fn upgrade(&self) -> Context {160 Context(self.0.upgrade().expect("context is removed"))161 }162}163#[cfg(feature = "unstable")]164impl PartialEq for WeakContext {165 fn eq(&self, other: &Self) -> bool {166 self.0.ptr_eq(&other.0)167 }168}1use crate::{2 error::Error::*, future_wrapper, map::LayeredHashMap, rc_fn_helper, resolved_lazy_val,3 LazyBinding, LazyVal, ObjValue, Result, Val,4};5use rustc_hash::FxHashMap;6use std::hash::BuildHasherDefault;7use std::{cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc};89rc_fn_helper!(10 ContextCreator,11 context_creator,12 dyn Fn(Option<ObjValue>, Option<ObjValue>) -> Result<Context>13);1415future_wrapper!(Context, FutureContext);1617struct ContextInternals {18 dollar: Option<ObjValue>,19 this: Option<ObjValue>,20 super_obj: Option<ObjValue>,21 bindings: LayeredHashMap<Rc<str>, LazyVal>,22}23impl Debug for ContextInternals {24 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {25 f.debug_struct("Context")26 .field("this", &self.this.as_ref().map(|e| Rc::as_ptr(&e.0)))27 .field("bindings", &self.bindings)28 .finish()29 }30}3132#[derive(Debug, Clone)]33pub struct Context(Rc<ContextInternals>);34impl Context {35 pub fn new_future() -> FutureContext {36 FutureContext(Rc::new(RefCell::new(None)))37 }3839 pub fn dollar(&self) -> &Option<ObjValue> {40 &self.0.dollar41 }4243 pub fn this(&self) -> &Option<ObjValue> {44 &self.0.this45 }4647 pub fn super_obj(&self) -> &Option<ObjValue> {48 &self.0.super_obj49 }5051 pub fn new() -> Context {52 Context(Rc::new(ContextInternals {53 dollar: None,54 this: None,55 super_obj: None,56 bindings: LayeredHashMap::default(),57 }))58 }5960 pub fn binding(&self, name: Rc<str>) -> Result<LazyVal> {61 Ok(self62 .063 .bindings64 .get(&name)65 .cloned()66 .ok_or_else(|| UnknownVariable(name))?)67 }68 pub fn into_future(self, ctx: FutureContext) -> Context {69 {70 ctx.0.borrow_mut().replace(self);71 }72 ctx.unwrap()73 }7475 pub fn with_var(self, name: Rc<str>, value: Val) -> Context {76 let mut new_bindings =77 FxHashMap::with_capacity_and_hasher(1, BuildHasherDefault::default());78 new_bindings.insert(name, resolved_lazy_val!(value));79 self.extend(new_bindings, None, None, None)80 }8182 pub fn extend(83 self,84 new_bindings: FxHashMap<Rc<str>, LazyVal>,85 new_dollar: Option<ObjValue>,86 new_this: Option<ObjValue>,87 new_super_obj: Option<ObjValue>,88 ) -> Context {89 match Rc::try_unwrap(self.0) {90 Ok(mut ctx) => {91 // Extended context aren't used by anything else, we can freely mutate it without cloning92 if let Some(dollar) = new_dollar {93 ctx.dollar = Some(dollar);94 }95 if let Some(this) = new_this {96 ctx.this = Some(this);97 }98 if let Some(super_obj) = new_super_obj {99 ctx.super_obj = Some(super_obj);100 }101 if !new_bindings.is_empty() {102 ctx.bindings = ctx.bindings.extend(new_bindings);103 }104 Context(Rc::new(ctx))105 }106 Err(ctx) => {107 let dollar = new_dollar.or_else(|| ctx.dollar.clone());108 let this = new_this.or_else(|| ctx.this.clone());109 let super_obj = new_super_obj.or_else(|| ctx.super_obj.clone());110 let bindings = if new_bindings.is_empty() {111 ctx.bindings.clone()112 } else {113 ctx.bindings.clone().extend(new_bindings)114 };115 Context(Rc::new(ContextInternals {116 dollar,117 this,118 super_obj,119 bindings,120 }))121 }122 }123 }124 pub fn extend_unbound(125 self,126 new_bindings: HashMap<Rc<str>, LazyBinding>,127 new_dollar: Option<ObjValue>,128 new_this: Option<ObjValue>,129 new_super_obj: Option<ObjValue>,130 ) -> Result<Context> {131 let this = new_this.or_else(|| self.0.this.clone());132 let super_obj = new_super_obj.or_else(|| self.0.super_obj.clone());133 let mut new =134 FxHashMap::with_capacity_and_hasher(new_bindings.len(), BuildHasherDefault::default());135 for (k, v) in new_bindings.into_iter() {136 new.insert(k, v.evaluate(this.clone(), super_obj.clone())?);137 }138 Ok(self.extend(new, new_dollar, this, super_obj))139 }140 #[cfg(feature = "unstable")]141 pub fn into_weak(self) -> WeakContext {142 WeakContext(Rc::downgrade(&self.0))143 }144}145146impl Default for Context {147 fn default() -> Self {148 Self::new()149 }150}151152impl PartialEq for Context {153 fn eq(&self, other: &Self) -> bool {154 Rc::ptr_eq(&self.0, &other.0)155 }156}157158#[cfg(feature = "unstable")]159#[derive(Debug, Clone)]160pub struct WeakContext(std::rc::Weak<ContextInternals>);161#[cfg(feature = "unstable")]162impl WeakContext {163 pub fn upgrade(&self) -> Context {164 Context(self.0.upgrade().expect("context is removed"))165 }166}167#[cfg(feature = "unstable")]168impl PartialEq for WeakContext {169 fn eq(&self, other: &Self) -> bool {170 self.0.ptr_eq(&other.0)171 }172}crates/jrsonnet-evaluator/src/evaluate.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/evaluate.rs
+++ b/crates/jrsonnet-evaluator/src/evaluate.rs
@@ -9,6 +9,7 @@
ForSpecData, IfSpecData, LiteralType, LocExpr, Member, ObjBody, ParamsDesc, UnaryOpType,
Visibility,
};
+use rustc_hash::FxHashMap;
use std::{collections::HashMap, rc::Rc};
pub fn evaluate_binding(b: &BindSpec, context_creator: ContextCreator) -> (Rc<str>, LazyBinding) {
@@ -45,7 +46,7 @@
}
pub fn evaluate_method(ctx: Context, name: Rc<str>, params: ParamsDesc, body: LocExpr) -> Val {
- Val::Func(FuncVal::Normal(Rc::new(FuncDesc {
+ Val::Func(Rc::new(FuncVal::Normal(FuncDesc {
name,
ctx,
params,
@@ -351,7 +352,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.clone().extend(HashMap::new(), None, this, None), &value)?))
+ Ok(LazyVal::new_resolved(evaluate(ctx.clone().extend(FxHashMap::default(), None, this, None), &value)?))
}),
));
@@ -468,7 +469,7 @@
} else if let Some(Val::Str(n)) =
v.get("__intristic_namespace__".into())?
{
- Ok(Val::Func(FuncVal::Intristic(n, s)))
+ Ok(Val::Func(Rc::new(FuncVal::Intristic(n, s))))
} else {
throw!(NoSuchField(s))
}
crates/jrsonnet-evaluator/src/function.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/function.rs
+++ b/crates/jrsonnet-evaluator/src/function.rs
@@ -1,7 +1,8 @@
use crate::{error::Error::*, evaluate, lazy_val, resolved_lazy_val, throw, Context, Result, Val};
use closure::closure;
use jrsonnet_parser::{ArgsDesc, ParamsDesc};
-use std::{collections::HashMap, rc::Rc};
+use rustc_hash::FxHashMap;
+use std::{collections::HashMap, hash::BuildHasherDefault, rc::Rc};
const NO_DEFAULT_CONTEXT: &str =
"no default context set for call with defined default parameter value";
@@ -20,7 +21,7 @@
args: &ArgsDesc,
tailstrict: bool,
) -> Result<Context> {
- let mut out = HashMap::with_capacity(params.len());
+ let mut out = HashMap::with_capacity_and_hasher(params.len(), BuildHasherDefault::default());
let mut positioned_args = vec![None; params.0.len()];
for (id, arg) in args.iter().enumerate() {
let idx = if let Some(name) = &arg.0 {
@@ -67,7 +68,7 @@
args: &HashMap<Rc<str>, Val>,
tailstrict: bool,
) -> Result<Context> {
- let mut out = HashMap::with_capacity(params.len());
+ let mut out = FxHashMap::with_capacity_and_hasher(params.len(), BuildHasherDefault::default());
let mut positioned_args = vec![None; params.0.len()];
for (name, val) in args.iter() {
let idx = params
@@ -115,7 +116,7 @@
params: &ParamsDesc,
args: &[Val],
) -> Result<Context> {
- let mut out = HashMap::with_capacity(params.len());
+ let mut out = FxHashMap::with_capacity_and_hasher(params.len(), BuildHasherDefault::default());
let mut positioned_args = vec![None; params.0.len()];
for (id, arg) in args.iter().enumerate() {
if id >= params.len() {
crates/jrsonnet-evaluator/src/map.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/map.rs
+++ b/crates/jrsonnet-evaluator/src/map.rs
@@ -1,16 +1,17 @@
-use std::{borrow::Borrow, collections::HashMap, hash::Hash, rc::Rc};
+use rustc_hash::FxHashMap;
+use std::{borrow::Borrow, hash::Hash, rc::Rc};
#[derive(Default, Debug)]
struct LayeredHashMapInternals<K: Hash, V> {
parent: Option<LayeredHashMap<K, V>>,
- current: HashMap<K, V>,
+ current: FxHashMap<K, V>,
}
#[derive(Debug)]
pub struct LayeredHashMap<K: Hash, V>(Rc<LayeredHashMapInternals<K, V>>);
impl<K: Hash + Eq, V> LayeredHashMap<K, V> {
- pub fn extend(self, new_layer: HashMap<K, V>) -> Self {
+ pub fn extend(self, new_layer: FxHashMap<K, V>) -> Self {
match Rc::try_unwrap(self.0) {
Ok(mut map) => {
map.current.extend(new_layer);
@@ -45,7 +46,7 @@
fn default() -> Self {
LayeredHashMap(Rc::new(LayeredHashMapInternals {
parent: None,
- current: HashMap::new(),
+ current: FxHashMap::default(),
}))
}
}
crates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/val.rs
+++ b/crates/jrsonnet-evaluator/src/val.rs
@@ -71,15 +71,16 @@
pub body: LocExpr,
}
-#[derive(Debug, Clone)]
+#[derive(Debug)]
pub enum FuncVal {
/// Plain function implemented in jsonnet
- Normal(Rc<FuncDesc>),
+ Normal(FuncDesc),
/// Standard library function
Intristic(Rc<str>, Rc<str>),
/// Library functions implemented in native
NativeExt(Rc<str>, Rc<NativeCallback>),
}
+
impl PartialEq for FuncVal {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
@@ -212,8 +213,9 @@
Lazy(LazyVal),
Arr(Rc<Vec<Val>>),
Obj(ObjValue),
- Func(FuncVal),
+ Func(Rc<FuncVal>),
}
+
macro_rules! matches_unwrap {
($e: expr, $p: pat, $r: expr) => {
match $e {