Merge pull request #636 from quake/quake/StraightHashMap

perf: change BTreeMap to StraightHashMap
This commit is contained in:
Stephen Chung 2022-09-05 21:08:32 +08:00 committed by GitHub
commit 0f4df9c4e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 59 additions and 44 deletions

View File

@ -27,6 +27,7 @@ rhai_codegen = { version = "1.4.1", path = "codegen", default-features = false }
no-std-compat = { version = "0.4", default-features = false, features = ["alloc"], optional = true }
libm = { version = "0.2", default-features = false, optional = true }
hashbrown = { version = "0.12", optional = true }
core-error = { version = "0.0", default-features = false, features = ["alloc"], optional = true }
serde = { version = "1.0", default-features = false, features = ["derive", "alloc"], optional = true }
serde_json = { version = "1.0", default-features = false, features = ["alloc"], optional = true }
@ -63,7 +64,7 @@ debugging = ["internals"] # enable debugging
serde = ["dep:serde", "smartstring/serde", "smallvec/serde"] # implement serde for rhai types
# compiling for no-std
no_std = ["no-std-compat", "num-traits/libm", "core-error", "libm", "ahash/compile-time-rng"]
no_std = ["no-std-compat", "num-traits/libm", "core-error", "libm", "ahash/compile-time-rng", "hashbrown"]
# compiling for WASM
wasm-bindgen = ["instant/wasm-bindgen"]

View File

@ -1,10 +1,10 @@
//! System caches.
use crate::func::CallableFunction;
use crate::func::{CallableFunction, StraightHashMap};
use crate::{Identifier, StaticVec};
use std::marker::PhantomData;
#[cfg(feature = "no_std")]
use std::prelude::v1::*;
use std::{collections::BTreeMap, marker::PhantomData};
/// _(internals)_ An entry in a function resolution cache.
/// Exported under the `internals` feature only.
@ -21,7 +21,7 @@ pub struct FnResolutionCacheEntry {
///
/// [`FnResolutionCacheEntry`] is [`Box`]ed in order to pack as many entries inside a single B-Tree
/// level as possible.
pub type FnResolutionCache = BTreeMap<u64, Option<FnResolutionCacheEntry>>;
pub type FnResolutionCache = StraightHashMap<u64, Option<FnResolutionCacheEntry>>;
/// _(internals)_ A type containing system-wide caches.
/// Exported under the `internals` feature only.
@ -66,7 +66,7 @@ impl Caches<'_> {
#[allow(dead_code)]
#[inline(always)]
pub fn push_fn_resolution_cache(&mut self) {
self.fn_resolution.push(BTreeMap::new());
self.fn_resolution.push(StraightHashMap::default());
}
/// Rewind the function resolution caches stack to a particular size.
#[inline(always)]

View File

@ -11,8 +11,12 @@ use crate::func::{
use crate::types::dynamic::AccessMode;
use crate::{Dynamic, Engine, Module, Position, RhaiResult, RhaiResultOf, Scope, ERR};
#[cfg(feature = "no_std")]
use hashbrown::hash_map::Entry;
#[cfg(not(feature = "no_std"))]
use std::collections::hash_map::Entry;
use std::num::NonZeroUsize;
#[cfg(feature = "no_std")]
use std::prelude::v1::*;
use std::{collections::btree_map::Entry, num::NonZeroUsize};
impl Engine {
/// Search for a module within an imports stack.

View File

@ -7,6 +7,16 @@ use std::{
hash::{BuildHasher, Hash, Hasher},
};
#[cfg(feature = "no_std")]
pub type StraightHashMap<K, V> = hashbrown::HashMap<K, V, StraightHasherBuilder>;
#[cfg(feature = "no_std")]
pub type StraightHashSet<K> = hashbrown::HashSet<K, StraightHasherBuilder>;
#[cfg(not(feature = "no_std"))]
pub type StraightHashMap<K, V> = std::collections::HashMap<K, V, StraightHasherBuilder>;
#[cfg(not(feature = "no_std"))]
pub type StraightHashSet<K> = std::collections::HashSet<K, StraightHasherBuilder>;
/// Dummy hash value to map zeros to. This value can be anything.
///
/// # Notes
@ -30,7 +40,7 @@ pub const ALT_ZERO_HASH: u64 = 42;
///
/// Panics when hashing any data type other than a [`u64`].
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
struct StraightHasher(u64);
pub struct StraightHasher(u64);
impl Hasher for StraightHasher {
#[inline(always)]
@ -38,23 +48,22 @@ impl Hasher for StraightHasher {
self.0
}
#[inline]
fn write(&mut self, bytes: &[u8]) {
assert_eq!(bytes.len(), 8, "StraightHasher can only hash u64 values");
fn write(&mut self, _bytes: &[u8]) {
panic!("StraightHasher can only hash u64 values");
}
let mut key = [0_u8; 8];
key.copy_from_slice(bytes);
self.0 = u64::from_ne_bytes(key);
if self.0 == 0 {
fn write_u64(&mut self, i: u64) {
if i == 0 {
self.0 = ALT_ZERO_HASH;
} else {
self.0 = i;
}
}
}
/// A hash builder for `StraightHasher`.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Default)]
struct StraightHasherBuilder;
pub struct StraightHasherBuilder;
impl BuildHasher for StraightHasherBuilder {
type Hasher = StraightHasher;

View File

@ -21,7 +21,7 @@ pub use callable_function::CallableFunction;
pub use func::Func;
pub use hashing::{
calc_fn_hash, calc_fn_params_hash, calc_qualified_fn_hash, calc_qualified_var_hash,
combine_hashes, get_hasher,
combine_hashes, get_hasher, StraightHashMap, StraightHashSet,
};
pub use native::{
locked_read, locked_write, shared_get_mut, shared_make_mut, shared_take, shared_take_or_clone,

View File

@ -23,6 +23,8 @@ use std::{
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
use crate::func::register::Mut;
use crate::func::{StraightHashMap, StraightHashSet};
/// A type representing the namespace of a function.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[cfg_attr(feature = "metadata", derive(serde::Serialize))]
@ -267,18 +269,18 @@ pub struct Module {
/// [`Module`] variables.
variables: BTreeMap<Identifier, Dynamic>,
/// Flattened collection of all [`Module`] variables, including those in sub-modules.
all_variables: BTreeMap<u64, Dynamic>,
all_variables: StraightHashMap<u64, Dynamic>,
/// Functions (both native Rust and scripted).
functions: BTreeMap<u64, Box<FuncInfo>>,
functions: StraightHashMap<u64, Box<FuncInfo>>,
/// Flattened collection of all functions, native Rust and scripted.
/// including those in sub-modules.
all_functions: BTreeMap<u64, CallableFunction>,
all_functions: StraightHashMap<u64, CallableFunction>,
/// Native Rust functions (in scripted hash format) that contain [`Dynamic`] parameters.
dynamic_functions: BTreeSet<u64>,
dynamic_functions: StraightHashSet<u64>,
/// Iterator functions, keyed by the type producing the iterator.
type_iterators: BTreeMap<TypeId, Shared<IteratorFn>>,
type_iterators: StraightHashMap<TypeId, Shared<IteratorFn>>,
/// Flattened collection of iterator functions, including those in sub-modules.
all_type_iterators: BTreeMap<TypeId, Shared<IteratorFn>>,
all_type_iterators: StraightHashMap<TypeId, Shared<IteratorFn>>,
/// Is the [`Module`] indexed?
indexed: bool,
/// Does the [`Module`] contain indexed functions that have been exposed to the global namespace?
@ -372,12 +374,12 @@ impl Module {
custom_types: CustomTypesCollection::new(),
modules: BTreeMap::new(),
variables: BTreeMap::new(),
all_variables: BTreeMap::new(),
functions: BTreeMap::new(),
all_functions: BTreeMap::new(),
dynamic_functions: BTreeSet::new(),
type_iterators: BTreeMap::new(),
all_type_iterators: BTreeMap::new(),
all_variables: StraightHashMap::default(),
functions: StraightHashMap::default(),
all_functions: StraightHashMap::default(),
dynamic_functions: StraightHashSet::default(),
type_iterators: StraightHashMap::default(),
all_type_iterators: StraightHashMap::default(),
indexed: true,
contains_indexed_global_functions: false,
}
@ -2137,9 +2139,9 @@ impl Module {
fn index_module<'a>(
module: &'a Module,
path: &mut Vec<&'a str>,
variables: &mut BTreeMap<u64, Dynamic>,
functions: &mut BTreeMap<u64, CallableFunction>,
type_iterators: &mut BTreeMap<TypeId, Shared<IteratorFn>>,
variables: &mut StraightHashMap<u64, Dynamic>,
functions: &mut StraightHashMap<u64, CallableFunction>,
type_iterators: &mut StraightHashMap<TypeId, Shared<IteratorFn>>,
) -> bool {
let mut contains_indexed_global_functions = false;
@ -2201,9 +2203,9 @@ impl Module {
if !self.indexed {
let mut path = Vec::with_capacity(4);
let mut variables = BTreeMap::new();
let mut functions = BTreeMap::new();
let mut type_iterators = BTreeMap::new();
let mut variables = StraightHashMap::default();
let mut functions = StraightHashMap::default();
let mut type_iterators = StraightHashMap::default();
path.push("");

View File

@ -9,7 +9,7 @@ use crate::ast::{
};
use crate::engine::{Precedence, KEYWORD_THIS, OP_CONTAINS};
use crate::eval::GlobalRuntimeState;
use crate::func::hashing::get_hasher;
use crate::func::{hashing::get_hasher, StraightHashMap};
use crate::tokenizer::{
is_keyword_function, is_valid_function_name, is_valid_identifier, Token, TokenStream,
TokenizerControl,
@ -32,7 +32,7 @@ use std::{
pub type ParseResult<T> = Result<T, ParseError>;
type FnLib = BTreeMap<u64, Shared<ScriptFnDef>>;
type FnLib = StraightHashMap<u64, Shared<ScriptFnDef>>;
const KEYWORD_SEMICOLON: &str = Token::SemiColon.literal_syntax();
@ -3790,7 +3790,7 @@ impl Engine {
state: &mut ParseState,
_optimization_level: OptimizationLevel,
) -> ParseResult<AST> {
let mut functions = BTreeMap::new();
let mut functions = StraightHashMap::default();
let mut options = self.options;
options.remove(LangOptions::STMT_EXPR);
@ -3850,7 +3850,7 @@ impl Engine {
state: &mut ParseState,
) -> ParseResult<(StmtBlockContainer, StaticVec<Shared<ScriptFnDef>>)> {
let mut statements = StmtBlockContainer::new_const();
let mut functions = BTreeMap::new();
let mut functions = StraightHashMap::default();
while !input.peek().expect(NEVER_ENDS).0.is_eof() {
let settings = ParseSettings {

View File

@ -1,10 +1,9 @@
use crate::func::hashing::get_hasher;
use crate::func::{hashing::get_hasher, StraightHashMap};
use crate::ImmutableString;
#[cfg(feature = "no_std")]
use std::prelude::v1::*;
use std::{
collections::BTreeMap,
fmt,
hash::{Hash, Hasher},
marker::PhantomData,
@ -21,14 +20,14 @@ pub const MAX_STRING_LEN: usize = 24;
/// Exported under the `internals` feature only.
///
/// Normal identifiers, property getters and setters are interned separately.
#[derive(Clone, Hash)]
#[derive(Clone)]
pub struct StringsInterner<'a> {
/// Maximum number of strings interned.
pub capacity: usize,
/// Maximum string length.
pub max_string_len: usize,
/// Normal strings.
strings: BTreeMap<u64, ImmutableString>,
strings: StraightHashMap<u64, ImmutableString>,
/// Take care of the lifetime parameter.
dummy: PhantomData<&'a ()>,
}
@ -55,7 +54,7 @@ impl StringsInterner<'_> {
Self {
capacity: MAX_INTERNED_STRINGS,
max_string_len: MAX_STRING_LEN,
strings: BTreeMap::new(),
strings: StraightHashMap::default(),
dummy: PhantomData,
}
}