Use hashing for strings interner.

This commit is contained in:
Stephen Chung 2022-08-12 10:34:09 +08:00
parent ac1f661ab0
commit 8bbb382d9c

View File

@ -1,7 +1,14 @@
use crate::func::hashing::get_hasher;
use crate::{Identifier, ImmutableString}; use crate::{Identifier, ImmutableString};
#[cfg(feature = "no_std")] #[cfg(feature = "no_std")]
use std::prelude::v1::*; use std::prelude::v1::*;
use std::{collections::BTreeMap, marker::PhantomData, ops::AddAssign}; use std::{
collections::BTreeMap,
hash::{Hash, Hasher},
marker::PhantomData,
ops::AddAssign,
};
/// _(internals)_ A factory of identifiers from text strings. /// _(internals)_ A factory of identifiers from text strings.
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
@ -10,13 +17,13 @@ use std::{collections::BTreeMap, marker::PhantomData, ops::AddAssign};
#[derive(Debug, Clone, Default, Hash)] #[derive(Debug, Clone, Default, Hash)]
pub struct StringsInterner<'a> { pub struct StringsInterner<'a> {
/// Normal strings. /// Normal strings.
strings: BTreeMap<Identifier, ImmutableString>, strings: BTreeMap<u64, ImmutableString>,
/// Property getters. /// Property getters.
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
getters: BTreeMap<Identifier, ImmutableString>, getters: BTreeMap<u64, ImmutableString>,
/// Property setters. /// Property setters.
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
setters: BTreeMap<Identifier, ImmutableString>, setters: BTreeMap<u64, ImmutableString>,
/// Take care of the lifetime parameter. /// Take care of the lifetime parameter.
dummy: PhantomData<&'a ()>, dummy: PhantomData<&'a ()>,
} }
@ -35,12 +42,14 @@ impl StringsInterner<'_> {
dummy: PhantomData, dummy: PhantomData,
} }
} }
/// Get an identifier from a text string and prefix, adding it to the interner if necessary. /// Get an identifier from a text string and prefix, adding it to the interner if necessary.
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn get(&mut self, text: impl AsRef<str>) -> ImmutableString { pub fn get(&mut self, text: impl AsRef<str>) -> ImmutableString {
self.get_with_prefix("", text) self.get_with_prefix("", text)
} }
/// Get an identifier from a text string and prefix, adding it to the interner if necessary. /// Get an identifier from a text string and prefix, adding it to the interner if necessary.
/// ///
/// # Prefix /// # Prefix
@ -75,14 +84,40 @@ impl StringsInterner<'_> {
_ => unreachable!("unsupported prefix {}", prefix), _ => unreachable!("unsupported prefix {}", prefix),
}; };
if !dict.is_empty() && dict.contains_key(text) { let hasher = &mut get_hasher();
dict.get(text).unwrap().clone() text.hash(hasher);
let key = hasher.finish();
if !dict.is_empty() && dict.contains_key(&key) {
dict.get(&key).unwrap().clone()
} else { } else {
let value: ImmutableString = mapper(text).into(); let value: ImmutableString = mapper(text).into();
dict.insert(text.into(), value.clone()); dict.insert(key, value.clone());
value value
} }
} }
/// Number of strings interned.
#[inline(always)]
#[must_use]
pub fn len(&self) -> usize {
#[cfg(not(feature = "no_object"))]
return self.strings.len() + self.getters.len() + self.setters.len();
#[cfg(feature = "no_object")]
return self.strings.len();
}
/// Number of strings interned.
#[inline(always)]
#[must_use]
pub fn is_empty(&self) -> bool {
#[cfg(not(feature = "no_object"))]
return self.strings.is_empty() || self.getters.is_empty() || self.setters.is_empty();
#[cfg(feature = "no_object")]
return self.strings.is_empty();
}
} }
impl AddAssign<Self> for StringsInterner<'_> { impl AddAssign<Self> for StringsInterner<'_> {