Reduce size of ChainArgument.

This commit is contained in:
Stephen Chung 2021-12-27 17:00:21 +08:00
parent 757eacfdde
commit 7a15071e4e
2 changed files with 52 additions and 51 deletions

View File

@ -368,8 +368,11 @@ enum ChainArgument {
Property(Position), Property(Position),
/// Arguments to a dot method call. /// Arguments to a dot method call.
/// Wrapped values are the arguments plus the [position][Position] of the first argument. /// Wrapped values are the arguments plus the [position][Position] of the first argument.
///
/// Since many dotted function calls have no arguments (e.g. `string.len()`), it is better to
/// reduce the size of [`ChainArgument`] by using a boxed slice.
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
MethodCallArgs(FnArgsVec<Dynamic>, Position), MethodCallArgs(Option<Box<[Dynamic]>>, Position),
/// Index value and [position][Position]. /// Index value and [position][Position].
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
IndexValue(Dynamic, Position), IndexValue(Dynamic, Position),
@ -389,13 +392,20 @@ impl ChainArgument {
} }
} }
/// Return the list of method call arguments. /// Return the list of method call arguments.
///
/// # Panics
///
/// Panics if the [`ChainArgument`] is not [`MethodCallArgs`][ChainArgument::MethodCallArgs].
#[inline(always)] #[inline(always)]
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
#[must_use] #[must_use]
pub fn into_fn_call_args(self) -> Option<(FnArgsVec<Dynamic>, Position)> { pub fn into_fn_call_args(self) -> (FnArgsVec<Dynamic>, Position) {
match self { match self {
Self::MethodCallArgs(values, pos) => Some((values, pos)), Self::MethodCallArgs(None, pos) => (FnArgsVec::new_const(), pos),
_ => None, Self::MethodCallArgs(Some(mut values), pos) => {
(values.iter_mut().map(std::mem::take).collect(), pos)
}
_ => unreachable!("`MethodCallArgs` expected"),
} }
} }
/// Return the [position][Position]. /// Return the [position][Position].
@ -412,20 +422,21 @@ impl ChainArgument {
ChainArgument::IndexValue(_, pos) => *pos, ChainArgument::IndexValue(_, pos) => *pos,
} }
} }
} /// Create n [`MethodCallArgs`][ChainArgument::MethodCallArgs].
#[cfg(not(feature = "no_object"))]
impl From<(FnArgsVec<Dynamic>, Position)> for ChainArgument {
#[inline(always)] #[inline(always)]
fn from((values, pos): (FnArgsVec<Dynamic>, Position)) -> Self { #[cfg(not(feature = "no_object"))]
Self::MethodCallArgs(values, pos) #[must_use]
pub fn from_fn_call_args(values: FnArgsVec<Dynamic>, pos: Position) -> Self {
if values.is_empty() {
Self::MethodCallArgs(None, pos)
} else {
Self::MethodCallArgs(Some(values.into_vec().into()), pos)
} }
} }
/// Create an [`IndexValue`][ChainArgument::IndexValue].
#[cfg(not(feature = "no_index"))]
impl From<(Dynamic, Position)> for ChainArgument {
#[inline(always)] #[inline(always)]
fn from((value, pos): (Dynamic, Position)) -> Self { #[must_use]
pub const fn from_index_value(value: Dynamic, pos: Position) -> Self {
Self::IndexValue(value, pos) Self::IndexValue(value, pos)
} }
} }
@ -1322,7 +1333,7 @@ impl Engine {
root: (&str, Position), root: (&str, Position),
rhs: &Expr, rhs: &Expr,
terminate_chaining: bool, terminate_chaining: bool,
idx_values: &mut FnArgsVec<ChainArgument>, idx_values: &mut StaticVec<ChainArgument>,
chain_type: ChainType, chain_type: ChainType,
level: usize, level: usize,
new_val: Option<((Dynamic, Position), (Option<OpAssignment>, Position))>, new_val: Option<((Dynamic, Position), (Option<OpAssignment>, Position))>,
@ -1445,9 +1456,7 @@ impl Engine {
// xxx.fn_name(arg_expr_list) // xxx.fn_name(arg_expr_list)
Expr::FnCall(x, pos) if !x.is_qualified() && new_val.is_none() => { Expr::FnCall(x, pos) if !x.is_qualified() && new_val.is_none() => {
let FnCallExpr { name, hashes, .. } = x.as_ref(); let FnCallExpr { name, hashes, .. } = x.as_ref();
let call_args = &mut idx_val let call_args = &mut idx_val.into_fn_call_args();
.into_fn_call_args()
.expect("`ChainType::Dot` with `Expr::FnCallExpr`");
self.make_method_call( self.make_method_call(
mods, state, lib, name, *hashes, target, call_args, *pos, level, mods, state, lib, name, *hashes, target, call_args, *pos, level,
) )
@ -1611,9 +1620,7 @@ impl Engine {
// {xxx:map}.fn_name(arg_expr_list)[expr] | {xxx:map}.fn_name(arg_expr_list).expr // {xxx:map}.fn_name(arg_expr_list)[expr] | {xxx:map}.fn_name(arg_expr_list).expr
Expr::FnCall(ref x, pos) if !x.is_qualified() => { Expr::FnCall(ref x, pos) if !x.is_qualified() => {
let FnCallExpr { name, hashes, .. } = x.as_ref(); let FnCallExpr { name, hashes, .. } = x.as_ref();
let call_args = &mut idx_val.into_fn_call_args().expect( let call_args = &mut idx_val.into_fn_call_args();
"`chain_type` is `ChainType::Dot` with `Expr::FnCallExpr`",
);
let (val, _) = self.make_method_call( let (val, _) = self.make_method_call(
mods, state, lib, name, *hashes, target, call_args, pos, level, mods, state, lib, name, *hashes, target, call_args, pos, level,
)?; )?;
@ -1736,9 +1743,7 @@ impl Engine {
Expr::FnCall(ref f, pos) if !f.is_qualified() => { Expr::FnCall(ref f, pos) if !f.is_qualified() => {
let FnCallExpr { name, hashes, .. } = f.as_ref(); let FnCallExpr { name, hashes, .. } = f.as_ref();
let rhs_chain = match_chaining_type(rhs); let rhs_chain = match_chaining_type(rhs);
let args = &mut idx_val.into_fn_call_args().expect( let args = &mut idx_val.into_fn_call_args();
"`chain_type` is `ChainType::Dot` with `Expr::FnCallExpr`",
);
let (mut val, _) = self.make_method_call( let (mut val, _) = self.make_method_call(
mods, state, lib, name, *hashes, target, args, pos, level, mods, state, lib, name, *hashes, target, args, pos, level,
)?; )?;
@ -1787,7 +1792,7 @@ impl Engine {
_ => unreachable!("index or dot chain expected, but gets {:?}", expr), _ => unreachable!("index or dot chain expected, but gets {:?}", expr),
}; };
let idx_values = &mut FnArgsVec::new_const(); let idx_values = &mut StaticVec::new_const();
self.eval_dot_index_chain_arguments( self.eval_dot_index_chain_arguments(
scope, mods, state, lib, this_ptr, rhs, term, chain_type, idx_values, 0, level, scope, mods, state, lib, this_ptr, rhs, term, chain_type, idx_values, 0, level,
@ -1843,7 +1848,7 @@ impl Engine {
expr: &Expr, expr: &Expr,
terminate_chaining: bool, terminate_chaining: bool,
parent_chain_type: ChainType, parent_chain_type: ChainType,
idx_values: &mut FnArgsVec<ChainArgument>, idx_values: &mut StaticVec<ChainArgument>,
size: usize, size: usize,
level: usize, level: usize,
) -> RhaiResultOf<()> { ) -> RhaiResultOf<()> {
@ -1873,7 +1878,7 @@ impl Engine {
}, },
)?; )?;
idx_values.push((values, pos).into()); idx_values.push(ChainArgument::from_fn_call_args(values, pos));
} }
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
Expr::FnCall(_, _) if _parent_chain_type == ChainType::Dotting => { Expr::FnCall(_, _) if _parent_chain_type == ChainType::Dotting => {
@ -1890,7 +1895,7 @@ impl Engine {
let crate::ast::BinaryExpr { lhs, rhs, .. } = x.as_ref(); let crate::ast::BinaryExpr { lhs, rhs, .. } = x.as_ref();
// Evaluate in left-to-right order // Evaluate in left-to-right order
let lhs_val = match lhs { let lhs_arg_val = match lhs {
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
Expr::Property(x) if _parent_chain_type == ChainType::Dotting => { Expr::Property(x) if _parent_chain_type == ChainType::Dotting => {
ChainArgument::Property((x.2).1) ChainArgument::Property((x.2).1)
@ -1905,8 +1910,7 @@ impl Engine {
args, constants, .. args, constants, ..
} = x.as_ref(); } = x.as_ref();
args.iter() let (values, pos) = args.iter().try_fold(
.try_fold(
(FnArgsVec::with_capacity(args.len()), Position::NONE), (FnArgsVec::with_capacity(args.len()), Position::NONE),
|(mut values, mut pos), expr| -> RhaiResultOf<_> { |(mut values, mut pos), expr| -> RhaiResultOf<_> {
let (value, arg_pos) = self.get_arg_value( let (value, arg_pos) = self.get_arg_value(
@ -1918,8 +1922,8 @@ impl Engine {
values.push(value.flatten()); values.push(value.flatten());
Ok((values, pos)) Ok((values, pos))
}, },
)? )?;
.into() ChainArgument::from_fn_call_args(values, pos)
} }
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
Expr::FnCall(_, _) if _parent_chain_type == ChainType::Dotting => { Expr::FnCall(_, _) if _parent_chain_type == ChainType::Dotting => {
@ -1932,7 +1936,7 @@ impl Engine {
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
_ if _parent_chain_type == ChainType::Indexing => self _ if _parent_chain_type == ChainType::Indexing => self
.eval_expr(scope, mods, state, lib, this_ptr, lhs, level) .eval_expr(scope, mods, state, lib, this_ptr, lhs, level)
.map(|v| (v.flatten(), lhs.position()).into())?, .map(|v| ChainArgument::from_index_value(v.flatten(), lhs.position()))?,
expr => unreachable!("unknown chained expression: {:?}", expr), expr => unreachable!("unknown chained expression: {:?}", expr),
}; };
@ -1944,7 +1948,7 @@ impl Engine {
level, level,
)?; )?;
idx_values.push(lhs_val); idx_values.push(lhs_arg_val);
} }
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
@ -1954,7 +1958,7 @@ impl Engine {
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
_ if _parent_chain_type == ChainType::Indexing => idx_values.push( _ if _parent_chain_type == ChainType::Indexing => idx_values.push(
self.eval_expr(scope, mods, state, lib, this_ptr, expr, level) self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)
.map(|v| (v.flatten(), expr.position()).into())?, .map(|v| ChainArgument::from_index_value(v.flatten(), expr.position()))?,
), ),
_ => unreachable!("unknown chained expression: {:?}", expr), _ => unreachable!("unknown chained expression: {:?}", expr),
} }

View File

@ -329,10 +329,7 @@ pub type StaticVec<T> = smallvec::SmallVec<[T; 3]>;
type FnArgsVec<T> = smallvec::SmallVec<[T; 8]>; type FnArgsVec<T> = smallvec::SmallVec<[T; 8]>;
/// Inline arguments storage for function calls. /// Inline arguments storage for function calls.
/// /// This type aliases to [`StaticVec`][crate::StaticVec].
/// # Notes
///
/// This type aliases to [`StaticVec`][crate::StaticVec] under `no_closure`.
#[cfg(feature = "no_closure")] #[cfg(feature = "no_closure")]
type FnArgsVec<T> = crate::StaticVec<T>; type FnArgsVec<T> = crate::StaticVec<T>;