git.delta.rocks / jrsonnet / refs/commits / 9d2a45fdc434

difftreelog

perf cleanup ObjValue

Yaroslav Bolyukin2021-02-20parent: #67899df.patch.diff
in: master

2 files changed

modifiedcrates/jrsonnet-evaluator/src/builtin/manifest.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/builtin/manifest.rs
+++ b/crates/jrsonnet-evaluator/src/builtin/manifest.rs
@@ -81,7 +81,7 @@
 		}
 		Val::Obj(obj) => {
 			buf.push('{');
-			let fields = obj.visible_fields();
+			let fields = obj.fields();
 			if !fields.is_empty() {
 				if mtype != ManifestType::ToString && mtype != ManifestType::Minify {
 					buf.push('\n');
modifiedcrates/jrsonnet-evaluator/src/obj.rsdiffbeforeafterboth
1use crate::{evaluate_add_op, LazyBinding, Result, Val};1use crate::{evaluate_add_op, LazyBinding, Result, Val};
2use indexmap::IndexMap;
3use jrsonnet_interner::IStr;2use jrsonnet_interner::IStr;
4use jrsonnet_parser::{ExprLocation, Visibility};3use jrsonnet_parser::{ExprLocation, Visibility};
4use rustc_hash::FxHashMap;
5use std::hash::{Hash, Hasher};
5use std::{cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc};6use std::{cell::RefCell, fmt::Debug, rc::Rc};
67
7#[derive(Debug)]8#[derive(Debug)]
8pub struct ObjMember {9pub struct ObjMember {
13}14}
1415
15// Field => This16// Field => This
16type CacheKey = (IStr, usize);17type CacheKey = (IStr, ObjValue);
17#[derive(Debug)]18#[derive(Debug)]
18pub struct ObjValueInternals {19pub struct ObjValueInternals {
19 super_obj: Option<ObjValue>,20 super_obj: Option<ObjValue>,
21 this_obj: Option<ObjValue>,
20 this_entries: Rc<HashMap<IStr, ObjMember>>,22 this_entries: Rc<FxHashMap<IStr, ObjMember>>,
21 value_cache: RefCell<HashMap<CacheKey, Option<Val>>>,23 value_cache: RefCell<FxHashMap<CacheKey, Option<Val>>>,
22}24}
25
23#[derive(Clone)]26#[derive(Clone)]
48}51}
4952
50impl ObjValue {53impl ObjValue {
51 pub fn new(super_obj: Option<Self>, this_entries: Rc<HashMap<IStr, ObjMember>>) -> Self {54 pub fn new(super_obj: Option<Self>, this_entries: Rc<FxHashMap<IStr, ObjMember>>) -> Self {
52 Self(Rc::new(ObjValueInternals {55 Self(Rc::new(ObjValueInternals {
53 super_obj,56 super_obj,
57 this_obj: None,
54 this_entries,58 this_entries,
55 value_cache: RefCell::new(HashMap::new()),59 value_cache: RefCell::new(FxHashMap::default()),
56 }))60 }))
57 }61 }
58 pub fn new_empty() -> Self {62 pub fn new_empty() -> Self {
59 Self::new(None, Rc::new(HashMap::new()))63 Self::new(None, Rc::new(FxHashMap::default()))
60 }64 }
61 pub fn with_super(&self, super_obj: Self) -> Self {65 pub fn with_super(&self, super_obj: Self) -> Self {
62 match &self.0.super_obj {66 match &self.0.super_obj {
63 None => Self::new(Some(super_obj), self.0.this_entries.clone()),67 None => Self::new(Some(super_obj), self.0.this_entries.clone()),
64 Some(v) => Self::new(Some(v.with_super(super_obj)), self.0.this_entries.clone()),68 Some(v) => Self::new(Some(v.with_super(super_obj)), self.0.this_entries.clone()),
65 }69 }
66 }70 }
71 pub fn with_this(&self, this_obj: Self) -> Self {
72 Self(Rc::new(ObjValueInternals {
73 super_obj: self.0.super_obj.clone(),
74 this_obj: Some(this_obj),
75 this_entries: self.0.this_entries.clone(),
76 value_cache: RefCell::new(FxHashMap::default()),
77 }))
78 }
79
80 /// Run callback for every field found in object
67 pub fn enum_fields(&self, handler: &impl Fn(&IStr, &Visibility)) {81 pub(crate) fn enum_fields(&self, handler: &mut impl FnMut(&IStr, &Visibility) -> bool) -> bool {
68 if let Some(s) = &self.0.super_obj {82 if let Some(s) = &self.0.super_obj {
69 s.enum_fields(handler);83 if s.enum_fields(handler) {
84 return true;
85 }
70 }86 }
71 for (name, member) in self.0.this_entries.iter() {87 for (name, member) in self.0.this_entries.iter() {
72 handler(name, &member.visibility);88 if handler(name, &member.visibility) {
89 return true;
90 }
73 }91 }
92 false
74 }93 }
94
75 pub fn fields_visibility(&self) -> IndexMap<IStr, bool> {95 pub fn fields_visibility(&self) -> FxHashMap<IStr, bool> {
76 let out = Rc::new(RefCell::new(IndexMap::new()));96 let mut out = FxHashMap::default();
77 self.enum_fields(&|name, visibility| {97 self.enum_fields(&mut |name, visibility| {
78 let mut out = out.borrow_mut();
79 match visibility {98 match visibility {
80 Visibility::Normal => {99 Visibility::Normal => {
81 if !out.contains_key(name) {
82 out.insert(name.to_owned(), true);100 let entry = out.entry(name.to_owned());
83 }101 entry.or_insert(true);
84 }102 }
85 Visibility::Hidden => {103 Visibility::Hidden => {
86 out.insert(name.to_owned(), false);104 out.insert(name.to_owned(), false);
89 out.insert(name.to_owned(), true);107 out.insert(name.to_owned(), true);
90 }108 }
91 };109 };
110 false
92 });111 });
93 Rc::try_unwrap(out).unwrap().into_inner()112 out
94 }113 }
95 pub fn visible_fields(&self) -> Vec<IStr> {114 pub fn fields_ex(&self, include_hidden: bool) -> Vec<IStr> {
96 let mut visible_fields: Vec<_> = self115 let mut fields: Vec<_> = self
97 .fields_visibility()116 .fields_visibility()
98 .into_iter()117 .into_iter()
99 .filter(|(_k, v)| *v)118 .filter(|(_k, v)| include_hidden || *v)
100 .map(|(k, _)| k)119 .map(|(k, _)| k)
101 .collect();120 .collect();
102 visible_fields.sort();121 fields.sort_unstable();
103 visible_fields122 fields
104 }123 }
124 pub fn fields(&self) -> Vec<IStr> {
125 self.fields_ex(false)
126 }
127
128 pub fn field_visibility(&self, name: IStr) -> Option<Visibility> {
129 if let Some(m) = self.0.this_entries.get(&name) {
130 Some(match &m.visibility {
131 Visibility::Normal => self
132 .0
133 .super_obj
134 .as_ref()
135 .and_then(|super_obj| super_obj.field_visibility(name))
136 .unwrap_or(Visibility::Normal),
137 v => *v,
138 })
139 } else if let Some(super_obj) = &self.0.super_obj {
140 super_obj.field_visibility(name)
141 } else {
142 None
143 }
144 }
145
146 fn has_field_include_hidden(&self, name: IStr) -> bool {
147 if self.0.this_entries.contains_key(&name) {
148 true
149 } else if let Some(super_obj) = &self.0.super_obj {
150 super_obj.has_field_include_hidden(name)
151 } else {
152 false
153 }
154 }
155
156 pub fn has_field_ex(&self, name: IStr, include_hidden: bool) -> bool {
157 if include_hidden {
158 self.has_field_include_hidden(name)
159 } else {
160 self.has_field(name)
161 }
162 }
163 pub fn has_field(&self, name: IStr) -> bool {
164 self.field_visibility(name)
165 .map(|v| v.is_visible())
166 .unwrap_or(false)
167 }
168
105 pub fn get(&self, key: IStr) -> Result<Option<Val>> {169 pub fn get(&self, key: IStr) -> Result<Option<Val>> {
106 Ok(self.get_raw(key, None)?)170 self.get_raw(key, self.0.this_obj.as_ref())
107 }171 }
108 pub(crate) fn get_raw(&self, key: IStr, real_this: Option<&Self>) -> Result<Option<Val>> {172 pub(crate) fn get_raw(&self, key: IStr, real_this: Option<&Self>) -> Result<Option<Val>> {
109 let real_this = real_this.unwrap_or(self);173 let real_this = real_this.unwrap_or(self);
110 let cache_key = (key.clone(), Rc::as_ptr(&real_this.0) as usize);174 let cache_key = (key.clone(), real_this.clone());
111175
112 if let Some(v) = self.0.value_cache.borrow().get(&cache_key) {176 if let Some(v) = self.0.value_cache.borrow().get(&cache_key) {
113 return Ok(v.clone());177 return Ok(v.clone());
135 Ok(value)199 Ok(value)
136 }200 }
137 fn evaluate_this(&self, v: &ObjMember, real_this: &Self) -> Result<Val> {201 fn evaluate_this(&self, v: &ObjMember, real_this: &Self) -> Result<Val> {
138 Ok(v.invoke202 v.invoke
139 .evaluate(Some(real_this.clone()), self.0.super_obj.clone())?203 .evaluate(Some(real_this.clone()), self.0.super_obj.clone())?
140 .evaluate()?)204 .evaluate()
141 }205 }
142206
143 pub fn ptr_eq(a: &Self, b: &Self) -> bool {207 pub fn ptr_eq(a: &Self, b: &Self) -> bool {
150 }215 }
151}216}
217
218impl Eq for ObjValue {}
219impl Hash for ObjValue {
220 fn hash<H: Hasher>(&self, state: &mut H) {
221 state.write_usize(Rc::as_ptr(&self.0) as usize)
222 }
223}
152224