Remove collect() with exact sizes.
This commit is contained in:
parent
2c21928f67
commit
ae9f4b5b71
@ -1667,22 +1667,19 @@ impl Engine {
|
|||||||
match expr {
|
match expr {
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Expr::FnCall(x, _) if _parent_chain_type == ChainType::Dot && !x.is_qualified() => {
|
Expr::FnCall(x, _) if _parent_chain_type == ChainType::Dot && !x.is_qualified() => {
|
||||||
let arg_values = x
|
let crate::ast::FnCallExpr {
|
||||||
.args
|
args, constants, ..
|
||||||
.iter()
|
} = x.as_ref();
|
||||||
.map(|arg_expr| match arg_expr {
|
let mut arg_values = StaticVec::with_capacity(args.len());
|
||||||
Expr::Stack(slot, _) => Ok(x.constants[*slot].clone()),
|
|
||||||
_ => self
|
|
||||||
.eval_expr(scope, mods, state, lib, this_ptr, arg_expr, level)
|
|
||||||
.map(Dynamic::flatten),
|
|
||||||
})
|
|
||||||
.collect::<Result<StaticVec<_>, _>>()?;
|
|
||||||
|
|
||||||
let pos = x
|
for index in 0..args.len() {
|
||||||
.args
|
let (value, _) = self.get_arg_value(
|
||||||
.get(0)
|
scope, mods, state, lib, this_ptr, level, args, constants, index,
|
||||||
.map(|arg_expr| arg_expr.position())
|
)?;
|
||||||
.unwrap_or_default();
|
arg_values.push(value.flatten());
|
||||||
|
}
|
||||||
|
|
||||||
|
let pos = x.args.get(0).map(Expr::position).unwrap_or_default();
|
||||||
|
|
||||||
idx_values.push((arg_values, pos).into());
|
idx_values.push((arg_values, pos).into());
|
||||||
}
|
}
|
||||||
@ -1712,22 +1709,19 @@ impl Engine {
|
|||||||
Expr::FnCall(x, _)
|
Expr::FnCall(x, _)
|
||||||
if _parent_chain_type == ChainType::Dot && !x.is_qualified() =>
|
if _parent_chain_type == ChainType::Dot && !x.is_qualified() =>
|
||||||
{
|
{
|
||||||
let arg_values = x
|
let crate::ast::FnCallExpr {
|
||||||
.args
|
args, constants, ..
|
||||||
.iter()
|
} = x.as_ref();
|
||||||
.map(|arg_expr| match arg_expr {
|
let mut arg_values = StaticVec::with_capacity(args.len());
|
||||||
Expr::Stack(slot, _) => Ok(x.constants[*slot].clone()),
|
|
||||||
_ => self
|
|
||||||
.eval_expr(scope, mods, state, lib, this_ptr, arg_expr, level)
|
|
||||||
.map(Dynamic::flatten),
|
|
||||||
})
|
|
||||||
.collect::<Result<StaticVec<_>, _>>()?;
|
|
||||||
|
|
||||||
let pos = x
|
for index in 0..args.len() {
|
||||||
.args
|
let (value, _) = self.get_arg_value(
|
||||||
.get(0)
|
scope, mods, state, lib, this_ptr, level, args, constants, index,
|
||||||
.map(|arg_expr| arg_expr.position())
|
)?;
|
||||||
.unwrap_or_default();
|
arg_values.push(value.flatten());
|
||||||
|
}
|
||||||
|
|
||||||
|
let pos = x.args.get(0).map(Expr::position).unwrap_or_default();
|
||||||
|
|
||||||
(arg_values, pos).into()
|
(arg_values, pos).into()
|
||||||
}
|
}
|
||||||
|
147
src/fn_call.rs
147
src/fn_call.rs
@ -24,7 +24,6 @@ use std::prelude::v1::*;
|
|||||||
use std::{
|
use std::{
|
||||||
any::{type_name, TypeId},
|
any::{type_name, TypeId},
|
||||||
convert::TryFrom,
|
convert::TryFrom,
|
||||||
iter::once,
|
|
||||||
mem,
|
mem,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -515,11 +514,12 @@ impl Engine {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Merge in encapsulated environment, if any
|
// Merge in encapsulated environment, if any
|
||||||
let lib_merged: StaticVec<_>;
|
let mut lib_merged = StaticVec::with_capacity(lib.len() + 1);
|
||||||
|
|
||||||
let (unified_lib, unified) = if let Some(ref env_lib) = fn_def.lib {
|
let (unified_lib, unified) = if let Some(ref env_lib) = fn_def.lib {
|
||||||
state.push_fn_resolution_cache();
|
state.push_fn_resolution_cache();
|
||||||
lib_merged = once(env_lib.as_ref()).chain(lib.iter().cloned()).collect();
|
lib_merged.push(env_lib.as_ref());
|
||||||
|
lib_merged.extend(lib.iter().cloned());
|
||||||
(lib_merged.as_ref(), true)
|
(lib_merged.as_ref(), true)
|
||||||
} else {
|
} else {
|
||||||
(lib, false)
|
(lib, false)
|
||||||
@ -911,8 +911,11 @@ impl Engine {
|
|||||||
// Recalculate hashes
|
// Recalculate hashes
|
||||||
let new_hash = FnCallHashes::from_script(calc_fn_hash(fn_name, args_len));
|
let new_hash = FnCallHashes::from_script(calc_fn_hash(fn_name, args_len));
|
||||||
// Arguments are passed as-is, adding the curried arguments
|
// Arguments are passed as-is, adding the curried arguments
|
||||||
let mut curry: StaticVec<_> = fn_ptr.curry().iter().cloned().collect();
|
let mut curry = StaticVec::with_capacity(fn_ptr.num_curried());
|
||||||
let mut args: StaticVec<_> = curry.iter_mut().chain(call_args.iter_mut()).collect();
|
curry.extend(fn_ptr.curry().iter().cloned());
|
||||||
|
let mut args = StaticVec::with_capacity(curry.len() + call_args.len());
|
||||||
|
args.extend(curry.iter_mut());
|
||||||
|
args.extend(call_args.iter_mut());
|
||||||
|
|
||||||
// Map it to name(args) in function-call style
|
// Map it to name(args) in function-call style
|
||||||
self.exec_fn_call(
|
self.exec_fn_call(
|
||||||
@ -945,11 +948,12 @@ impl Engine {
|
|||||||
calc_fn_hash(fn_name, args_len + 1),
|
calc_fn_hash(fn_name, args_len + 1),
|
||||||
);
|
);
|
||||||
// Replace the first argument with the object pointer, adding the curried arguments
|
// Replace the first argument with the object pointer, adding the curried arguments
|
||||||
let mut curry: StaticVec<_> = fn_ptr.curry().iter().cloned().collect();
|
let mut curry = StaticVec::with_capacity(fn_ptr.num_curried());
|
||||||
let mut args: StaticVec<_> = once(target.as_mut())
|
curry.extend(fn_ptr.curry().iter().cloned());
|
||||||
.chain(curry.iter_mut())
|
let mut args = StaticVec::with_capacity(curry.len() + call_args.len() + 1);
|
||||||
.chain(call_args.iter_mut())
|
args.push(target.as_mut());
|
||||||
.collect();
|
args.extend(curry.iter_mut());
|
||||||
|
args.extend(call_args.iter_mut());
|
||||||
|
|
||||||
// Map it to name(args) in function-call style
|
// Map it to name(args) in function-call style
|
||||||
self.exec_fn_call(
|
self.exec_fn_call(
|
||||||
@ -1020,8 +1024,9 @@ impl Engine {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Attached object pointer in front of the arguments
|
// Attached object pointer in front of the arguments
|
||||||
let mut args: StaticVec<_> =
|
let mut args = StaticVec::with_capacity(call_args.len() + 1);
|
||||||
once(target.as_mut()).chain(call_args.iter_mut()).collect();
|
args.push(target.as_mut());
|
||||||
|
args.extend(call_args.iter_mut());
|
||||||
|
|
||||||
self.exec_fn_call(
|
self.exec_fn_call(
|
||||||
mods, state, lib, fn_name, hash, &mut args, is_ref, true, pos, None, level,
|
mods, state, lib, fn_name, hash, &mut args, is_ref, true, pos, None, level,
|
||||||
@ -1039,8 +1044,9 @@ impl Engine {
|
|||||||
Ok((result, updated))
|
Ok((result, updated))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Evaluate an argument.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn get_arg_value(
|
pub(crate) fn get_arg_value(
|
||||||
&self,
|
&self,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
mods: &mut Imports,
|
mods: &mut Imports,
|
||||||
@ -1147,12 +1153,12 @@ impl Engine {
|
|||||||
let (name, mut fn_curry) = arg.cast::<FnPtr>().take_data();
|
let (name, mut fn_curry) = arg.cast::<FnPtr>().take_data();
|
||||||
|
|
||||||
// Append the new curried arguments to the existing list.
|
// Append the new curried arguments to the existing list.
|
||||||
args_expr.iter().skip(1).try_for_each(|expr| match expr {
|
for index in 1..args_expr.len() {
|
||||||
Expr::Stack(slot, _) => Ok(fn_curry.push(constants[*slot].clone())),
|
let (value, _) = self.get_arg_value(
|
||||||
_ => self
|
scope, mods, state, lib, this_ptr, level, args_expr, constants, index,
|
||||||
.eval_expr(scope, mods, state, lib, this_ptr, expr, level)
|
)?;
|
||||||
.map(|value| fn_curry.push(value)),
|
fn_curry.push(value);
|
||||||
})?;
|
}
|
||||||
|
|
||||||
return Ok(FnPtr::new_unchecked(name, fn_curry).into());
|
return Ok(FnPtr::new_unchecked(name, fn_curry).into());
|
||||||
}
|
}
|
||||||
@ -1249,8 +1255,8 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Normal function call - except for Fn, curry, call and eval (handled above)
|
// Normal function call - except for Fn, curry, call and eval (handled above)
|
||||||
let mut arg_values: StaticVec<_>;
|
let mut arg_values = StaticVec::with_capacity(args_expr.len());
|
||||||
let mut args: StaticVec<_>;
|
let mut args = StaticVec::with_capacity(args_expr.len() + curry.len());
|
||||||
let mut is_ref = false;
|
let mut is_ref = false;
|
||||||
let capture = if capture_scope && !scope.is_empty() {
|
let capture = if capture_scope && !scope.is_empty() {
|
||||||
Some(scope.clone_visible())
|
Some(scope.clone_visible())
|
||||||
@ -1260,23 +1266,18 @@ impl Engine {
|
|||||||
|
|
||||||
if args_expr.is_empty() && curry.is_empty() {
|
if args_expr.is_empty() && curry.is_empty() {
|
||||||
// No arguments
|
// No arguments
|
||||||
args = Default::default();
|
|
||||||
} else {
|
} else {
|
||||||
// If the first argument is a variable, and there is no curried arguments,
|
// If the first argument is a variable, and there is no curried arguments,
|
||||||
// convert to method-call style in order to leverage potential &mut first argument and
|
// convert to method-call style in order to leverage potential &mut first argument and
|
||||||
// avoid cloning the value
|
// avoid cloning the value
|
||||||
if curry.is_empty() && !args_expr.is_empty() && args_expr[0].is_variable_access(false) {
|
if curry.is_empty() && !args_expr.is_empty() && args_expr[0].is_variable_access(false) {
|
||||||
// func(x, ...) -> x.func(...)
|
// func(x, ...) -> x.func(...)
|
||||||
arg_values = args_expr
|
for index in 1..args_expr.len() {
|
||||||
.iter()
|
let (value, _) = self.get_arg_value(
|
||||||
.skip(1)
|
scope, mods, state, lib, this_ptr, level, args_expr, constants, index,
|
||||||
.map(|expr| match expr {
|
)?;
|
||||||
Expr::Stack(slot, _) => Ok(constants[*slot].clone()),
|
arg_values.push(value.flatten());
|
||||||
_ => self
|
}
|
||||||
.eval_expr(scope, mods, state, lib, this_ptr, expr, level)
|
|
||||||
.map(Dynamic::flatten),
|
|
||||||
})
|
|
||||||
.collect::<Result<_, _>>()?;
|
|
||||||
|
|
||||||
let (mut target, _pos) =
|
let (mut target, _pos) =
|
||||||
self.search_namespace(scope, mods, state, lib, this_ptr, &args_expr[0])?;
|
self.search_namespace(scope, mods, state, lib, this_ptr, &args_expr[0])?;
|
||||||
@ -1293,28 +1294,26 @@ impl Engine {
|
|||||||
#[cfg(feature = "no_closure")]
|
#[cfg(feature = "no_closure")]
|
||||||
let target_is_shared = false;
|
let target_is_shared = false;
|
||||||
|
|
||||||
args = if target_is_shared || target.is_value() {
|
if target_is_shared || target.is_value() {
|
||||||
arg_values.insert(0, target.take_or_clone().flatten());
|
arg_values.insert(0, target.take_or_clone().flatten());
|
||||||
arg_values.iter_mut().collect()
|
args.extend(arg_values.iter_mut())
|
||||||
} else {
|
} else {
|
||||||
// Turn it into a method call only if the object is not shared and not a simple value
|
// Turn it into a method call only if the object is not shared and not a simple value
|
||||||
is_ref = true;
|
is_ref = true;
|
||||||
let obj_ref = target.take_ref().expect("never fails because `target` is a reference if it is not a value and not shared");
|
let obj_ref = target.take_ref().expect("never fails because `target` is a reference if it is not a value and not shared");
|
||||||
once(obj_ref).chain(arg_values.iter_mut()).collect()
|
args.push(obj_ref);
|
||||||
};
|
args.extend(arg_values.iter_mut());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// func(..., ...)
|
// func(..., ...)
|
||||||
arg_values = args_expr
|
for index in 0..args_expr.len() {
|
||||||
.iter()
|
let (value, _) = self.get_arg_value(
|
||||||
.map(|expr| match expr {
|
scope, mods, state, lib, this_ptr, level, args_expr, constants, index,
|
||||||
Expr::Stack(slot, _) => Ok(constants[*slot].clone()),
|
)?;
|
||||||
_ => self
|
arg_values.push(value.flatten());
|
||||||
.eval_expr(scope, mods, state, lib, this_ptr, expr, level)
|
}
|
||||||
.map(Dynamic::flatten),
|
args.extend(curry.iter_mut());
|
||||||
})
|
args.extend(arg_values.iter_mut());
|
||||||
.collect::<Result<_, _>>()?;
|
|
||||||
|
|
||||||
args = curry.iter_mut().chain(arg_values.iter_mut()).collect();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1340,35 +1339,28 @@ impl Engine {
|
|||||||
pos: Position,
|
pos: Position,
|
||||||
level: usize,
|
level: usize,
|
||||||
) -> RhaiResult {
|
) -> RhaiResult {
|
||||||
let mut arg_values: StaticVec<_>;
|
let mut arg_values = StaticVec::with_capacity(args_expr.len());
|
||||||
|
let mut args = StaticVec::with_capacity(args_expr.len());
|
||||||
let mut first_arg_value = None;
|
let mut first_arg_value = None;
|
||||||
let mut args: StaticVec<_>;
|
|
||||||
|
|
||||||
if args_expr.is_empty() {
|
if args_expr.is_empty() {
|
||||||
// No arguments
|
// No arguments
|
||||||
args = Default::default();
|
|
||||||
} else {
|
} else {
|
||||||
// See if the first argument is a variable (not namespace-qualified).
|
// See if the first argument is a variable (not namespace-qualified).
|
||||||
// If so, convert to method-call style in order to leverage potential
|
// If so, convert to method-call style in order to leverage potential
|
||||||
// &mut first argument and avoid cloning the value
|
// &mut first argument and avoid cloning the value
|
||||||
if !args_expr.is_empty() && args_expr[0].is_variable_access(true) {
|
if !args_expr.is_empty() && args_expr[0].is_variable_access(true) {
|
||||||
// func(x, ...) -> x.func(...)
|
// func(x, ...) -> x.func(...)
|
||||||
arg_values = args_expr
|
for index in 0..args_expr.len() {
|
||||||
.iter()
|
if index == 0 {
|
||||||
.enumerate()
|
arg_values.push(Default::default());
|
||||||
.map(|(i, expr)| {
|
} else {
|
||||||
// Skip the first argument
|
let (value, _) = self.get_arg_value(
|
||||||
if i == 0 {
|
scope, mods, state, lib, this_ptr, level, args_expr, constants, index,
|
||||||
return Ok(Default::default());
|
)?;
|
||||||
}
|
arg_values.push(value.flatten());
|
||||||
match expr {
|
}
|
||||||
Expr::Stack(slot, _) => Ok(constants[*slot].clone()),
|
}
|
||||||
_ => self
|
|
||||||
.eval_expr(scope, mods, state, lib, this_ptr, expr, level)
|
|
||||||
.map(Dynamic::flatten),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<Result<_, _>>()?;
|
|
||||||
|
|
||||||
// Get target reference to first argument
|
// Get target reference to first argument
|
||||||
let (target, _pos) =
|
let (target, _pos) =
|
||||||
@ -1384,7 +1376,7 @@ impl Engine {
|
|||||||
|
|
||||||
if target_is_shared || target.is_value() {
|
if target_is_shared || target.is_value() {
|
||||||
arg_values[0] = target.take_or_clone().flatten();
|
arg_values[0] = target.take_or_clone().flatten();
|
||||||
args = arg_values.iter_mut().collect();
|
args.extend(arg_values.iter_mut());
|
||||||
} else {
|
} else {
|
||||||
// Turn it into a method call only if the object is not shared and not a simple value
|
// Turn it into a method call only if the object is not shared and not a simple value
|
||||||
let (first, rest) = arg_values
|
let (first, rest) = arg_values
|
||||||
@ -1392,21 +1384,18 @@ impl Engine {
|
|||||||
.expect("never fails because the arguments list is not empty");
|
.expect("never fails because the arguments list is not empty");
|
||||||
first_arg_value = Some(first);
|
first_arg_value = Some(first);
|
||||||
let obj_ref = target.take_ref().expect("never fails because `target` is a reference if it is not a value and not shared");
|
let obj_ref = target.take_ref().expect("never fails because `target` is a reference if it is not a value and not shared");
|
||||||
args = once(obj_ref).chain(rest.iter_mut()).collect();
|
args.push(obj_ref);
|
||||||
|
args.extend(rest.iter_mut());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// func(..., ...) or func(mod::x, ...)
|
// func(..., ...) or func(mod::x, ...)
|
||||||
arg_values = args_expr
|
for index in 0..args_expr.len() {
|
||||||
.iter()
|
let (value, _) = self.get_arg_value(
|
||||||
.map(|expr| match expr {
|
scope, mods, state, lib, this_ptr, level, args_expr, constants, index,
|
||||||
Expr::Stack(slot, _) => Ok(constants[*slot].clone()),
|
)?;
|
||||||
_ => self
|
arg_values.push(value.flatten());
|
||||||
.eval_expr(scope, mods, state, lib, this_ptr, expr, level)
|
}
|
||||||
.map(Dynamic::flatten),
|
args.extend(arg_values.iter_mut());
|
||||||
})
|
|
||||||
.collect::<Result<_, _>>()?;
|
|
||||||
|
|
||||||
args = arg_values.iter_mut().collect();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -344,28 +344,23 @@ impl FnPtr {
|
|||||||
this_ptr: Option<&mut Dynamic>,
|
this_ptr: Option<&mut Dynamic>,
|
||||||
mut arg_values: impl AsMut<[Dynamic]>,
|
mut arg_values: impl AsMut<[Dynamic]>,
|
||||||
) -> RhaiResult {
|
) -> RhaiResult {
|
||||||
let mut args_data: StaticVec<_>;
|
let mut arg_values = arg_values.as_mut();
|
||||||
|
let mut args_data;
|
||||||
|
|
||||||
let arg_values = if self.curry().is_empty() {
|
if self.num_curried() > 0 {
|
||||||
arg_values.as_mut()
|
args_data = StaticVec::with_capacity(self.num_curried() + arg_values.len());
|
||||||
} else {
|
args_data.extend(self.curry().iter().cloned());
|
||||||
args_data = self
|
args_data.extend(arg_values.iter_mut().map(mem::take));
|
||||||
.curry()
|
arg_values = args_data.as_mut();
|
||||||
.iter()
|
|
||||||
.cloned()
|
|
||||||
.chain(arg_values.as_mut().iter_mut().map(mem::take))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
args_data.as_mut()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let is_method = this_ptr.is_some();
|
let is_method = this_ptr.is_some();
|
||||||
|
|
||||||
let mut args: StaticVec<_> = if let Some(obj) = this_ptr {
|
let mut args = StaticVec::with_capacity(arg_values.len() + 1);
|
||||||
once(obj).chain(arg_values.iter_mut()).collect()
|
if let Some(obj) = this_ptr {
|
||||||
} else {
|
args.push(obj);
|
||||||
arg_values.iter_mut().collect()
|
}
|
||||||
};
|
args.extend(arg_values.iter_mut());
|
||||||
|
|
||||||
ctx.call_fn_dynamic_raw(self.fn_name(), is_method, &mut args)
|
ctx.call_fn_dynamic_raw(self.fn_name(), is_method, &mut args)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user