Set capacity of hash maps.
This commit is contained in:
parent
a63f14b59c
commit
bde8917ed4
28
src/ast.rs
28
src/ast.rs
@ -15,6 +15,12 @@ use crate::FLOAT;
|
|||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
use crate::engine::Imports;
|
use crate::engine::Imports;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
use crate::engine::TYPICAL_ARRAY_SIZE;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
use crate::engine::TYPICAL_MAP_SIZE;
|
||||||
|
|
||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
boxed::Box,
|
boxed::Box,
|
||||||
@ -31,6 +37,9 @@ use crate::stdlib::{
|
|||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
use crate::stdlib::collections::HashSet;
|
use crate::stdlib::collections::HashSet;
|
||||||
|
|
||||||
|
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||||
|
use crate::stdlib::cmp::max;
|
||||||
|
|
||||||
/// A type representing the access mode of a scripted function.
|
/// A type representing the access mode of a scripted function.
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
||||||
pub enum FnAccess {
|
pub enum FnAccess {
|
||||||
@ -927,17 +936,20 @@ impl Expr {
|
|||||||
Self::Unit(_) => ().into(),
|
Self::Unit(_) => ().into(),
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Self::Array(x, _) if x.iter().all(Self::is_constant) => Dynamic(Union::Array(
|
Self::Array(x, _) if self.is_constant() => {
|
||||||
Box::new(x.iter().map(|v| v.get_constant_value().unwrap()).collect()),
|
let mut arr = Vec::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"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Self::Map(x, _) if x.iter().all(|(_, v)| v.is_constant()) => {
|
Self::Map(x, _) if self.is_constant() => {
|
||||||
Dynamic(Union::Map(Box::new(
|
let mut map = HashMap::with_capacity(max(TYPICAL_MAP_SIZE, x.len()));
|
||||||
|
map.extend(
|
||||||
x.iter()
|
x.iter()
|
||||||
.map(|(k, v)| (k.name.clone(), v.get_constant_value().unwrap()))
|
.map(|(k, v)| (k.name.clone(), v.get_constant_value().unwrap())),
|
||||||
.collect(),
|
);
|
||||||
)))
|
Dynamic(Union::Map(Box::new(map)))
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => return None,
|
_ => return None,
|
||||||
|
@ -58,12 +58,21 @@ use crate::stdlib::mem;
|
|||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
pub type Array = crate::stdlib::vec::Vec<Dynamic>;
|
pub type Array = crate::stdlib::vec::Vec<Dynamic>;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
pub const TYPICAL_ARRAY_SIZE: usize = 8; // Small arrays are typical
|
||||||
|
|
||||||
|
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||||
|
use crate::stdlib::cmp::max;
|
||||||
|
|
||||||
/// Hash map of `Dynamic` values with `ImmutableString` keys.
|
/// Hash map of `Dynamic` values with `ImmutableString` keys.
|
||||||
///
|
///
|
||||||
/// Not available under the `no_object` feature.
|
/// Not available under the `no_object` feature.
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
pub type Map = HashMap<ImmutableString, Dynamic>;
|
pub type Map = HashMap<ImmutableString, Dynamic>;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
pub const TYPICAL_MAP_SIZE: usize = 8; // Small maps are typical
|
||||||
|
|
||||||
/// _[INTERNALS]_ A stack of imported modules.
|
/// _[INTERNALS]_ A stack of imported modules.
|
||||||
/// Exported under the `internals` feature only.
|
/// Exported under the `internals` feature only.
|
||||||
///
|
///
|
||||||
@ -597,7 +606,7 @@ pub struct Engine {
|
|||||||
|
|
||||||
/// A hashset containing symbols to disable.
|
/// A hashset containing symbols to disable.
|
||||||
pub(crate) disabled_symbols: HashSet<String>,
|
pub(crate) disabled_symbols: HashSet<String>,
|
||||||
/// A hashset containing custom keywords and precedence to recognize.
|
/// A hashmap containing custom keywords and precedence to recognize.
|
||||||
pub(crate) custom_keywords: HashMap<String, Option<u8>>,
|
pub(crate) custom_keywords: HashMap<String, Option<u8>>,
|
||||||
/// Custom syntax.
|
/// Custom syntax.
|
||||||
pub(crate) custom_syntax: HashMap<ImmutableString, CustomSyntax>,
|
pub(crate) custom_syntax: HashMap<ImmutableString, CustomSyntax>,
|
||||||
@ -711,10 +720,10 @@ impl Engine {
|
|||||||
#[cfg(any(feature = "no_std", target_arch = "wasm32",))]
|
#[cfg(any(feature = "no_std", target_arch = "wasm32",))]
|
||||||
module_resolver: None,
|
module_resolver: None,
|
||||||
|
|
||||||
type_names: Default::default(),
|
type_names: HashMap::with_capacity(8),
|
||||||
disabled_symbols: Default::default(),
|
disabled_symbols: HashSet::with_capacity(4),
|
||||||
custom_keywords: Default::default(),
|
custom_keywords: HashMap::with_capacity(4),
|
||||||
custom_syntax: Default::default(),
|
custom_syntax: HashMap::with_capacity(4),
|
||||||
|
|
||||||
// variable resolver
|
// variable resolver
|
||||||
resolve_var: None,
|
resolve_var: None,
|
||||||
@ -768,10 +777,10 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
module_resolver: None,
|
module_resolver: None,
|
||||||
|
|
||||||
type_names: Default::default(),
|
type_names: HashMap::with_capacity(8),
|
||||||
disabled_symbols: Default::default(),
|
disabled_symbols: HashSet::with_capacity(4),
|
||||||
custom_keywords: Default::default(),
|
custom_keywords: HashMap::with_capacity(4),
|
||||||
custom_syntax: Default::default(),
|
custom_syntax: HashMap::with_capacity(4),
|
||||||
|
|
||||||
resolve_var: None,
|
resolve_var: None,
|
||||||
|
|
||||||
@ -1716,21 +1725,25 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Expr::Array(x, _) => Ok(Dynamic(Union::Array(Box::new(
|
Expr::Array(x, _) => {
|
||||||
x.iter()
|
let mut arr = Vec::with_capacity(max(TYPICAL_ARRAY_SIZE, x.len()));
|
||||||
.map(|item| self.eval_expr(scope, mods, state, lib, this_ptr, item, level))
|
for item in x.as_ref() {
|
||||||
.collect::<Result<_, _>>()?,
|
arr.push(self.eval_expr(scope, mods, state, lib, this_ptr, item, level)?);
|
||||||
)))),
|
}
|
||||||
|
Ok(Dynamic(Union::Array(Box::new(arr))))
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Expr::Map(x, _) => Ok(Dynamic(Union::Map(Box::new(
|
Expr::Map(x, _) => {
|
||||||
x.iter()
|
let mut map = HashMap::with_capacity(max(TYPICAL_MAP_SIZE, x.len()));
|
||||||
.map(|(key, expr)| {
|
for (IdentX { name: key, .. }, expr) in x.as_ref() {
|
||||||
self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)
|
map.insert(
|
||||||
.map(|val| (key.name.clone(), val))
|
key.clone(),
|
||||||
})
|
self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?,
|
||||||
.collect::<Result<HashMap<_, _>, _>>()?,
|
);
|
||||||
)))),
|
}
|
||||||
|
Ok(Dynamic(Union::Map(Box::new(map))))
|
||||||
|
}
|
||||||
|
|
||||||
// Normal function call
|
// Normal function call
|
||||||
Expr::FnCall(x, pos) if x.namespace.is_none() => {
|
Expr::FnCall(x, pos) if x.namespace.is_none() => {
|
||||||
|
@ -23,8 +23,7 @@ impl Engine {
|
|||||||
/// In other words, loaded packages are searched in reverse order.
|
/// In other words, loaded packages are searched in reverse order.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn load_package(&mut self, package: impl Into<PackageLibrary>) -> &mut Self {
|
pub fn load_package(&mut self, package: impl Into<PackageLibrary>) -> &mut Self {
|
||||||
// Push the package to the top - packages are searched in reverse order
|
self.packages.add(package.into());
|
||||||
self.packages.push(package.into());
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
/// Control whether and how the `Engine` will optimize an AST after compilation.
|
/// Control whether and how the `Engine` will optimize an AST after compilation.
|
||||||
|
@ -59,7 +59,7 @@ pub struct FuncInfo {
|
|||||||
/// and/or script-defined functions.
|
/// and/or script-defined functions.
|
||||||
///
|
///
|
||||||
/// Not available under the `no_module` feature.
|
/// Not available under the `no_module` feature.
|
||||||
#[derive(Default, Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Module {
|
pub struct Module {
|
||||||
/// Sub-modules.
|
/// Sub-modules.
|
||||||
modules: HashMap<String, Shared<Module>>,
|
modules: HashMap<String, Shared<Module>>,
|
||||||
@ -69,15 +69,29 @@ pub struct Module {
|
|||||||
all_variables: HashMap<u64, Dynamic, StraightHasherBuilder>,
|
all_variables: HashMap<u64, Dynamic, StraightHasherBuilder>,
|
||||||
/// External Rust functions.
|
/// External Rust functions.
|
||||||
functions: HashMap<u64, FuncInfo, StraightHasherBuilder>,
|
functions: HashMap<u64, FuncInfo, StraightHasherBuilder>,
|
||||||
/// Iterator functions, keyed by the type producing the iterator.
|
|
||||||
type_iterators: HashMap<TypeId, IteratorFn>,
|
|
||||||
/// Flattened collection of all external Rust functions, native or scripted,
|
/// Flattened collection of all external Rust functions, native or scripted,
|
||||||
/// including those in sub-modules.
|
/// including those in sub-modules.
|
||||||
all_functions: HashMap<u64, CallableFunction, StraightHasherBuilder>,
|
all_functions: HashMap<u64, CallableFunction, StraightHasherBuilder>,
|
||||||
|
/// Iterator functions, keyed by the type producing the iterator.
|
||||||
|
type_iterators: HashMap<TypeId, IteratorFn>,
|
||||||
/// Is the module indexed?
|
/// Is the module indexed?
|
||||||
indexed: bool,
|
indexed: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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),
|
||||||
|
functions: HashMap::with_capacity_and_hasher(64, StraightHasherBuilder),
|
||||||
|
all_functions: HashMap::with_capacity_and_hasher(256, StraightHasherBuilder),
|
||||||
|
type_iterators: HashMap::with_capacity(4),
|
||||||
|
indexed: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Module {
|
impl fmt::Debug for Module {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
@ -1462,9 +1476,9 @@ impl Module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !self.indexed {
|
if !self.indexed {
|
||||||
let mut qualifiers: Vec<_> = Default::default();
|
let mut qualifiers = Vec::with_capacity(4);
|
||||||
let mut variables: Vec<_> = Default::default();
|
let mut variables = Vec::with_capacity(8);
|
||||||
let mut functions: Vec<_> = Default::default();
|
let mut functions = Vec::with_capacity(16);
|
||||||
|
|
||||||
qualifiers.push("root");
|
qualifiers.push("root");
|
||||||
|
|
||||||
|
@ -17,12 +17,6 @@ use crate::{calc_native_fn_hash, StaticVec};
|
|||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
use crate::ast::ReturnType;
|
use crate::ast::ReturnType;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
|
||||||
use crate::Array;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
|
||||||
use crate::Map;
|
|
||||||
|
|
||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
boxed::Box,
|
boxed::Box,
|
||||||
hash::{Hash, Hasher},
|
hash::{Hash, Hasher},
|
||||||
@ -566,26 +560,22 @@ fn optimize_expr(expr: &mut Expr, state: &mut State) {
|
|||||||
},
|
},
|
||||||
// [ constant .. ]
|
// [ constant .. ]
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Expr::Array(a, pos) if a.iter().all(Expr::is_constant) => {
|
Expr::Array(_, _) if expr.is_constant() => {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
let mut arr: Array = Default::default();
|
*expr = Expr::DynamicConstant(Box::new(expr.get_constant_value().unwrap()), expr.position());
|
||||||
arr.extend(mem::take(a).into_iter().map(|expr| expr.get_constant_value().unwrap()));
|
|
||||||
*expr = Expr::DynamicConstant(Box::new(arr.into()), *pos);
|
|
||||||
}
|
}
|
||||||
// [ items .. ]
|
// [ items .. ]
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Expr::Array(a, _) => a.iter_mut().for_each(|expr| optimize_expr(expr, state)),
|
Expr::Array(x, _) => x.iter_mut().for_each(|expr| optimize_expr(expr, state)),
|
||||||
// #{ key:constant, .. }
|
// #{ key:constant, .. }
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Expr::Map(m, pos) if m.iter().all(|(_, expr)| expr.is_constant()) => {
|
Expr::Map(_, _) if expr.is_constant()=> {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
let mut map: Map = Default::default();
|
*expr = Expr::DynamicConstant(Box::new(expr.get_constant_value().unwrap()), expr.position());
|
||||||
map.extend(mem::take(m).into_iter().map(|(key, expr)| (key.name, expr.get_constant_value().unwrap())));
|
|
||||||
*expr = Expr::DynamicConstant(Box::new(map.into()), *pos);
|
|
||||||
}
|
}
|
||||||
// #{ key:value, .. }
|
// #{ key:value, .. }
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Expr::Map(m, _) => m.iter_mut().for_each(|(_, expr)| optimize_expr(expr, state)),
|
Expr::Map(x, _) => x.iter_mut().for_each(|(_, expr)| optimize_expr(expr, state)),
|
||||||
// lhs in rhs
|
// lhs in rhs
|
||||||
Expr::In(x, _) => match (&mut x.lhs, &mut x.rhs) {
|
Expr::In(x, _) => match (&mut x.lhs, &mut x.rhs) {
|
||||||
// "xxx" in "xxxxx"
|
// "xxx" in "xxxxx"
|
||||||
|
@ -56,7 +56,9 @@ pub(crate) struct PackagesCollection(StaticVec<PackageLibrary>);
|
|||||||
|
|
||||||
impl PackagesCollection {
|
impl PackagesCollection {
|
||||||
/// Add a `PackageLibrary` into the `PackagesCollection`.
|
/// Add a `PackageLibrary` into the `PackagesCollection`.
|
||||||
pub fn push(&mut self, package: PackageLibrary) {
|
///
|
||||||
|
/// Packages are searched in reverse order.
|
||||||
|
pub fn add(&mut self, package: PackageLibrary) {
|
||||||
// Later packages override previous ones.
|
// Later packages override previous ones.
|
||||||
self.0.insert(0, package);
|
self.0.insert(0, package);
|
||||||
}
|
}
|
||||||
|
@ -69,7 +69,7 @@ struct ParseState<'e> {
|
|||||||
allow_capture: bool,
|
allow_capture: bool,
|
||||||
/// Encapsulates a local stack with imported module names.
|
/// Encapsulates a local stack with imported module names.
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
modules: Vec<ImmutableString>,
|
modules: StaticVec<ImmutableString>,
|
||||||
/// Maximum levels of expression nesting.
|
/// Maximum levels of expression nesting.
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
max_expr_depth: usize,
|
max_expr_depth: usize,
|
||||||
@ -99,11 +99,11 @@ impl<'e> ParseState<'e> {
|
|||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
max_function_expr_depth,
|
max_function_expr_depth,
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
externals: Default::default(),
|
externals: HashMap::with_capacity(8),
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
allow_capture: true,
|
allow_capture: true,
|
||||||
strings: Default::default(),
|
strings: HashMap::with_capacity(64),
|
||||||
stack: Default::default(),
|
stack: Vec::with_capacity(16),
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
modules: Default::default(),
|
modules: Default::default(),
|
||||||
}
|
}
|
||||||
@ -818,7 +818,7 @@ fn parse_switch(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut table: HashMap<u64, Stmt, StraightHasherBuilder> = Default::default();
|
let mut table = HashMap::with_capacity_and_hasher(16, StraightHasherBuilder);
|
||||||
let mut def_stmt = None;
|
let mut def_stmt = None;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
@ -1137,17 +1137,15 @@ fn parse_unary(
|
|||||||
|
|
||||||
match token {
|
match token {
|
||||||
// If statement is allowed to act as expressions
|
// If statement is allowed to act as expressions
|
||||||
Token::If if settings.allow_if_expr => {
|
Token::If if settings.allow_if_expr => Ok(Expr::Stmt(
|
||||||
let mut block: StaticVec<_> = Default::default();
|
Box::new(vec![parse_if(input, state, lib, settings.level_up())?].into()),
|
||||||
block.push(parse_if(input, state, lib, settings.level_up())?);
|
settings.pos,
|
||||||
Ok(Expr::Stmt(Box::new(block), settings.pos))
|
)),
|
||||||
}
|
|
||||||
// Switch statement is allowed to act as expressions
|
// Switch statement is allowed to act as expressions
|
||||||
Token::Switch if settings.allow_switch_expr => {
|
Token::Switch if settings.allow_switch_expr => Ok(Expr::Stmt(
|
||||||
let mut block: StaticVec<_> = Default::default();
|
Box::new(vec![parse_switch(input, state, lib, settings.level_up())?].into()),
|
||||||
block.push(parse_switch(input, state, lib, settings.level_up())?);
|
settings.pos,
|
||||||
Ok(Expr::Stmt(Box::new(block), settings.pos))
|
)),
|
||||||
}
|
|
||||||
// -expr
|
// -expr
|
||||||
Token::UnaryMinus => {
|
Token::UnaryMinus => {
|
||||||
let pos = eat_token(input, Token::UnaryMinus);
|
let pos = eat_token(input, Token::UnaryMinus);
|
||||||
@ -2635,7 +2633,7 @@ fn parse_fn(
|
|||||||
let params: StaticVec<_> = params.into_iter().map(|(p, _)| p).collect();
|
let params: StaticVec<_> = params.into_iter().map(|(p, _)| p).collect();
|
||||||
|
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
let externals: HashSet<_> = state
|
let externals = state
|
||||||
.externals
|
.externals
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(name, _)| name)
|
.map(|(name, _)| name)
|
||||||
@ -2802,7 +2800,7 @@ fn parse_anon_fn(
|
|||||||
access: FnAccess::Public,
|
access: FnAccess::Public,
|
||||||
params,
|
params,
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
externals: Default::default(),
|
externals: HashSet::with_capacity(4),
|
||||||
body,
|
body,
|
||||||
lib: None,
|
lib: None,
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
Loading…
Reference in New Issue
Block a user