diff --git a/src/ast/expr.rs b/src/ast/expr.rs index bfb4a9ef..c8cdedb1 100644 --- a/src/ast/expr.rs +++ b/src/ast/expr.rs @@ -489,11 +489,13 @@ impl Expr { #[cfg(not(feature = "no_object"))] Self::Map(x, ..) if self.is_constant() => { - Dynamic::from_map(x.0.iter().fold(x.1.clone(), |mut map, (k, v)| { - let value_ref = map.get_mut(k.name.as_str()).unwrap(); - *value_ref = v.get_literal_value().unwrap(); - map - })) + let mut map = x.1.clone(); + + for (k, v) in &x.0 { + *map.get_mut(k.name.as_str()).unwrap() = v.get_literal_value().unwrap(); + } + + Dynamic::from_map(map) } // Interpolated string diff --git a/src/eval/data_check.rs b/src/eval/data_check.rs index 2b031bcd..21dd0c54 100644 --- a/src/eval/data_check.rs +++ b/src/eval/data_check.rs @@ -18,23 +18,37 @@ impl Dynamic { /// Panics if any interior data is shared (should never happen). #[cfg(not(feature = "no_index"))] #[inline] - pub(crate) fn calc_array_sizes(array: &crate::Array, _top: bool) -> (usize, usize, usize) { - array - .iter() - .fold((0, 0, 0), |(ax, mx, sx), value| match value.0 { - Union::Array(..) => { - let (a, m, s) = value.calc_data_sizes(false); - (ax + a + 1, mx + m, sx + s) + pub(crate) fn calc_array_sizes(array: &crate::Array) -> (usize, usize, usize) { + let (mut ax, mut mx, mut sx) = (0, 0, 0); + + for value in array { + ax += 1; + + match value.0 { + Union::Array(ref a, ..) => { + let (a, m, s) = Self::calc_array_sizes(a); + ax += a; + mx += m; + sx += s; } - Union::Blob(ref a, ..) => (ax + 1 + a.len(), mx, sx), + Union::Blob(ref a, ..) => ax += 1 + a.len(), #[cfg(not(feature = "no_object"))] - Union::Map(..) => { - let (a, m, s) = value.calc_data_sizes(false); - (ax + a + 1, mx + m, sx + s) + Union::Map(ref m, ..) => { + let (a, m, s) = Self::calc_map_sizes(m); + ax += a; + mx += m; + sx += s; } - Union::Str(ref s, ..) => (ax + 1, mx, sx + s.len()), - _ => (ax + 1, mx, sx), - }) + Union::Str(ref s, ..) => sx += s.len(), + #[cfg(not(feature = "no_closure"))] + Union::Shared(..) => { + unreachable!("shared values discovered within data") + } + _ => (), + } + } + + (ax, mx, sx) } /// Recursively calculate the sizes of a map. /// @@ -45,23 +59,37 @@ impl Dynamic { /// Panics if any interior data is shared (should never happen). #[cfg(not(feature = "no_object"))] #[inline] - pub(crate) fn calc_map_sizes(map: &crate::Map, _top: bool) -> (usize, usize, usize) { - map.values() - .fold((0, 0, 0), |(ax, mx, sx), value| match value.0 { - #[cfg(not(feature = "no_index"))] - Union::Array(..) => { - let (a, m, s) = value.calc_data_sizes(false); - (ax + a, mx + m + 1, sx + s) + pub(crate) fn calc_map_sizes(map: &crate::Map) -> (usize, usize, usize) { + let (mut ax, mut mx, mut sx) = (0, 0, 0); + + for value in map.values() { + mx += 1; + + match value.0 { + Union::Array(ref a, ..) => { + let (a, m, s) = Self::calc_array_sizes(a); + ax += a; + mx += m; + sx += s; } - #[cfg(not(feature = "no_index"))] - Union::Blob(ref a, ..) => (ax + a.len(), mx, sx), - Union::Map(..) => { - let (a, m, s) = value.calc_data_sizes(false); - (ax + a, mx + m + 1, sx + s) + Union::Blob(ref a, ..) => ax += 1 + a.len(), + #[cfg(not(feature = "no_object"))] + Union::Map(ref m, ..) => { + let (a, m, s) = Self::calc_map_sizes(m); + ax += a; + mx += m; + sx += s; } - Union::Str(ref s, ..) => (ax, mx + 1, sx + s.len()), - _ => (ax, mx + 1, sx), - }) + Union::Str(ref s, ..) => sx += s.len(), + #[cfg(not(feature = "no_closure"))] + Union::Shared(..) => { + unreachable!("shared values discovered within data") + } + _ => (), + } + } + + (ax, mx, sx) } /// Recursively calculate the sizes of a value. /// @@ -74,11 +102,11 @@ impl Dynamic { pub(crate) fn calc_data_sizes(&self, _top: bool) -> (usize, usize, usize) { match self.0 { #[cfg(not(feature = "no_index"))] - Union::Array(ref arr, ..) => Self::calc_array_sizes(&**arr, _top), + Union::Array(ref arr, ..) => Self::calc_array_sizes(&**arr), #[cfg(not(feature = "no_index"))] Union::Blob(ref blob, ..) => (blob.len(), 0, 0), #[cfg(not(feature = "no_object"))] - Union::Map(ref map, ..) => Self::calc_map_sizes(&**map, _top), + Union::Map(ref map, ..) => Self::calc_map_sizes(&**map), Union::Str(ref s, ..) => (0, 0, s.len()), #[cfg(not(feature = "no_closure"))] Union::Shared(..) if _top => self.read_lock::().unwrap().calc_data_sizes(true), diff --git a/src/packages/array_basic.rs b/src/packages/array_basic.rs index b8396991..08c61b9e 100644 --- a/src/packages/array_basic.rs +++ b/src/packages/array_basic.rs @@ -237,7 +237,7 @@ pub mod array_functions { #[cfg(not(feature = "unchecked"))] if _ctx.engine().max_array_size() > 0 { let pad = len - array.len(); - let (a, m, s) = Dynamic::calc_array_sizes(array, true); + let (a, m, s) = Dynamic::calc_array_sizes(array); let (ax, mx, sx) = item.calc_data_sizes(true); _ctx.engine() diff --git a/src/types/interner.rs b/src/types/interner.rs index ce704bc4..118950cf 100644 --- a/src/types/interner.rs +++ b/src/types/interner.rs @@ -112,20 +112,22 @@ impl StringsInterner { // We leave at least two entries, one for the empty string, and one for the string // that has just been inserted. while self.cache.len() > MAX_INTERNED_STRINGS - 3 { - let (_, _, n) = self - .cache - .iter() - .fold((0, usize::MAX, 0), |(x, c, n), (&k, v)| { - if k != skip_hash - && (v.strong_count() < c || (v.strong_count() == c && v.len() > x)) - { - (v.len(), v.strong_count(), k) - } else { - (x, c, n) - } - }); + let mut max_len = 0; + let mut min_count = usize::MAX; + let mut index = 0; - self.cache.remove(&n); + for (&k, v) in &self.cache { + if k != skip_hash + && (v.strong_count() < min_count + || (v.strong_count() == min_count && v.len() > max_len)) + { + max_len = v.len(); + min_count = v.strong_count(); + index = k; + } + } + + self.cache.remove(&index); } }