Simplify Array::pad.

This commit is contained in:
Stephen Chung 2022-12-26 17:32:46 +08:00
parent d47bfa431a
commit c5cb2d5e0f
2 changed files with 63 additions and 78 deletions

View File

@ -9,6 +9,60 @@ use std::borrow::Borrow;
use std::prelude::v1::*; use std::prelude::v1::*;
impl Dynamic { impl Dynamic {
/// Recursively calculate the sizes of an array.
///
/// Sizes returned are `(` [`Array`][crate::Array], [`Map`][crate::Map] and [`String`] `)`.
///
/// # Panics
///
/// 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)
}
Union::Blob(ref a, ..) => (ax + 1 + a.len(), mx, sx),
#[cfg(not(feature = "no_object"))]
Union::Map(..) => {
let (a, m, s) = value.calc_data_sizes(false);
(ax + a + 1, mx + m, sx + s)
}
Union::Str(ref s, ..) => (ax + 1, mx, sx + s.len()),
_ => (ax + 1, mx, sx),
})
}
/// Recursively calculate the sizes of a map.
///
/// Sizes returned are `(` [`Array`][crate::Array], [`Map`][crate::Map] and [`String`] `)`.
///
/// # Panics
///
/// 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)
}
#[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::Str(ref s, ..) => (ax, mx + 1, sx + s.len()),
_ => (ax, mx + 1, sx),
})
}
/// Recursively calculate the sizes of a value. /// Recursively calculate the sizes of a value.
/// ///
/// Sizes returned are `(` [`Array`][crate::Array], [`Map`][crate::Map] and [`String`] `)`. /// Sizes returned are `(` [`Array`][crate::Array], [`Map`][crate::Map] and [`String`] `)`.
@ -16,47 +70,15 @@ impl Dynamic {
/// # Panics /// # Panics
/// ///
/// Panics if any interior data is shared (should never happen). /// Panics if any interior data is shared (should never happen).
#[inline]
pub(crate) fn calc_data_sizes(&self, _top: bool) -> (usize, usize, usize) { pub(crate) fn calc_data_sizes(&self, _top: bool) -> (usize, usize, usize) {
match self.0 { match self.0 {
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
Union::Array(ref arr, ..) => { Union::Array(ref arr, ..) => Self::calc_array_sizes(&**arr, _top),
arr.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)
}
Union::Blob(ref a, ..) => (ax + 1 + a.len(), mx, sx),
#[cfg(not(feature = "no_object"))]
Union::Map(..) => {
let (a, m, s) = value.calc_data_sizes(false);
(ax + a + 1, mx + m, sx + s)
}
Union::Str(ref s, ..) => (ax + 1, mx, sx + s.len()),
_ => (ax + 1, mx, sx),
})
}
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
Union::Blob(ref blob, ..) => (blob.len(), 0, 0), Union::Blob(ref blob, ..) => (blob.len(), 0, 0),
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
Union::Map(ref map, ..) => { Union::Map(ref map, ..) => Self::calc_map_sizes(&**map, _top),
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)
}
#[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::Str(ref s, ..) => (ax, mx + 1, sx + s.len()),
_ => (ax, mx + 1, sx),
})
}
Union::Str(ref s, ..) => (0, 0, s.len()), Union::Str(ref s, ..) => (0, 0, s.len()),
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
Union::Shared(..) if _top => self.read_lock::<Self>().unwrap().calc_data_sizes(true), Union::Shared(..) if _top => self.read_lock::<Self>().unwrap().calc_data_sizes(true),

View File

@ -235,52 +235,15 @@ pub mod array_functions {
// Check if array will be over max size limit // Check if array will be over max size limit
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
{ if _ctx.engine().max_array_size() > 0 {
use crate::types::dynamic::Union; let pad = len - array.len();
let (a, m, s) = Dynamic::calc_array_sizes(array, true);
let (ax, mx, sx) = item.calc_data_sizes(true);
if _ctx.engine().max_array_size() > 0 && len > _ctx.engine().max_array_size() { _ctx.engine()
return Err( .throw_on_size((a + pad + ax * pad, m + mx * pad, s + sx * pad))?;
ERR::ErrorDataTooLarge("Size of array".to_string(), Position::NONE).into(),
);
}
let check_sizes = match item.0 {
Union::Str(..) => true,
Union::Array(..) => true,
#[cfg(not(feature = "no_object"))]
Union::Map(..) => true,
_ => false,
};
if check_sizes {
let mut arr_len = array.len();
let mut arr = Dynamic::from_array(mem::take(array));
let (mut a1, mut m1, mut s1) = arr.calc_data_sizes(true);
let (a2, m2, s2) = item.calc_data_sizes(true);
{
let mut guard = arr.write_lock::<Array>().unwrap();
while arr_len < len {
a1 += a2;
m1 += m2;
s1 += s2;
_ctx.engine().throw_on_size((a1, m1, s1))?;
guard.push(item.clone());
arr_len += 1;
}
}
*array = arr.into_array().unwrap();
} else {
array.resize(len, item);
}
} }
#[cfg(feature = "unchecked")]
array.resize(len, item); array.resize(len, item);
Ok(()) Ok(())