This commit is contained in:
@@ -1,23 +1,30 @@
|
||||
use hashbrown::HashMap;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::lazy::SyncLazy;
|
||||
use std::sync::{Arc, Mutex, Weak};
|
||||
|
||||
use hashbrown::HashMap;
|
||||
|
||||
/// StringKey is an immutable string that is used for indexing of hashmaps or equality a lot.
|
||||
/// By reference counting the string instead of copying, and caching the hash, we can get some
|
||||
/// free speed out of it. Note that StringKeys also compare case insensitive, so that for example
|
||||
/// `charmander` == `Charmander`.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct StringKey {
|
||||
/// The underlying reference counted string.
|
||||
str: Arc<str>,
|
||||
/// The unique hash of the string.
|
||||
hash: u32,
|
||||
}
|
||||
|
||||
/// A cache of all allocated strings. This allows us to re-use strings that are often used without
|
||||
/// allocation.
|
||||
static STRING_CACHE: SyncLazy<Mutex<HashMap<u32, Weak<str>>>> = SyncLazy::new(|| Mutex::new(HashMap::new()));
|
||||
/// An empty StringKey
|
||||
static EMPTY: SyncLazy<StringKey> = SyncLazy::new(|| StringKey::new(""));
|
||||
|
||||
impl StringKey {
|
||||
/// Calculates the hash of a string key in a const manner.
|
||||
pub const fn get_hash_const<const N: usize>(s: &[u8; N]) -> u32 {
|
||||
let mut crc: u32 = 0xffffffff;
|
||||
|
||||
@@ -29,6 +36,7 @@ impl StringKey {
|
||||
crc ^ 0xffffffff
|
||||
}
|
||||
|
||||
/// Gets the hash of a string.
|
||||
pub fn get_hash(s: &str) -> u32 {
|
||||
let mut crc: u32 = 0xffffffff;
|
||||
for byte in s.bytes() {
|
||||
@@ -37,6 +45,8 @@ impl StringKey {
|
||||
crc ^ 0xffffffff
|
||||
}
|
||||
|
||||
/// Creates a new StringKey. If we can find a value for this StringKey in the cache, we re-use
|
||||
/// that value.
|
||||
pub fn new(s: &str) -> Self {
|
||||
let hash = StringKey::get_hash(s);
|
||||
let mut cache = STRING_CACHE.lock().unwrap();
|
||||
@@ -54,14 +64,17 @@ impl StringKey {
|
||||
v
|
||||
}
|
||||
|
||||
/// Gets the empty StringKey.
|
||||
pub fn empty() -> Self {
|
||||
EMPTY.clone()
|
||||
}
|
||||
|
||||
/// Gets the underlying string for the StringKey.
|
||||
pub fn str(&self) -> &str {
|
||||
&self.str
|
||||
}
|
||||
|
||||
/// Gets the hash of the string value.
|
||||
pub fn hash(&self) -> u32 {
|
||||
self.hash
|
||||
}
|
||||
@@ -93,6 +106,7 @@ impl Display for StringKey {
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a character to lowercased in a const safe way.
|
||||
const fn to_lower(c: u8) -> u8 {
|
||||
if c >= b'A' && c <= b'Z' {
|
||||
return c + (b'a' - b'A');
|
||||
@@ -100,6 +114,7 @@ const fn to_lower(c: u8) -> u8 {
|
||||
c
|
||||
}
|
||||
|
||||
/// A lookup table for use in CRC32 hash.
|
||||
const CRC_TABLE: &[u32] = &[
|
||||
0, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4,
|
||||
0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148,
|
||||
|
||||
Reference in New Issue
Block a user