use std::sync::OnceLock;
use gxhash::GxBuildHasher;
static SEED: OnceLock<i64> = OnceLock::new();
#[inline]
fn seed() -> i64 {
*SEED.get_or_init(|| fastrand::i64(..))
}
#[cfg(feature = "map")]
pub type ConcurrentMap<K, V> = papaya::HashMap<K, V, GxBuildHasher>;
#[cfg(feature = "map")]
#[inline]
pub fn new_concurrent_map<K, V>() -> ConcurrentMap<K, V> {
papaya::HashMap::builder()
.hasher(GxBuildHasher::with_seed(seed()))
.build()
}
#[cfg(feature = "set")]
pub type ConcurrentSet<K> = papaya::HashSet<K, GxBuildHasher>;
#[cfg(feature = "set")]
#[inline]
pub fn new_concurrent_set<K>() -> ConcurrentSet<K> {
papaya::HashSet::builder()
.hasher(GxBuildHasher::with_seed(seed()))
.build()
}
#[cfg(test)]
mod tests {
#[cfg(any(feature = "map", feature = "set"))]
#[test]
fn test_seed_randomized() {
assert_ne!(super::seed(), 42);
}
#[cfg(any(feature = "map", feature = "set"))]
#[test]
fn test_seed_shared_across_tables() {
let first = super::seed();
let _map = super::new_concurrent_map::<u64, u64>();
let _set = super::new_concurrent_set::<u64>();
assert_eq!(super::SEED.get(), Some(&first));
}
#[cfg(feature = "map")]
#[test]
fn test_map() {
let map = super::new_concurrent_map();
let pin = map.pin();
assert!(pin.is_empty());
pin.insert("a", 1);
assert_eq!(pin.get("a"), Some(&1));
assert_eq!(pin.len(), 1);
assert_eq!(pin.remove(&"a"), Some(&1));
assert!(pin.is_empty());
}
#[cfg(feature = "set")]
#[test]
fn test_set() {
let set = super::new_concurrent_set();
let pin = set.pin();
assert!(pin.is_empty());
pin.insert("a");
assert!(pin.contains("a"));
assert_eq!(pin.len(), 1);
assert!(!pin.is_empty());
assert!(pin.remove(&"a"));
assert!(pin.is_empty());
}
}