#![doc = include_str!("../README.md")]
use core::fmt;
use core::hash::{BuildHasher, BuildHasherDefault, Hash};
use core::ops::{Deref, DerefMut};
pub use axhash_core::{AxBuildHasher, AxHasher};
pub use dashmap::DashMap as RawDashMap;
pub use dashmap::DashSet as RawDashSet;
pub use dashmap::Entry as DashEntry;
pub use dashmap::OccupiedEntry as DashOccupiedEntry;
pub use dashmap::VacantEntry as DashVacantEntry;
pub type DashMap<K, V> = RawDashMap<K, V, BuildHasherDefault<AxHasher>>;
pub type DashSet<T> = RawDashSet<T, BuildHasherDefault<AxHasher>>;
pub struct AxDashMap<K, V, S = BuildHasherDefault<AxHasher>>(RawDashMap<K, V, S>);
impl<K, V> AxDashMap<K, V, BuildHasherDefault<AxHasher>>
where
K: Hash + Eq,
{
#[inline(always)]
pub fn new() -> Self {
Self(RawDashMap::with_hasher(BuildHasherDefault::default()))
}
#[inline(always)]
pub fn with_capacity(capacity: usize) -> Self {
Self(RawDashMap::with_capacity_and_hasher(
capacity,
BuildHasherDefault::default(),
))
}
#[inline(always)]
pub fn with_shard_amount(shard_amount: usize) -> Self {
Self(RawDashMap::with_hasher_and_shard_amount(
BuildHasherDefault::default(),
shard_amount,
))
}
#[inline(always)]
pub fn with_capacity_and_shard_amount(capacity: usize, shard_amount: usize) -> Self {
Self(RawDashMap::with_capacity_and_hasher_and_shard_amount(
capacity,
BuildHasherDefault::default(),
shard_amount,
))
}
}
impl<K, V, S> AxDashMap<K, V, S>
where
K: Hash + Eq,
S: BuildHasher + Clone,
{
#[inline(always)]
pub fn with_hasher(hasher: S) -> Self {
Self(RawDashMap::with_hasher(hasher))
}
#[inline(always)]
pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> Self {
Self(RawDashMap::with_capacity_and_hasher(capacity, hasher))
}
#[inline(always)]
pub fn with_hasher_and_shard_amount(hasher: S, shard_amount: usize) -> Self {
Self(RawDashMap::with_hasher_and_shard_amount(
hasher,
shard_amount,
))
}
#[inline(always)]
pub fn with_capacity_and_hasher_and_shard_amount(
capacity: usize,
hasher: S,
shard_amount: usize,
) -> Self {
Self(RawDashMap::with_capacity_and_hasher_and_shard_amount(
capacity,
hasher,
shard_amount,
))
}
#[inline(always)]
pub fn into_inner(self) -> RawDashMap<K, V, S> {
self.0
}
}
impl<K, V, S> Deref for AxDashMap<K, V, S> {
type Target = RawDashMap<K, V, S>;
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<K, V, S> DerefMut for AxDashMap<K, V, S> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<K, V> Default for AxDashMap<K, V, BuildHasherDefault<AxHasher>>
where
K: Hash + Eq,
{
#[inline(always)]
fn default() -> Self {
Self::new()
}
}
impl<K, V, S> fmt::Debug for AxDashMap<K, V, S>
where
K: Hash + Eq + fmt::Debug,
V: fmt::Debug,
S: BuildHasher + Clone,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl<K, V> FromIterator<(K, V)> for AxDashMap<K, V, BuildHasherDefault<AxHasher>>
where
K: Hash + Eq,
{
fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
let iter = iter.into_iter();
let (lower, _) = iter.size_hint();
let map = Self::with_capacity(lower);
iter.for_each(|(k, v)| {
map.insert(k, v);
});
map
}
}
impl<K, V, S> Extend<(K, V)> for AxDashMap<K, V, S>
where
K: Hash + Eq,
S: BuildHasher + Clone,
{
#[inline]
fn extend<I: IntoIterator<Item = (K, V)>>(&mut self, iter: I) {
iter.into_iter().for_each(|(k, v)| {
self.0.insert(k, v);
});
}
}
impl<K, V, S> From<RawDashMap<K, V, S>> for AxDashMap<K, V, S> {
#[inline(always)]
fn from(inner: RawDashMap<K, V, S>) -> Self {
Self(inner)
}
}
impl<K, V, S> From<AxDashMap<K, V, S>> for RawDashMap<K, V, S> {
#[inline(always)]
fn from(wrapper: AxDashMap<K, V, S>) -> Self {
wrapper.0
}
}
pub struct AxDashSet<T, S = BuildHasherDefault<AxHasher>>(RawDashSet<T, S>);
impl<T> AxDashSet<T, BuildHasherDefault<AxHasher>>
where
T: Hash + Eq,
{
#[inline(always)]
pub fn new() -> Self {
Self(RawDashSet::with_hasher(BuildHasherDefault::default()))
}
#[inline(always)]
pub fn with_capacity(capacity: usize) -> Self {
Self(RawDashSet::with_capacity_and_hasher(
capacity,
BuildHasherDefault::default(),
))
}
}
impl<T, S> AxDashSet<T, S>
where
T: Hash + Eq,
S: BuildHasher + Clone,
{
#[inline(always)]
pub fn with_hasher(hasher: S) -> Self {
Self(RawDashSet::with_hasher(hasher))
}
#[inline(always)]
pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> Self {
Self(RawDashSet::with_capacity_and_hasher(capacity, hasher))
}
#[inline(always)]
pub fn into_inner(self) -> RawDashSet<T, S> {
self.0
}
}
impl<T, S> Deref for AxDashSet<T, S> {
type Target = RawDashSet<T, S>;
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T, S> DerefMut for AxDashSet<T, S> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<T> Default for AxDashSet<T, BuildHasherDefault<AxHasher>>
where
T: Hash + Eq,
{
#[inline(always)]
fn default() -> Self {
Self::new()
}
}
impl<T, S> fmt::Debug for AxDashSet<T, S>
where
T: Hash + Eq + fmt::Debug,
S: BuildHasher + Clone,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl<T> FromIterator<T> for AxDashSet<T, BuildHasherDefault<AxHasher>>
where
T: Hash + Eq,
{
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
let iter = iter.into_iter();
let (lower, _) = iter.size_hint();
let set = Self::with_capacity(lower);
iter.for_each(|v| {
set.insert(v);
});
set
}
}
impl<T, S> Extend<T> for AxDashSet<T, S>
where
T: Hash + Eq,
S: BuildHasher + Clone,
{
#[inline]
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
iter.into_iter().for_each(|v| {
self.0.insert(v);
});
}
}
impl<T, S> From<RawDashSet<T, S>> for AxDashSet<T, S> {
#[inline(always)]
fn from(inner: RawDashSet<T, S>) -> Self {
Self(inner)
}
}
impl<T, S> From<AxDashSet<T, S>> for RawDashSet<T, S> {
#[inline(always)]
fn from(wrapper: AxDashSet<T, S>) -> Self {
wrapper.0
}
}
#[cfg(test)]
mod tests {
use super::*;
use core::hash::BuildHasherDefault;
#[test]
fn map_basic_operations() {
let map: AxDashMap<&str, u32> = AxDashMap::new();
assert!(map.is_empty());
map.insert("one", 1);
map.insert("two", 2);
map.insert("three", 3);
assert_eq!(map.len(), 3);
assert_eq!(*map.get("one").unwrap(), 1);
assert!(map.get("missing").is_none());
map.remove("two");
assert_eq!(map.len(), 2);
}
#[test]
fn map_with_capacity() {
let map: AxDashMap<u32, u32> = AxDashMap::with_capacity(1024);
assert!(map.is_empty());
}
#[test]
fn map_with_shard_amount() {
let map: AxDashMap<u32, u32> = AxDashMap::with_shard_amount(16);
map.insert(1, 10);
assert_eq!(*map.get(&1).unwrap(), 10);
}
#[test]
fn map_with_capacity_and_shard_amount() {
let map: AxDashMap<u32, u32> = AxDashMap::with_capacity_and_shard_amount(512, 8);
assert!(map.is_empty());
}
#[test]
fn map_default() {
let map: AxDashMap<u64, u64> = AxDashMap::default();
assert!(map.is_empty());
}
#[test]
fn map_seeded_hasher() {
let seed: u64 = 0xc0ffee_deadbeef;
let map: AxDashMap<&str, i32, AxBuildHasher> =
AxDashMap::with_hasher(AxBuildHasher::with_seed(seed));
map.insert("seeded", -1);
assert_eq!(*map.get("seeded").unwrap(), -1);
}
#[test]
fn map_entry_api() {
let map: AxDashMap<&str, u32> = AxDashMap::new();
for _ in 0..5 {
map.entry("counter").and_modify(|n| *n += 1).or_insert(0);
}
assert_eq!(*map.get("counter").unwrap(), 4);
}
#[test]
fn map_from_iterator() {
let map: AxDashMap<&str, u32> = [("a", 1u32), ("b", 2), ("c", 3)].into_iter().collect();
assert_eq!(map.len(), 3);
assert_eq!(*map.get("b").unwrap(), 2);
}
#[test]
fn map_extend() {
let mut map: AxDashMap<u32, u32> = AxDashMap::new();
map.extend([(1u32, 10), (2, 20), (3, 30)]);
assert_eq!(map.len(), 3);
assert_eq!(*map.get(&2u32).unwrap(), 20);
}
#[test]
fn map_iter() {
let map: AxDashMap<u32, u32> = [(1u32, 10), (2, 20), (3, 30)].into_iter().collect();
let sum: u32 = map.iter().map(|r| *r.value()).sum();
assert_eq!(sum, 60);
}
#[test]
fn map_alter() {
let map: AxDashMap<u32, u32> = [(1u32, 1), (2, 2), (3, 3)].into_iter().collect();
map.alter_all(|_, v| v * 10);
assert_eq!(*map.get(&1u32).unwrap(), 10);
assert_eq!(*map.get(&3u32).unwrap(), 30);
}
#[test]
fn map_retain() {
let map: AxDashMap<u32, u32> = (0u32..10).map(|i| (i, i * i)).collect();
map.retain(|_, v| *v > 25);
assert!(map.iter().all(|r| *r.value() > 25));
}
#[test]
fn map_into_read_only() {
let map: AxDashMap<&str, u32> = AxDashMap::new();
map.insert("ro", 99);
let ro = map.into_inner().into_read_only();
assert_eq!(*ro.get("ro").unwrap(), 99);
}
#[test]
fn map_into_inner_roundtrip() {
let map: AxDashMap<&str, i32> = AxDashMap::new();
map.insert("x", 99);
let raw: RawDashMap<&str, i32, BuildHasherDefault<AxHasher>> = map.into_inner();
assert_eq!(*raw.get("x").unwrap(), 99);
let wrapped: AxDashMap<&str, i32> = raw.into();
assert_eq!(*wrapped.get("x").unwrap(), 99);
}
#[test]
fn map_concurrent_insert() {
use std::sync::Arc;
let map: Arc<AxDashMap<u32, u32>> = Arc::new(AxDashMap::with_capacity(1_000));
let handles: Vec<_> = (0..8)
.map(|t| {
let m = Arc::clone(&map);
std::thread::spawn(move || {
for i in 0u32..125 {
m.insert(t * 125 + i, i);
}
})
})
.collect();
for h in handles {
h.join().unwrap();
}
assert_eq!(map.len(), 1_000);
}
#[test]
fn alias_dashmap_basic() {
let map: DashMap<&str, u32> = dashmap::DashMap::with_hasher(BuildHasherDefault::default());
map.insert("hello", 42);
assert_eq!(*map.get("hello").unwrap(), 42);
}
#[test]
fn set_basic_operations() {
let set: AxDashSet<u32> = AxDashSet::new();
assert!(set.is_empty());
set.insert(1);
set.insert(2);
set.insert(2); set.insert(3);
assert_eq!(set.len(), 3);
assert!(set.contains(&1));
assert!(!set.contains(&99));
set.remove(&2);
assert_eq!(set.len(), 2);
}
#[test]
fn set_default() {
let set: AxDashSet<u64> = AxDashSet::default();
assert!(set.is_empty());
}
#[test]
fn set_from_iterator() {
let set: AxDashSet<u32> = [1u32, 2, 3, 2, 1].into_iter().collect();
assert_eq!(set.len(), 3);
}
#[test]
fn set_extend() {
let mut set: AxDashSet<u32> = AxDashSet::new();
set.extend([1u32, 2, 3]);
set.extend([3u32, 4, 5]);
assert_eq!(set.len(), 5);
}
#[test]
fn set_iter() {
let set: AxDashSet<u32> = [1u32, 2, 3].into_iter().collect();
let sum: u32 = set.iter().map(|r| *r).sum();
assert_eq!(sum, 6);
}
#[test]
fn set_into_inner_roundtrip() {
let set: AxDashSet<i32> = AxDashSet::new();
set.insert(42);
let raw: RawDashSet<i32, BuildHasherDefault<AxHasher>> = set.into_inner();
assert!(raw.contains(&42));
let wrapped: AxDashSet<i32> = raw.into();
assert!(wrapped.contains(&42));
}
#[test]
fn set_concurrent_insert() {
use std::sync::Arc;
let set: Arc<AxDashSet<u32>> = Arc::new(AxDashSet::with_capacity(1_000));
let handles: Vec<_> = (0..8)
.map(|t| {
let s = Arc::clone(&set);
std::thread::spawn(move || {
for i in 0u32..125 {
s.insert(t * 125 + i);
}
})
})
.collect();
for h in handles {
h.join().unwrap();
}
assert_eq!(set.len(), 1_000);
}
#[test]
fn alias_dashset_basic() {
let set: DashSet<u32> = dashmap::DashSet::with_hasher(BuildHasherDefault::default());
set.insert(1);
set.insert(2);
set.insert(2);
assert_eq!(set.len(), 2);
}
}