Make FunctionsLib a HashMap.

This commit is contained in:
Stephen Chung 2020-04-16 23:58:57 +08:00
parent f8e9d66a0b
commit 3a93ab8240
4 changed files with 45 additions and 62 deletions

View File

@ -956,7 +956,11 @@ impl Engine {
ast: AST, ast: AST,
optimization_level: OptimizationLevel, optimization_level: OptimizationLevel,
) -> AST { ) -> AST {
let fn_lib = ast.1.iter().map(|fn_def| fn_def.as_ref().clone()).collect(); let fn_lib = ast
.1
.iter()
.map(|(_, fn_def)| fn_def.as_ref().clone())
.collect();
optimize_into_ast(self, scope, ast.0, fn_lib, optimization_level) optimize_into_ast(self, scope, ast.0, fn_lib, optimization_level)
} }

View File

@ -11,7 +11,6 @@ use crate::token::Position;
use crate::stdlib::{ use crate::stdlib::{
any::TypeId, any::TypeId,
boxed::Box, boxed::Box,
cmp::Ordering,
collections::{hash_map::DefaultHasher, HashMap}, collections::{hash_map::DefaultHasher, HashMap},
format, format,
hash::{Hash, Hasher}, hash::{Hash, Hasher},
@ -125,48 +124,41 @@ impl<'a> From<&'a mut Dynamic> for Target<'a> {
/// So instead this is implemented as a sorted list and binary searched. /// So instead this is implemented as a sorted list and binary searched.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct FunctionsLib( pub struct FunctionsLib(
#[cfg(feature = "sync")] Vec<Arc<FnDef>>, #[cfg(feature = "sync")] HashMap<u64, Arc<FnDef>>,
#[cfg(not(feature = "sync"))] Vec<Rc<FnDef>>, #[cfg(not(feature = "sync"))] HashMap<u64, Rc<FnDef>>,
); );
impl FnDef {
/// Function to order two FnDef records, for binary search.
pub fn compare(&self, name: &str, params_len: usize) -> Ordering {
// First order by name
match self.name.as_str().cmp(name) {
// Then by number of parameters
Ordering::Equal => self.params.len().cmp(&params_len),
order => order,
}
}
}
impl FunctionsLib { impl FunctionsLib {
/// Create a new `FunctionsLib`. /// Create a new `FunctionsLib`.
pub fn new() -> Self { pub fn new() -> Self {
FunctionsLib(Vec::new()) FunctionsLib(HashMap::new())
} }
/// Create a new `FunctionsLib` from a collection of `FnDef`. /// Create a new `FunctionsLib` from a collection of `FnDef`.
pub fn from_vec(vec: Vec<FnDef>) -> Self { pub fn from_vec(vec: Vec<FnDef>) -> Self {
#[cfg(feature = "sync")] FunctionsLib(
{ vec.into_iter()
FunctionsLib(vec.into_iter().map(Arc::new).collect()) .map(|f| {
} let hash = calc_fn_def(&f.name, f.params.len());
#[cfg(not(feature = "sync"))]
{ #[cfg(feature = "sync")]
FunctionsLib(vec.into_iter().map(Rc::new).collect()) {
} (hash, Arc::new(f))
}
#[cfg(not(feature = "sync"))]
{
(hash, Rc::new(f))
}
})
.collect(),
)
} }
/// Does a certain function exist in the `FunctionsLib`? /// Does a certain function exist in the `FunctionsLib`?
pub fn has_function(&self, name: &str, params: usize) -> bool { pub fn has_function(&self, name: &str, params: usize) -> bool {
self.0.binary_search_by(|f| f.compare(name, params)).is_ok() self.contains_key(&calc_fn_def(name, params))
} }
/// Get a function definition from the `FunctionsLib`. /// Get a function definition from the `FunctionsLib`.
pub fn get_function(&self, name: &str, params: usize) -> Option<&FnDef> { pub fn get_function(&self, name: &str, params: usize) -> Option<&FnDef> {
self.0 self.get(&calc_fn_def(name, params)).map(|f| f.as_ref())
.binary_search_by(|f| f.compare(name, params))
.ok()
.map(|n| self.0[n].as_ref())
} }
/// Merge another `FunctionsLib` into this `FunctionsLib`. /// Merge another `FunctionsLib` into this `FunctionsLib`.
pub fn merge(&self, other: &Self) -> Self { pub fn merge(&self, other: &Self) -> Self {
@ -177,16 +169,8 @@ impl FunctionsLib {
} else { } else {
let mut functions = self.clone(); let mut functions = self.clone();
other.iter().cloned().for_each(|fn_def| { other.iter().for_each(|(hash, fn_def)| {
if let Some((n, _)) = functions functions.insert(*hash, fn_def.clone());
.iter()
.enumerate()
.find(|(_, f)| f.name == fn_def.name && f.params.len() == fn_def.params.len())
{
functions[n] = fn_def;
} else {
functions.push(fn_def);
}
}); });
functions functions
@ -196,9 +180,9 @@ impl FunctionsLib {
impl Deref for FunctionsLib { impl Deref for FunctionsLib {
#[cfg(feature = "sync")] #[cfg(feature = "sync")]
type Target = Vec<Arc<FnDef>>; type Target = HashMap<u64, Arc<FnDef>>;
#[cfg(not(feature = "sync"))] #[cfg(not(feature = "sync"))]
type Target = Vec<Rc<FnDef>>; type Target = HashMap<u64, Rc<FnDef>>;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.0 &self.0
@ -207,11 +191,11 @@ impl Deref for FunctionsLib {
impl DerefMut for FunctionsLib { impl DerefMut for FunctionsLib {
#[cfg(feature = "sync")] #[cfg(feature = "sync")]
fn deref_mut(&mut self) -> &mut Vec<Arc<FnDef>> { fn deref_mut(&mut self) -> &mut HashMap<u64, Arc<FnDef>> {
&mut self.0 &mut self.0
} }
#[cfg(not(feature = "sync"))] #[cfg(not(feature = "sync"))]
fn deref_mut(&mut self) -> &mut Vec<Rc<FnDef>> { fn deref_mut(&mut self) -> &mut HashMap<u64, Rc<FnDef>> {
&mut self.0 &mut self.0
} }
} }
@ -349,6 +333,13 @@ pub(crate) fn calc_fn_spec(fn_name: &str, params: impl Iterator<Item = TypeId>)
s.finish() s.finish()
} }
pub(crate) fn calc_fn_def(fn_name: &str, params: usize) -> u64 {
let mut s = DefaultHasher::new();
fn_name.hash(&mut s);
params.hash(&mut s);
s.finish()
}
impl Engine { impl Engine {
/// Create a new `Engine` /// Create a new `Engine`
pub fn new() -> Self { pub fn new() -> Self {

View File

@ -1,7 +1,7 @@
//! Main module defining the lexer and parser. //! Main module defining the lexer and parser.
use crate::any::{Dynamic, Union}; use crate::any::{Dynamic, Union};
use crate::engine::{Engine, FunctionsLib}; use crate::engine::{calc_fn_def, Engine, FunctionsLib};
use crate::error::{LexError, ParseError, ParseErrorType}; use crate::error::{LexError, ParseError, ParseErrorType};
use crate::optimize::{optimize_into_ast, OptimizationLevel}; use crate::optimize::{optimize_into_ast, OptimizationLevel};
use crate::scope::{EntryType as ScopeEntryType, Scope}; use crate::scope::{EntryType as ScopeEntryType, Scope};
@ -1787,9 +1787,9 @@ pub fn parse_global_expr<'a>(
/// Parse the global level statements. /// Parse the global level statements.
fn parse_global_level<'a>( fn parse_global_level<'a>(
input: &mut Peekable<TokenIterator<'a>>, input: &mut Peekable<TokenIterator<'a>>,
) -> Result<(Vec<Stmt>, Vec<FnDef>), ParseError> { ) -> Result<(Vec<Stmt>, HashMap<u64, FnDef>), ParseError> {
let mut statements = Vec::<Stmt>::new(); let mut statements = Vec::<Stmt>::new();
let mut functions = Vec::<FnDef>::new(); let mut functions = HashMap::<u64, FnDef>::new();
while input.peek().is_some() { while input.peek().is_some() {
// Collect all the function definitions // Collect all the function definitions
@ -1797,13 +1797,7 @@ fn parse_global_level<'a>(
{ {
if matches!(input.peek().expect("should not be None"), (Token::Fn, _)) { if matches!(input.peek().expect("should not be None"), (Token::Fn, _)) {
let f = parse_fn(input, true)?; let f = parse_fn(input, true)?;
functions.insert(calc_fn_def(&f.name, f.params.len()), f);
// Ensure list is sorted
match functions.binary_search_by(|fn_def| fn_def.compare(&f.name, f.params.len())) {
Ok(n) => functions[n] = f, // Override previous definition
Err(n) => functions.insert(n, f), // New function definition
}
continue; continue;
} }
} }
@ -1849,9 +1843,10 @@ pub fn parse<'a>(
) -> Result<AST, ParseError> { ) -> Result<AST, ParseError> {
let (statements, functions) = parse_global_level(input)?; let (statements, functions) = parse_global_level(input)?;
let fn_lib = functions.into_iter().map(|(_, v)| v).collect();
Ok( Ok(
// Optimize AST // Optimize AST
optimize_into_ast(engine, scope, statements, functions, optimization_level), optimize_into_ast(engine, scope, statements, fn_lib, optimization_level),
) )
} }

View File

@ -397,13 +397,6 @@ impl<'a> Scope<'a> {
&mut entry.value &mut entry.value
} }
/// Get a mutable reference to an entry in the Scope and downcast it to a specific type
pub(crate) fn get_mut_by_type<T: Variant + Clone>(&mut self, key: EntryRef) -> &mut T {
self.get_mut(key)
.downcast_mut::<T>()
.expect("wrong type cast")
}
/// Get an iterator to entries in the Scope. /// Get an iterator to entries in the Scope.
pub fn iter(&self) -> impl Iterator<Item = &Entry> { pub fn iter(&self) -> impl Iterator<Item = &Entry> {
self.0.iter().rev() // Always search a Scope in reverse order self.0.iter().rev() // Always search a Scope in reverse order