Calculate whether contains global functions during indexing.

This commit is contained in:
Stephen Chung 2021-03-05 20:07:35 +08:00
parent 4e5039d4fe
commit 65ef32af19
4 changed files with 78 additions and 77 deletions

View File

@ -1893,7 +1893,7 @@ impl Engine {
if mods if mods
.scan_raw() .scan_raw()
.skip(_mods_len) .skip(_mods_len)
.any(|(_, m)| m.has_namespace(crate::FnNamespace::Global, true)) .any(|(_, m)| m.contains_indexed_global_functions())
{ {
if _restore_fn_resolution_cache { if _restore_fn_resolution_cache {
// When new module is imported with global functions and there is already // When new module is imported with global functions and there is already

View File

@ -188,42 +188,6 @@ impl Engine {
allow_dynamic: bool, allow_dynamic: bool,
is_op_assignment: bool, is_op_assignment: bool,
) -> &'s Option<(CallableFunction, Option<ImmutableString>)> { ) -> &'s Option<(CallableFunction, Option<ImmutableString>)> {
fn find_function(
engine: &Engine,
hash: NonZeroU64,
mods: &Imports,
lib: &[&Module],
) -> Option<(CallableFunction, Option<ImmutableString>)> {
lib.iter()
.find_map(|m| {
m.get_fn(hash, false)
.map(|f| (f.clone(), m.id_raw().cloned()))
})
.or_else(|| {
engine
.global_namespace
.get_fn(hash, false)
.cloned()
.map(|f| (f, None))
})
.or_else(|| {
engine.global_modules.iter().find_map(|m| {
m.get_fn(hash, false)
.map(|f| (f.clone(), m.id_raw().cloned()))
})
})
.or_else(|| {
mods.get_fn(hash)
.map(|(f, source)| (f.clone(), source.cloned()))
})
.or_else(|| {
engine.global_sub_modules.values().find_map(|m| {
m.get_qualified_fn(hash)
.map(|f| (f.clone(), m.id_raw().cloned()))
})
})
}
&*state &*state
.fn_resolution_cache_mut() .fn_resolution_cache_mut()
.entry(hash) .entry(hash)
@ -237,7 +201,36 @@ impl Engine {
let mut bitmask = 1usize; // Bitmask of which parameter to replace with `Dynamic` let mut bitmask = 1usize; // Bitmask of which parameter to replace with `Dynamic`
loop { loop {
match find_function(self, hash, mods, lib) { let func = lib
.iter()
.find_map(|m| {
m.get_fn(hash, false)
.map(|f| (f.clone(), m.id_raw().cloned()))
})
.or_else(|| {
self.global_namespace
.get_fn(hash, false)
.cloned()
.map(|f| (f, None))
})
.or_else(|| {
self.global_modules.iter().find_map(|m| {
m.get_fn(hash, false)
.map(|f| (f.clone(), m.id_raw().cloned()))
})
})
.or_else(|| {
mods.get_fn(hash)
.map(|(f, source)| (f.clone(), source.cloned()))
})
.or_else(|| {
self.global_sub_modules.values().find_map(|m| {
m.get_qualified_fn(hash)
.map(|f| (f.clone(), m.id_raw().cloned()))
})
});
match func {
// Specific version found // Specific version found
Some(f) => return Some(f), Some(f) => return Some(f),
@ -520,18 +513,16 @@ impl Engine {
); );
// Merge in encapsulated environment, if any // Merge in encapsulated environment, if any
let mut lib_merged: StaticVec<_>; let lib_merged;
let mut unified = false;
let unified_lib = if let Some(ref env_lib) = fn_def.lib { let (unified_lib, unified) = if let Some(ref env_lib) = fn_def.lib {
unified = true;
state.push_fn_resolution_cache(); state.push_fn_resolution_cache();
lib_merged = Default::default(); lib_merged = once(env_lib.as_ref())
lib_merged.push(env_lib.as_ref()); .chain(lib.iter().cloned())
lib_merged.extend(lib.iter().cloned()); .collect::<StaticVec<_>>();
lib_merged.as_ref() (lib_merged.as_ref(), true)
} else { } else {
lib (lib, false)
}; };
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]

View File

@ -127,6 +127,8 @@ pub struct Module {
all_type_iterators: HashMap<TypeId, IteratorFn>, all_type_iterators: HashMap<TypeId, IteratorFn>,
/// Is the [`Module`] indexed? /// Is the [`Module`] indexed?
indexed: bool, indexed: bool,
/// Does the [`Module`] contain indexed functions that have been exposed to the global namespace?
contains_indexed_global_functions: bool,
} }
impl Default for Module { impl Default for Module {
@ -141,6 +143,7 @@ impl Default for Module {
type_iterators: Default::default(), type_iterators: Default::default(),
all_type_iterators: Default::default(), all_type_iterators: Default::default(),
indexed: false, indexed: false,
contains_indexed_global_functions: false,
} }
} }
} }
@ -434,6 +437,7 @@ impl Module {
) -> &mut Self { ) -> &mut Self {
self.variables.insert(name.into(), Dynamic::from(value)); self.variables.insert(name.into(), Dynamic::from(value));
self.indexed = false; self.indexed = false;
self.contains_indexed_global_functions = false;
self self
} }
@ -477,6 +481,7 @@ impl Module {
}, },
); );
self.indexed = false; self.indexed = false;
self.contains_indexed_global_functions = false;
hash_script hash_script
} }
@ -521,6 +526,7 @@ impl Module {
self.all_variables.clear(); self.all_variables.clear();
self.all_type_iterators.clear(); self.all_type_iterators.clear();
self.indexed = false; self.indexed = false;
self.contains_indexed_global_functions = false;
&mut self.modules &mut self.modules
} }
@ -581,6 +587,7 @@ impl Module {
) -> &mut Self { ) -> &mut Self {
self.modules.insert(name.into(), sub_module.into()); self.modules.insert(name.into(), sub_module.into());
self.indexed = false; self.indexed = false;
self.contains_indexed_global_functions = false;
self self
} }
@ -649,6 +656,7 @@ impl Module {
f.namespace = namespace; f.namespace = namespace;
} }
self.indexed = false; self.indexed = false;
self.contains_indexed_global_functions = false;
self self
} }
@ -704,6 +712,7 @@ impl Module {
); );
self.indexed = false; self.indexed = false;
self.contains_indexed_global_functions = false;
hash_fn hash_fn
} }
@ -1497,6 +1506,7 @@ impl Module {
self.all_variables.clear(); self.all_variables.clear();
self.all_type_iterators.clear(); self.all_type_iterators.clear();
self.indexed = false; self.indexed = false;
self.contains_indexed_global_functions = false;
self self
} }
@ -1515,6 +1525,7 @@ impl Module {
self.all_variables.clear(); self.all_variables.clear();
self.all_type_iterators.clear(); self.all_type_iterators.clear();
self.indexed = false; self.indexed = false;
self.contains_indexed_global_functions = false;
self self
} }
@ -1542,6 +1553,7 @@ impl Module {
self.all_variables.clear(); self.all_variables.clear();
self.all_type_iterators.clear(); self.all_type_iterators.clear();
self.indexed = false; self.indexed = false;
self.contains_indexed_global_functions = false;
self self
} }
@ -1602,6 +1614,7 @@ impl Module {
self.all_variables.clear(); self.all_variables.clear();
self.all_type_iterators.clear(); self.all_type_iterators.clear();
self.indexed = false; self.indexed = false;
self.contains_indexed_global_functions = false;
self self
} }
@ -1634,6 +1647,7 @@ impl Module {
self.all_variables.clear(); self.all_variables.clear();
self.all_type_iterators.clear(); self.all_type_iterators.clear();
self.indexed = false; self.indexed = false;
self.contains_indexed_global_functions = false;
self self
} }
@ -1820,29 +1834,14 @@ impl Module {
Ok(module) Ok(module)
} }
/// Are there functions (or type iterators) marked for the specified namespace? /// Does the [`Module`] contain indexed functions that have been exposed to the global namespace?
pub fn has_namespace(&self, namespace: FnNamespace, recursive: bool) -> bool { ///
// Type iterators are default global /// # Panics
if !self.type_iterators.is_empty() { ///
return true; /// Panics if the [`Module`] is not yet indexed via [`build_index`][Module::build_index].
} #[inline(always)]
// Any function marked global? pub fn contains_indexed_global_functions(&self) -> bool {
if self.functions.values().any(|f| f.namespace == namespace) { self.contains_indexed_global_functions
return true;
}
// Scan sub-modules
if recursive {
if self
.modules
.values()
.any(|m| m.has_namespace(namespace, recursive))
{
return true;
}
}
false
} }
/// Scan through all the sub-modules in the [`Module`] and build a hash index of all /// Scan through all the sub-modules in the [`Module`] and build a hash index of all
@ -1857,11 +1856,15 @@ impl Module {
variables: &mut HashMap<NonZeroU64, Dynamic, StraightHasherBuilder>, variables: &mut HashMap<NonZeroU64, Dynamic, StraightHasherBuilder>,
functions: &mut HashMap<NonZeroU64, CallableFunction, StraightHasherBuilder>, functions: &mut HashMap<NonZeroU64, CallableFunction, StraightHasherBuilder>,
type_iterators: &mut HashMap<TypeId, IteratorFn>, type_iterators: &mut HashMap<TypeId, IteratorFn>,
) { ) -> bool {
let mut contains_indexed_global_functions = false;
module.modules.iter().for_each(|(name, m)| { module.modules.iter().for_each(|(name, m)| {
// Index all the sub-modules first. // Index all the sub-modules first.
qualifiers.push(name); qualifiers.push(name);
index_module(m, qualifiers, variables, functions, type_iterators); if index_module(m, qualifiers, variables, functions, type_iterators) {
contains_indexed_global_functions = true;
}
qualifiers.pop(); qualifiers.pop();
}); });
@ -1875,6 +1878,7 @@ impl Module {
// Index type iterators // Index type iterators
module.type_iterators.iter().for_each(|(&type_id, func)| { module.type_iterators.iter().for_each(|(&type_id, func)| {
type_iterators.insert(type_id, func.clone()); type_iterators.insert(type_id, func.clone());
contains_indexed_global_functions = true;
}); });
// Index all Rust functions // Index all Rust functions
@ -1895,6 +1899,7 @@ impl Module {
FnNamespace::Global => { FnNamespace::Global => {
// Flatten all functions with global namespace // Flatten all functions with global namespace
functions.insert(hash, func.clone()); functions.insert(hash, func.clone());
contains_indexed_global_functions = true;
} }
FnNamespace::Internal => (), FnNamespace::Internal => (),
} }
@ -1927,6 +1932,8 @@ impl Module {
} }
}, },
); );
contains_indexed_global_functions
} }
if !self.indexed { if !self.indexed {
@ -1937,7 +1944,7 @@ impl Module {
qualifiers.push("root"); qualifiers.push("root");
index_module( self.contains_indexed_global_functions = index_module(
self, self,
&mut qualifiers, &mut qualifiers,
&mut variables, &mut variables,
@ -1968,6 +1975,7 @@ impl Module {
pub fn set_iter(&mut self, typ: TypeId, func: IteratorFn) -> &mut Self { pub fn set_iter(&mut self, typ: TypeId, func: IteratorFn) -> &mut Self {
self.type_iterators.insert(typ, func); self.type_iterators.insert(typ, func);
self.indexed = false; self.indexed = false;
self.contains_indexed_global_functions = false;
self self
} }

View File

@ -24,10 +24,12 @@ fn test_module_sub_module() -> Result<(), Box<EvalAltResult>> {
sub_module2.set_var("answer", 41 as INT); sub_module2.set_var("answer", 41 as INT);
let hash_inc = sub_module2.set_fn_1_mut("inc", FnNamespace::Internal, |x: &mut INT| Ok(*x + 1)); let hash_inc = sub_module2.set_fn_1_mut("inc", FnNamespace::Internal, |x: &mut INT| Ok(*x + 1));
assert!(!sub_module2.has_namespace(FnNamespace::Global, true)); sub_module2.build_index();
assert!(!sub_module2.contains_indexed_global_functions());
sub_module2.set_fn_1_mut("super_inc", FnNamespace::Global, |x: &mut INT| Ok(*x + 1)); sub_module2.set_fn_1_mut("super_inc", FnNamespace::Global, |x: &mut INT| Ok(*x + 1));
assert!(sub_module2.has_namespace(FnNamespace::Global, true)); sub_module2.build_index();
assert!(sub_module2.contains_indexed_global_functions());
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
sub_module2.set_getter_fn("doubled", |x: &mut INT| Ok(*x * 2)); sub_module2.set_getter_fn("doubled", |x: &mut INT| Ok(*x * 2));
@ -35,9 +37,9 @@ fn test_module_sub_module() -> Result<(), Box<EvalAltResult>> {
sub_module.set_sub_module("universe", sub_module2); sub_module.set_sub_module("universe", sub_module2);
module.set_sub_module("life", sub_module); module.set_sub_module("life", sub_module);
module.set_var("MYSTIC_NUMBER", Dynamic::from(42 as INT)); module.set_var("MYSTIC_NUMBER", Dynamic::from(42 as INT));
module.build_index();
assert!(module.has_namespace(FnNamespace::Global, true)); assert!(module.contains_indexed_global_functions());
assert!(!module.has_namespace(FnNamespace::Global, false));
assert!(module.contains_sub_module("life")); assert!(module.contains_sub_module("life"));
let m = module.get_sub_module("life").unwrap(); let m = module.get_sub_module("life").unwrap();