A bunch of fixes and improvements
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
2022-09-17 09:38:02 +02:00
parent 7bcfd92d45
commit a4fd112a07
15 changed files with 179 additions and 100 deletions

View File

@@ -1,12 +1,12 @@
use arcstr::ArcStr;
use hashbrown::HashMap;
use parking_lot::RwLock;
use std::borrow::Borrow;
use std::ffi::CStr;
use std::fmt::{Display, Formatter};
use std::hash::{Hash, Hasher};
use std::ops::Deref;
use std::sync::{Arc, Mutex, Weak};
use conquer_once::OnceCell;
use hashbrown::HashMap;
use std::sync::LazyLock;
/// 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
@@ -16,16 +16,16 @@ use hashbrown::HashMap;
#[cfg_attr(feature = "wasm", derive(unique_type_id_derive::UniqueTypeId))]
pub struct StringKey {
/// The underlying reference counted string.
str: Arc<str>,
str: ArcStr,
/// 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: OnceCell<Mutex<HashMap<u32, Weak<str>>>> = OnceCell::uninit();
static STRING_CACHE: LazyLock<RwLock<HashMap<u32, ArcStr>>> = LazyLock::new(|| RwLock::new(HashMap::new()));
/// An empty StringKey
static EMPTY: OnceCell<StringKey> = OnceCell::uninit();
static EMPTY: LazyLock<StringKey> = LazyLock::new(|| StringKey::new(""));
impl StringKey {
/// Gets the hash of a string.
@@ -42,25 +42,29 @@ impl StringKey {
/// 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.get_or_init(|| Mutex::new(HashMap::new())).lock().unwrap();
let cached_value = cache.get(&hash);
if let Some(cached_value) = cached_value {
if let Some(cached_value) = cached_value.upgrade() {
let s: ArcStr = s.into();
let hash = StringKey::get_hash(s.as_str());
{
let cache_read = STRING_CACHE.read();
let cached_value = cache_read.get(&hash);
if let Some(cached_value) = cached_value {
return Self {
str: cached_value,
str: cached_value.clone(),
hash,
};
}
}
let v = Self { str: s.into(), hash };
cache.insert(hash, Arc::downgrade(&v.str));
v
{
let v = Self { str: s.clone(), hash };
let mut cache_write = STRING_CACHE.write();
cache_write.insert(hash, s);
v
}
}
/// Gets the empty StringKey.
pub fn empty() -> Self {
EMPTY.get_or_init(|| StringKey::new("")).clone()
EMPTY.clone()
}
/// Gets the underlying string for the StringKey.
@@ -108,7 +112,7 @@ impl Display for StringKey {
impl Into<StringKey> for &CStr {
fn into(self) -> StringKey {
StringKey::new(self.to_str().unwrap())
StringKey::new(self.to_str().unwrap().into())
}
}
/// Converts a character to lowercased in a const safe way.
@@ -160,7 +164,7 @@ mod tests {
#[test]
fn create_empty_stringkey() {
let sk = StringKey::new("");
let sk = StringKey::new("".into());
assert_eq!(sk.str(), "");
assert_eq!(sk.hash(), 0);
assert_eq!(sk.hash(), StringKey::get_hash(""));
@@ -168,7 +172,7 @@ mod tests {
#[test]
fn create_stringkey_foo() {
let sk = StringKey::new("foo");
let sk = StringKey::new("foo".into());
assert_eq!(sk.str(), "foo");
assert_eq!(sk.hash(), 2356372769);
assert_eq!(sk.hash(), StringKey::get_hash("foo"));
@@ -177,7 +181,7 @@ mod tests {
#[test]
fn create_stringkey_bar() {
let sk = StringKey::new("bar");
let sk = StringKey::new("bar".into());
assert_eq!(sk.str(), "bar");
assert_eq!(sk.hash(), 1996459178);
assert_eq!(sk.hash(), StringKey::get_hash("bar"));