Optimize imports layout.

This commit is contained in:
Stephen Chung 2021-03-12 22:30:08 +08:00
parent 81ca86a8d2
commit 61b0c7b2b3
4 changed files with 36 additions and 42 deletions

View File

@ -53,7 +53,7 @@ pub const TYPICAL_MAP_SIZE: usize = 8; // Small maps are typical
// the module name will live beyond the AST of the eval script text.
// The best we can do is a shared reference.
#[derive(Debug, Clone, Default)]
pub struct Imports(StaticVec<(ImmutableString, Shared<Module>)>);
pub struct Imports(StaticVec<ImmutableString>, StaticVec<Shared<Module>>);
impl Imports {
/// Get the length of this stack of imported [modules][Module].
@ -69,7 +69,7 @@ impl Imports {
/// Get the imported [modules][Module] at a particular index.
#[inline(always)]
pub fn get(&self, index: usize) -> Option<Shared<Module>> {
self.0.get(index).map(|(_, m)| m).cloned()
self.1.get(index).cloned()
}
/// Get the index of an imported [modules][Module] by name.
#[inline(always)]
@ -78,18 +78,19 @@ impl Imports {
.iter()
.enumerate()
.rev()
.find(|(_, (key, _))| key.as_str() == name)
.map(|(index, _)| index)
.find_map(|(i, key)| if key.as_str() == name { Some(i) } else { None })
}
/// Push an imported [modules][Module] onto the stack.
#[inline(always)]
pub fn push(&mut self, name: impl Into<ImmutableString>, module: impl Into<Shared<Module>>) {
self.0.push((name.into(), module.into()));
self.0.push(name.into());
self.1.push(module.into());
}
/// Truncate the stack of imported [modules][Module] to a particular length.
#[inline(always)]
pub fn truncate(&mut self, size: usize) {
self.0.truncate(size);
self.1.truncate(size);
}
/// Get an iterator to this stack of imported [modules][Module] in reverse order.
#[allow(dead_code)]
@ -97,6 +98,7 @@ impl Imports {
pub fn iter(&self) -> impl Iterator<Item = (&str, &Module)> {
self.0
.iter()
.zip(self.1.iter())
.rev()
.map(|(name, module)| (name.as_str(), module.as_ref()))
}
@ -104,52 +106,44 @@ impl Imports {
#[allow(dead_code)]
#[inline(always)]
pub(crate) fn iter_raw(&self) -> impl Iterator<Item = (&ImmutableString, &Shared<Module>)> {
self.0.iter().rev().map(|(n, m)| (n, m))
self.0.iter().rev().zip(self.1.iter().rev())
}
/// Get an iterator to this stack of imported [modules][Module] in forward order.
#[allow(dead_code)]
#[inline(always)]
pub(crate) fn scan_raw(&self) -> impl Iterator<Item = (&ImmutableString, &Shared<Module>)> {
self.0.iter().map(|(n, m)| (n, m))
self.0.iter().zip(self.1.iter())
}
/// Get a consuming iterator to this stack of imported [modules][Module] in reverse order.
#[inline(always)]
pub fn into_iter(self) -> impl Iterator<Item = (ImmutableString, Shared<Module>)> {
self.0.into_iter().rev()
}
/// Add a stream of imported [modules][Module].
#[inline(always)]
pub fn extend(&mut self, stream: impl Iterator<Item = (ImmutableString, Shared<Module>)>) {
self.0.extend(stream)
self.0.into_iter().rev().zip(self.1.into_iter().rev())
}
/// Does the specified function hash key exist in this stack of imported [modules][Module]?
#[allow(dead_code)]
#[inline(always)]
pub fn contains_fn(&self, hash: u64) -> bool {
self.0.iter().any(|(_, m)| m.contains_qualified_fn(hash))
self.1.iter().any(|m| m.contains_qualified_fn(hash))
}
/// Get specified function via its hash key.
#[inline(always)]
pub fn get_fn(&self, hash: u64) -> Option<(&CallableFunction, Option<&ImmutableString>)> {
self.0
self.1
.iter()
.rev()
.find_map(|(_, m)| m.get_qualified_fn(hash).map(|f| (f, m.id_raw())))
.find_map(|m| m.get_qualified_fn(hash).map(|f| (f, m.id_raw())))
}
/// Does the specified [`TypeId`][std::any::TypeId] iterator exist in this stack of
/// imported [modules][Module]?
#[allow(dead_code)]
#[inline(always)]
pub fn contains_iter(&self, id: TypeId) -> bool {
self.0.iter().any(|(_, m)| m.contains_qualified_iter(id))
self.1.iter().any(|m| m.contains_qualified_iter(id))
}
/// Get the specified [`TypeId`][std::any::TypeId] iterator.
#[inline(always)]
pub fn get_iter(&self, id: TypeId) -> Option<IteratorFn> {
self.0
.iter()
.rev()
.find_map(|(_, m)| m.get_qualified_iter(id))
self.1.iter().rev().find_map(|m| m.get_qualified_iter(id))
}
}

View File

@ -539,7 +539,10 @@ impl Engine {
#[cfg(not(feature = "no_module"))]
if !fn_def.mods.is_empty() {
mods.extend(fn_def.mods.iter_raw().map(|(n, m)| (n.clone(), m.clone())));
fn_def
.mods
.iter_raw()
.for_each(|(n, m)| mods.push(n.clone(), m.clone()));
}
// Evaluate the function

View File

@ -1836,7 +1836,7 @@ impl Module {
// Collect a particular module.
fn index_module<'a>(
module: &'a Module,
qualifiers: &mut Vec<&'a str>,
path: &mut Vec<&'a str>,
variables: &mut HashMap<u64, Dynamic, StraightHasherBuilder>,
functions: &mut HashMap<u64, CallableFunction, StraightHasherBuilder>,
type_iterators: &mut HashMap<TypeId, IteratorFn>,
@ -1845,16 +1845,16 @@ impl Module {
module.modules.iter().for_each(|(name, m)| {
// Index all the sub-modules first.
qualifiers.push(name);
if index_module(m, qualifiers, variables, functions, type_iterators) {
path.push(name);
if index_module(m, path, variables, functions, type_iterators) {
contains_indexed_global_functions = true;
}
qualifiers.pop();
path.pop();
});
// Index all variables
module.variables.iter().for_each(|(var_name, value)| {
let hash_var = crate::calc_fn_hash(qualifiers.iter().map(|&v| v), var_name, 0);
let hash_var = crate::calc_fn_hash(path.iter().map(|&v| v), var_name, 0);
variables.insert(hash_var, value.clone());
});
@ -1880,15 +1880,12 @@ impl Module {
}
if !f.func.is_script() {
let hash_qualified_fn = calc_native_fn_hash(
qualifiers.iter().cloned(),
f.name.as_str(),
&f.param_types,
);
let hash_qualified_fn =
calc_native_fn_hash(path.iter().cloned(), f.name.as_str(), &f.param_types);
functions.insert(hash_qualified_fn, f.func.clone());
} else if cfg!(not(feature = "no_function")) {
let hash_qualified_script =
crate::calc_fn_hash(qualifiers.iter().cloned(), f.name.as_str(), f.params);
crate::calc_fn_hash(path.iter().cloned(), f.name.as_str(), f.params);
functions.insert(hash_qualified_script, f.func.clone());
}
});
@ -1897,16 +1894,16 @@ impl Module {
}
if !self.indexed {
let mut qualifiers = Vec::with_capacity(4);
let mut path = Vec::with_capacity(4);
let mut variables = HashMap::with_capacity_and_hasher(16, StraightHasherBuilder);
let mut functions = HashMap::with_capacity_and_hasher(256, StraightHasherBuilder);
let mut type_iterators = HashMap::with_capacity(16);
qualifiers.push("root");
path.push("root");
self.contains_indexed_global_functions = index_module(
self,
&mut qualifiers,
&mut path,
&mut variables,
&mut functions,
&mut type_iterators,

View File

@ -840,8 +840,8 @@ pub fn parse_string_literal(
pos: &mut Position,
enclosing_char: char,
) -> Result<String, (LexError, Position)> {
let mut result: StaticVec<char> = Default::default();
let mut escape: StaticVec<char> = Default::default();
let mut result: smallvec::SmallVec<[char; 16]> = Default::default();
let mut escape: smallvec::SmallVec<[char; 12]> = Default::default();
let start = *pos;
@ -1109,7 +1109,7 @@ fn get_next_token_inner(
// digit ...
('0'..='9', _) => {
let mut result: StaticVec<char> = Default::default();
let mut result: smallvec::SmallVec<[char; 16]> = Default::default();
let mut radix_base: Option<u32> = None;
let mut valid: fn(char) -> bool = is_numeric_digit;
result.push(c);
@ -1596,7 +1596,7 @@ fn get_identifier(
start_pos: Position,
first_char: char,
) -> Option<(Token, Position)> {
let mut result: StaticVec<_> = Default::default();
let mut result: smallvec::SmallVec<[char; 8]> = Default::default();
result.push(first_char);
while let Some(next_char) = stream.peek_next() {
@ -1691,10 +1691,10 @@ pub fn is_id_continue(x: char) -> bool {
pub struct MultiInputsStream<'a> {
/// Buffered character, if any.
buf: Option<char>,
/// The input character streams.
streams: StaticVec<Peekable<Chars<'a>>>,
/// The current stream index.
index: usize,
/// The input character streams.
streams: StaticVec<Peekable<Chars<'a>>>,
}
impl InputStream for MultiInputsStream<'_> {