diff --git a/src/func/call.rs b/src/func/call.rs index 6677ab32..817a8d7b 100644 --- a/src/func/call.rs +++ b/src/func/call.rs @@ -10,9 +10,8 @@ use crate::engine::{ use crate::eval::{Caches, FnResolutionCacheEntry, GlobalRuntimeState}; use crate::tokenizer::{is_valid_function_name, Token}; use crate::{ - calc_fn_hash, calc_fn_params_hash, combine_hashes, Dynamic, Engine, FnArgsVec, FnPtr, - ImmutableString, Module, OptimizationLevel, Position, RhaiError, RhaiResult, RhaiResultOf, - Scope, ERR, + calc_fn_hash, calc_fn_hash_full, Dynamic, Engine, FnArgsVec, FnPtr, ImmutableString, Module, + OptimizationLevel, Position, RhaiError, RhaiResult, RhaiResultOf, Scope, ERR, }; #[cfg(feature = "no_std")] use hashbrown::hash_map::Entry; @@ -178,8 +177,7 @@ impl Engine { } let mut hash = args.as_ref().map_or(hash_base, |args| { - let hash_params = calc_fn_params_hash(args.iter().map(|a| a.type_id())); - combine_hashes(hash_base, hash_params) + calc_fn_hash_full(hash_base, args.iter().map(|a| a.type_id())) }); let cache = caches.fn_resolution_cache_mut(); @@ -287,7 +285,8 @@ impl Engine { } // Try all permutations with `Dynamic` wildcards - let hash_params = calc_fn_params_hash( + hash = calc_fn_hash_full( + hash_base, args.as_ref() .expect("no permutations") .iter() @@ -302,7 +301,6 @@ impl Engine { } }), ); - hash = combine_hashes(hash_base, hash_params); bitmask += 1; } @@ -1335,9 +1333,7 @@ impl Engine { // Then search native Rust functions None => { self.track_operation(global, pos)?; - let hash_params = calc_fn_params_hash(args.iter().map(|a| a.type_id())); - let hash_qualified_fn = combine_hashes(hash, hash_params); - + let hash_qualified_fn = calc_fn_hash_full(hash, args.iter().map(|a| a.type_id())); module.get_qualified_fn(hash_qualified_fn) } r => r, @@ -1355,16 +1351,18 @@ impl Engine { // Try all permutations with `Dynamic` wildcards while bitmask < max_bitmask { - let hash_params = calc_fn_params_hash(args.iter().enumerate().map(|(i, a)| { - let mask = 1usize << (num_args - i - 1); - if bitmask & mask == 0 { - a.type_id() - } else { - // Replace with `Dynamic` - TypeId::of::() - } - })); - let hash_qualified_fn = combine_hashes(hash, hash_params); + let hash_qualified_fn = calc_fn_hash_full( + hash, + args.iter().enumerate().map(|(i, a)| { + let mask = 1usize << (num_args - i - 1); + if bitmask & mask == 0 { + a.type_id() + } else { + // Replace with `Dynamic` + TypeId::of::() + } + }), + ); self.track_operation(global, pos)?; diff --git a/src/func/hashing.rs b/src/func/hashing.rs index 855dcd3d..2b457c4d 100644 --- a/src/func/hashing.rs +++ b/src/func/hashing.rs @@ -156,7 +156,7 @@ pub fn calc_fn_hash<'a>( } } -/// Calculate a non-zero [`u64`] hash key from a list of parameter types. +/// Calculate a non-zero [`u64`] hash key from a base [`u64`] hash key and a list of parameter types. /// /// Parameter types are passed in via [`TypeId`] values from an iterator. /// @@ -165,10 +165,12 @@ pub fn calc_fn_hash<'a>( /// If the hash happens to be zero, it is mapped to `DEFAULT_HASH`. #[inline] #[must_use] -pub fn calc_fn_params_hash( +pub fn calc_fn_hash_full( + base: u64, params: impl IntoIterator>, ) -> u64 { let s = &mut get_hasher(); + base.hash(s); let iter = params.into_iter(); let len = iter.len(); iter.for_each(|t| { @@ -181,17 +183,3 @@ pub fn calc_fn_params_hash( r => r, } } - -/// Combine two [`u64`] hashes by taking the XOR of them. -/// -/// # Zeros -/// -/// If the hash happens to be zero, it is mapped to `DEFAULT_HASH`. -#[inline(always)] -#[must_use] -pub const fn combine_hashes(a: u64, b: u64) -> u64 { - match a ^ b { - 0 => ALT_ZERO_HASH, - r => r, - } -} diff --git a/src/func/mod.rs b/src/func/mod.rs index 54652e74..6120764d 100644 --- a/src/func/mod.rs +++ b/src/func/mod.rs @@ -21,9 +21,7 @@ pub use call::FnCallArgs; pub use callable_function::CallableFunction; #[cfg(not(feature = "no_function"))] pub use func::Func; -pub use hashing::{ - calc_fn_hash, calc_fn_params_hash, calc_var_hash, combine_hashes, get_hasher, StraightHashMap, -}; +pub use hashing::{calc_fn_hash, calc_fn_hash_full, calc_var_hash, get_hasher, StraightHashMap}; pub use native::{ locked_read, locked_write, shared_get_mut, shared_make_mut, shared_take, shared_take_or_clone, shared_try_take, FnAny, FnPlugin, IteratorFn, Locked, NativeCallContext, SendSync, Shared, diff --git a/src/lib.rs b/src/lib.rs index 8879012f..12f36850 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -238,7 +238,7 @@ pub use func::Shared; /// Alias to [`RefCell`][std::cell::RefCell] or [`RwLock`][std::sync::RwLock] depending on the `sync` feature flag. pub use func::Locked; -use func::{calc_fn_hash, calc_fn_params_hash, calc_var_hash, combine_hashes}; +use func::{calc_fn_hash, calc_fn_hash_full, calc_var_hash}; pub use rhai_codegen::*; diff --git a/src/module/mod.rs b/src/module/mod.rs index f0f1a982..68ef16e3 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -10,8 +10,8 @@ use crate::func::{ }; use crate::types::{dynamic::Variant, BloomFilterU64, CustomTypesCollection}; use crate::{ - calc_fn_hash, calc_fn_params_hash, combine_hashes, Dynamic, Identifier, ImmutableString, - NativeCallContext, RhaiResultOf, Shared, SmartString, StaticVec, + calc_fn_hash, calc_fn_hash_full, Dynamic, Identifier, ImmutableString, NativeCallContext, + RhaiResultOf, Shared, SmartString, StaticVec, }; #[cfg(feature = "no_std")] use std::prelude::v1::*; @@ -151,9 +151,10 @@ pub fn calc_native_fn_hash<'a>( fn_name: &str, params: &[TypeId], ) -> u64 { - let hash_script = calc_fn_hash(modules, fn_name, params.len()); - let hash_params = calc_fn_params_hash(params.iter().copied()); - combine_hashes(hash_script, hash_params) + calc_fn_hash_full( + calc_fn_hash(modules, fn_name, params.len()), + params.iter().copied(), + ) } /// A module which may contain variables, sub-modules, external Rust functions, @@ -1028,8 +1029,7 @@ impl Module { let name = name.as_ref(); let hash_script = calc_fn_hash(None, name, param_types.len()); - let hash_params = calc_fn_params_hash(param_types.iter().copied()); - let hash_fn = combine_hashes(hash_script, hash_params); + let hash_fn = calc_fn_hash_full(hash_script, param_types.iter().copied()); if is_dynamic { self.dynamic_functions_filter.mark(hash_script); diff --git a/src/optimizer.rs b/src/optimizer.rs index bd7b0140..4428c6da 100644 --- a/src/optimizer.rs +++ b/src/optimizer.rs @@ -11,8 +11,8 @@ use crate::func::hashing::get_hasher; use crate::tokenizer::Token; use crate::types::dynamic::AccessMode; use crate::{ - calc_fn_hash, calc_fn_params_hash, combine_hashes, Dynamic, Engine, FnPtr, Identifier, - ImmutableString, Position, Scope, StaticVec, AST, INT, + calc_fn_hash, calc_fn_hash_full, Dynamic, Engine, FnPtr, Identifier, ImmutableString, Position, + Scope, StaticVec, AST, INT, }; #[cfg(feature = "no_std")] use std::prelude::v1::*; @@ -171,8 +171,7 @@ fn has_native_fn_override( hash_script: u64, arg_types: impl AsRef<[TypeId]>, ) -> bool { - let hash_params = calc_fn_params_hash(arg_types.as_ref().iter().copied()); - let hash = combine_hashes(hash_script, hash_params); + let hash = calc_fn_hash_full(hash_script, arg_types.as_ref().iter().copied()); // First check the global namespace and packages, but skip modules that are standard because // they should never conflict with system functions.