diff --git a/codegen/src/module.rs b/codegen/src/module.rs index eb3497bf..283436ab 100644 --- a/codegen/src/module.rs +++ b/codegen/src/module.rs @@ -259,7 +259,7 @@ impl Module { let mut mod_all = mod_all.unwrap(); let mod_name = mod_all.ident.clone(); let (_, orig_content) = mod_all.content.take().unwrap(); - let mod_attrs = mem::replace(&mut mod_all.attrs, Vec::with_capacity(0)); + let mod_attrs = mem::take(&mut mod_all.attrs); if !params.skip { // Generate new module items. diff --git a/src/ast.rs b/src/ast.rs index 44970d9c..0421a03b 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -16,10 +16,10 @@ use crate::FLOAT; use crate::engine::Imports; #[cfg(not(feature = "no_index"))] -use crate::engine::TYPICAL_ARRAY_SIZE; +use crate::{engine::TYPICAL_ARRAY_SIZE, Array}; #[cfg(not(feature = "no_object"))] -use crate::engine::TYPICAL_MAP_SIZE; +use crate::{engine::TYPICAL_MAP_SIZE, Map}; use crate::stdlib::{ borrow::Cow, @@ -129,7 +129,7 @@ impl fmt::Display for ScriptFnDef { /// # Thread Safety /// /// Currently, `AST` is neither `Send` nor `Sync`. Turn on the `sync` feature to make it `Send + Sync`. -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone)] pub struct AST( /// Global statements. Vec, @@ -137,11 +137,17 @@ pub struct AST( Module, ); +impl Default for AST { + fn default() -> Self { + Self(Vec::with_capacity(16), Default::default()) + } +} + impl AST { /// Create a new `AST`. #[inline(always)] - pub fn new(statements: Vec, lib: Module) -> Self { - Self(statements, lib) + pub fn new(statements: impl IntoIterator, lib: Module) -> Self { + Self(statements.into_iter().collect(), lib) } /// Get the statements. #[cfg(not(feature = "internals"))] @@ -937,14 +943,14 @@ impl Expr { #[cfg(not(feature = "no_index"))] Self::Array(x, _) if self.is_constant() => { - let mut arr = Vec::with_capacity(max(TYPICAL_ARRAY_SIZE, x.len())); + let mut arr = Array::with_capacity(max(TYPICAL_ARRAY_SIZE, x.len())); arr.extend(x.iter().map(|v| v.get_constant_value().unwrap())); Dynamic(Union::Array(Box::new(arr))) } #[cfg(not(feature = "no_object"))] Self::Map(x, _) if self.is_constant() => { - let mut map = HashMap::with_capacity(max(TYPICAL_MAP_SIZE, x.len())); + let mut map = Map::with_capacity(max(TYPICAL_MAP_SIZE, x.len())); map.extend( x.iter() .map(|(k, v)| (k.name.clone(), v.get_constant_value().unwrap())), diff --git a/src/engine.rs b/src/engine.rs index 06a249af..99a717be 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -720,10 +720,10 @@ impl Engine { #[cfg(any(feature = "no_std", target_arch = "wasm32",))] module_resolver: None, - type_names: HashMap::with_capacity(8), - disabled_symbols: HashSet::with_capacity(4), - custom_keywords: HashMap::with_capacity(4), - custom_syntax: HashMap::with_capacity(4), + type_names: Default::default(), + disabled_symbols: Default::default(), + custom_keywords: Default::default(), + custom_syntax: Default::default(), // variable resolver resolve_var: None, @@ -777,10 +777,10 @@ impl Engine { #[cfg(not(feature = "no_module"))] module_resolver: None, - type_names: HashMap::with_capacity(8), - disabled_symbols: HashSet::with_capacity(4), - custom_keywords: HashMap::with_capacity(4), - custom_syntax: HashMap::with_capacity(4), + type_names: Default::default(), + disabled_symbols: Default::default(), + custom_keywords: Default::default(), + custom_syntax: Default::default(), resolve_var: None, @@ -1726,7 +1726,7 @@ impl Engine { #[cfg(not(feature = "no_index"))] Expr::Array(x, _) => { - let mut arr = Vec::with_capacity(max(TYPICAL_ARRAY_SIZE, x.len())); + let mut arr = Array::with_capacity(max(TYPICAL_ARRAY_SIZE, x.len())); for item in x.as_ref() { arr.push(self.eval_expr(scope, mods, state, lib, this_ptr, item, level)?); } @@ -1735,7 +1735,7 @@ impl Engine { #[cfg(not(feature = "no_object"))] Expr::Map(x, _) => { - let mut map = HashMap::with_capacity(max(TYPICAL_MAP_SIZE, x.len())); + let mut map = Map::with_capacity(max(TYPICAL_MAP_SIZE, x.len())); for (IdentX { name: key, .. }, expr) in x.as_ref() { map.insert( key.clone(), diff --git a/src/module/mod.rs b/src/module/mod.rs index 53882fa8..7d798f70 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -81,12 +81,12 @@ pub struct Module { impl Default for Module { fn default() -> Self { Self { - modules: HashMap::with_capacity(4), - variables: HashMap::with_capacity(4), - all_variables: HashMap::with_capacity_and_hasher(32, StraightHasherBuilder), + modules: Default::default(), + variables: Default::default(), + all_variables: Default::default(), functions: HashMap::with_capacity_and_hasher(64, StraightHasherBuilder), all_functions: HashMap::with_capacity_and_hasher(256, StraightHasherBuilder), - type_iterators: HashMap::with_capacity(4), + type_iterators: Default::default(), indexed: false, } } @@ -1477,8 +1477,8 @@ impl Module { if !self.indexed { let mut qualifiers = Vec::with_capacity(4); - let mut variables = Vec::with_capacity(8); - let mut functions = Vec::with_capacity(16); + let mut variables = Vec::with_capacity(16); + let mut functions = Vec::with_capacity(256); qualifiers.push("root"); diff --git a/src/optimize.rs b/src/optimize.rs index 03b2bd3b..071dfe8f 100644 --- a/src/optimize.rs +++ b/src/optimize.rs @@ -753,7 +753,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut State) { } fn optimize( - statements: Vec, + mut statements: Vec, engine: &Engine, scope: &Scope, lib: &[&Module], @@ -761,6 +761,7 @@ fn optimize( ) -> Vec { // If optimization level is None then skip optimizing if level == OptimizationLevel::None { + statements.shrink_to_fit(); return statements; } @@ -779,16 +780,14 @@ fn optimize( let orig_constants_len = state.constants.len(); - let mut result = statements; - // Optimization loop loop { state.reset(); state.restore_constants(orig_constants_len); - let num_statements = result.len(); + let num_statements = statements.len(); - result.iter_mut().enumerate().for_each(|(i, stmt)| { + statements.iter_mut().enumerate().for_each(|(i, stmt)| { match stmt { Stmt::Const(var_def, expr, _, _) if expr.is_some() => { // Load constants @@ -828,26 +827,27 @@ fn optimize( } // Eliminate code that is pure but always keep the last statement - let last_stmt = result.pop(); + let last_stmt = statements.pop(); // Remove all pure statements at global level - result.retain(|stmt| !stmt.is_pure()); + statements.retain(|stmt| !stmt.is_pure()); // Add back the last statement unless it is a lone No-op if let Some(stmt) = last_stmt { - if !result.is_empty() || !stmt.is_noop() { - result.push(stmt); + if !statements.is_empty() || !stmt.is_noop() { + statements.push(stmt); } } - result + statements.shrink_to_fit(); + statements } /// Optimize an AST. pub fn optimize_into_ast( engine: &Engine, scope: &Scope, - statements: Vec, + mut statements: Vec, _functions: Vec, level: OptimizationLevel, ) -> AST { @@ -922,6 +922,8 @@ pub fn optimize_into_ast( #[cfg(feature = "no_function")] let lib = Default::default(); + statements.shrink_to_fit(); + AST::new( match level { OptimizationLevel::None => statements, diff --git a/src/packages/array_basic.rs b/src/packages/array_basic.rs index 339c4c94..c3554529 100644 --- a/src/packages/array_basic.rs +++ b/src/packages/array_basic.rs @@ -3,7 +3,7 @@ use crate::def_package; use crate::dynamic::Dynamic; -use crate::engine::{Array, OP_EQUALS}; +use crate::engine::{Array, OP_EQUALS, TYPICAL_ARRAY_SIZE}; use crate::fn_native::{FnPtr, NativeCallContext}; use crate::plugin::*; use crate::result::EvalAltResult; @@ -14,7 +14,7 @@ use crate::INT; #[cfg(not(feature = "no_object"))] use crate::engine::Map; -use crate::stdlib::{any::TypeId, boxed::Box, cmp::Ordering, string::ToString}; +use crate::stdlib::{any::TypeId, boxed::Box, cmp::max, cmp::Ordering, string::ToString}; pub type Unit = (); @@ -201,7 +201,7 @@ mod array_functions { list: &mut Array, mapper: FnPtr, ) -> Result> { - let mut array = Array::with_capacity(list.len()); + let mut array = Array::with_capacity(max(TYPICAL_ARRAY_SIZE, list.len())); for (i, item) in list.iter().enumerate() { array.push( @@ -233,7 +233,7 @@ mod array_functions { list: &mut Array, filter: FnPtr, ) -> Result> { - let mut array = Array::with_capacity(list.len()); + let mut array = Array::with_capacity(max(TYPICAL_ARRAY_SIZE, list.len())); for (i, item) in list.iter().enumerate() { if filter @@ -537,7 +537,7 @@ mod array_functions { list: &mut Array, filter: FnPtr, ) -> Result> { - let mut drained = Array::with_capacity(list.len()); + let mut drained = Array::with_capacity(max(TYPICAL_ARRAY_SIZE, list.len())); let mut i = list.len(); @@ -596,7 +596,7 @@ mod array_functions { list: &mut Array, filter: FnPtr, ) -> Result> { - let mut drained = Array::with_capacity(list.len()); + let mut drained = Array::with_capacity(max(TYPICAL_ARRAY_SIZE, list.len())); let mut i = list.len(); diff --git a/src/packages/mod.rs b/src/packages/mod.rs index dae31183..563da34a 100644 --- a/src/packages/mod.rs +++ b/src/packages/mod.rs @@ -130,7 +130,7 @@ macro_rules! def_package { impl $package { pub fn new() -> Self { - let mut module = $root::Module::new_with_capacity(512); + let mut module = $root::Module::new_with_capacity(1024); ::init(&mut module); Self(module.into()) } diff --git a/src/parser.rs b/src/parser.rs index 8897232f..bae5dbe4 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -41,9 +41,6 @@ use crate::stdlib::{ vec::Vec, }; -#[cfg(not(feature = "no_closure"))] -use crate::stdlib::collections::HashSet; - type PERR = ParseErrorType; type FunctionsLib = HashMap; @@ -99,7 +96,7 @@ impl<'e> ParseState<'e> { #[cfg(not(feature = "no_function"))] max_function_expr_depth, #[cfg(not(feature = "no_closure"))] - externals: HashMap::with_capacity(8), + externals: Default::default(), #[cfg(not(feature = "no_closure"))] allow_capture: true, strings: HashMap::with_capacity(64), @@ -2211,7 +2208,7 @@ fn parse_export( _ => (), } - let mut exports = Vec::new(); + let mut exports = Vec::with_capacity(4); loop { let (id, id_pos) = match input.next().unwrap() { @@ -2279,7 +2276,7 @@ fn parse_block( #[cfg(not(feature = "unchecked"))] settings.ensure_level_within_max_limit(state.max_expr_depth)?; - let mut statements = Vec::new(); + let mut statements = Vec::with_capacity(8); let prev_stack_len = state.stack.len(); #[cfg(not(feature = "no_module"))] @@ -2584,7 +2581,7 @@ fn parse_fn( (_, pos) => return Err(PERR::FnMissingParams(name).into_err(*pos)), }; - let mut params = Vec::new(); + let mut params: StaticVec<_> = Default::default(); if !match_token(input, Token::RightParen).0 { let sep_err = format!("to separate the parameters of function '{}'", name); @@ -2716,7 +2713,7 @@ fn parse_anon_fn( #[cfg(not(feature = "unchecked"))] settings.ensure_level_within_max_limit(state.max_expr_depth)?; - let mut params = Vec::new(); + let mut params: StaticVec<_> = Default::default(); if input.next().unwrap().0 != Token::Or { if !match_token(input, Token::Pipe).0 { @@ -2800,7 +2797,7 @@ fn parse_anon_fn( access: FnAccess::Public, params, #[cfg(not(feature = "no_closure"))] - externals: HashSet::with_capacity(4), + externals: Default::default(), body, lib: None, #[cfg(not(feature = "no_module"))] @@ -2877,8 +2874,8 @@ impl Engine { script_hash: u64, input: &mut TokenStream, ) -> Result<(Vec, Vec), ParseError> { - let mut statements: Vec = Default::default(); - let mut functions = Default::default(); + let mut statements = Vec::with_capacity(16); + let mut functions = HashMap::with_capacity_and_hasher(16, StraightHasherBuilder); let mut state = ParseState::new( self, script_hash, diff --git a/src/scope.rs b/src/scope.rs index 901755f0..eda857ce 100644 --- a/src/scope.rs +++ b/src/scope.rs @@ -65,7 +65,7 @@ impl EntryType { // // Since `Dynamic` is reasonably small, packing it tightly improves cache locality when variables are accessed. // The variable type is packed separately into another array because it is even smaller. -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone)] pub struct Scope<'a> { /// Current value of the entry. values: Vec, @@ -75,6 +75,16 @@ pub struct Scope<'a> { names: Vec<(Cow<'a, str>, Box>)>, } +impl Default for Scope<'_> { + fn default() -> Self { + Self { + values: Vec::with_capacity(16), + types: Vec::with_capacity(16), + names: Vec::with_capacity(16), + } + } +} + impl<'a> Scope<'a> { /// Create a new Scope. ///