Skip to content

Commit

Permalink
Only hash keys once, taking advantage of hashbrown raw entry api (#259)
Browse files Browse the repository at this point in the history
  • Loading branch information
arthurprs authored Aug 21, 2023
1 parent ea4ea24 commit 3448b6f
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 67 deletions.
104 changes: 54 additions & 50 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ use core::fmt;
use core::hash::{BuildHasher, Hash, Hasher};
use core::iter::FromIterator;
use core::ops::{BitAnd, BitOr, Shl, Shr, Sub};
use hashbrown::hash_map::RawEntryMut;
use iter::{Iter, IterMut, OwningIter};
use mapref::entry::{Entry, OccupiedEntry, VacantEntry};
use mapref::multiple::RefMulti;
Expand Down Expand Up @@ -295,11 +296,15 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap<K, V, S> {
/// Hash a given item to produce a usize.
/// Uses the provided or default HashBuilder.
pub fn hash_usize<T: Hash>(&self, item: &T) -> usize {
self.hash_u64(item) as usize
}

fn hash_u64<T: Hash>(&self, item: &T) -> u64 {
let mut hasher = self.hasher.build_hasher();

item.hash(&mut hasher);

hasher.finish() as usize
hasher.finish()
}

cfg_if! {
Expand Down Expand Up @@ -916,9 +921,9 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
}

fn _insert(&self, key: K, value: V) -> Option<V> {
let hash = self.hash_usize(&key);
let hash = self.hash_u64(&key);

let idx = self.determine_shard(hash);
let idx = self.determine_shard(hash as usize);

let mut shard = unsafe { self._yield_write_shard(idx) };

Expand All @@ -932,9 +937,9 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
let hash = self.hash_usize(&key);
let hash = self.hash_u64(&key);

let idx = self.determine_shard(hash);
let idx = self.determine_shard(hash as usize);

let mut shard = unsafe { self._yield_write_shard(idx) };

Expand All @@ -946,22 +951,20 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
let hash = self.hash_usize(&key);
let hash = self.hash_u64(&key);

let idx = self.determine_shard(hash);
let idx = self.determine_shard(hash as usize);

let mut shard = unsafe { self._yield_write_shard(idx) };

if let Some((kptr, vptr)) = shard.get_key_value(key) {
unsafe {
let kptr: *const K = kptr;
let vptr: *mut V = vptr.as_ptr();

if f(&*kptr, &mut *vptr) {
shard.remove_entry(key).map(|(k, v)| (k, v.into_inner()))
} else {
None
}
if let RawEntryMut::Occupied(entry) =
shard.raw_entry_mut().from_key_hashed_nocheck(hash, key)
{
if f(&entry.key(), &entry.get().get()) {
let (k, v) = entry.remove_entry();
Some((k, v.into_inner()))
} else {
None
}
} else {
None
Expand All @@ -973,22 +976,21 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
let hash = self.hash_usize(&key);
let hash = self.hash_u64(&key);

let idx = self.determine_shard(hash);
let idx = self.determine_shard(hash as usize);

let mut shard = unsafe { self._yield_write_shard(idx) };

if let Some((kptr, vptr)) = shard.get_key_value(key) {
unsafe {
let kptr: *const K = kptr;
let vptr: *mut V = vptr.as_ptr();

if f(&*kptr, &mut *vptr) {
shard.remove_entry(key).map(|(k, v)| (k, v.into_inner()))
} else {
None
}
if let RawEntryMut::Occupied(mut entry) =
shard.raw_entry_mut().from_key_hashed_nocheck(hash, key)
{
let (k, v) = entry.get_key_value_mut();
if f(k, v.get_mut()) {
let (k, v) = entry.remove_entry();
Some((k, v.into_inner()))
} else {
None
}
} else {
None
Expand All @@ -1008,13 +1010,13 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
let hash = self.hash_usize(&key);
let hash = self.hash_u64(&key);

let idx = self.determine_shard(hash);
let idx = self.determine_shard(hash as usize);

let shard = unsafe { self._yield_read_shard(idx) };

if let Some((kptr, vptr)) = shard.get_key_value(key) {
if let Some((kptr, vptr)) = shard.raw_entry().from_key_hashed_nocheck(hash, key) {
unsafe {
let kptr: *const K = kptr;
let vptr: *const V = vptr.get();
Expand All @@ -1030,16 +1032,18 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
let hash = self.hash_usize(&key);
let hash = self.hash_u64(&key);

let idx = self.determine_shard(hash);
let idx = self.determine_shard(hash as usize);

let shard = unsafe { self._yield_write_shard(idx) };
let mut shard = unsafe { self._yield_write_shard(idx) };

if let Some((kptr, vptr)) = shard.get_key_value(key) {
if let RawEntryMut::Occupied(mut entry) =
shard.raw_entry_mut().from_key_hashed_nocheck(hash, key)
{
unsafe {
let kptr: *const K = kptr;
let vptr: *mut V = vptr.as_ptr();
let kptr: *const K = entry.key();
let vptr: *mut V = entry.get_mut().as_ptr();
Some(RefMut::new(shard, kptr, vptr))
}
} else {
Expand All @@ -1052,16 +1056,16 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
let hash = self.hash_usize(&key);
let hash = self.hash_u64(&key);

let idx = self.determine_shard(hash);
let idx = self.determine_shard(hash as usize);

let shard = match unsafe { self._try_yield_read_shard(idx) } {
Some(shard) => shard,
None => return TryResult::Locked,
};

if let Some((kptr, vptr)) = shard.get_key_value(key) {
if let Some((kptr, vptr)) = shard.raw_entry().from_key_hashed_nocheck(hash, key) {
unsafe {
let kptr: *const K = kptr;
let vptr: *const V = vptr.get();
Expand All @@ -1077,16 +1081,16 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
let hash = self.hash_usize(&key);
let hash = self.hash_u64(&key);

let idx = self.determine_shard(hash);
let idx = self.determine_shard(hash as usize);

let shard = match unsafe { self._try_yield_write_shard(idx) } {
Some(shard) => shard,
None => return TryResult::Locked,
};

if let Some((kptr, vptr)) = shard.get_key_value(key) {
if let Some((kptr, vptr)) = shard.raw_entry().from_key_hashed_nocheck(hash, key) {
unsafe {
let kptr: *const K = kptr;
let vptr: *mut V = vptr.as_ptr();
Expand Down Expand Up @@ -1145,13 +1149,13 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
}

fn _entry(&'a self, key: K) -> Entry<'a, K, V, S> {
let hash = self.hash_usize(&key);
let hash = self.hash_u64(&key);

let idx = self.determine_shard(hash);
let idx = self.determine_shard(hash as usize);

let shard = unsafe { self._yield_write_shard(idx) };

if let Some((kptr, vptr)) = shard.get_key_value(&key) {
if let Some((kptr, vptr)) = shard.raw_entry().from_key_hashed_nocheck(hash, &key) {
unsafe {
let kptr: *const K = kptr;
let vptr: *mut V = vptr.as_ptr();
Expand All @@ -1163,16 +1167,16 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
}

fn _try_entry(&'a self, key: K) -> Option<Entry<'a, K, V, S>> {
let hash = self.hash_usize(&key);
let hash = self.hash_u64(&key);

let idx = self.determine_shard(hash);
let idx = self.determine_shard(hash as usize);

let shard = match unsafe { self._try_yield_write_shard(idx) } {
Some(shard) => shard,
None => return None,
};

if let Some((kptr, vptr)) = shard.get_key_value(&key) {
if let Some((kptr, vptr)) = shard.raw_entry().from_key_hashed_nocheck(hash, &key) {
unsafe {
let kptr: *const K = kptr;
let vptr: *mut V = vptr.as_ptr();
Expand Down
25 changes: 8 additions & 17 deletions src/read_only.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,7 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> ReadOnlyView<K, V, S>
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
let hash = self.map.hash_usize(&key);

let idx = self.map.determine_shard(hash);

let shard = unsafe { self.map._get_read_shard(idx) };

shard.contains_key(key)
self.get(key).is_some()
}

/// Returns a reference to the value corresponding to the key.
Expand All @@ -76,13 +70,7 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> ReadOnlyView<K, V, S>
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
let hash = self.map.hash_usize(&key);

let idx = self.map.determine_shard(hash);

let shard = unsafe { self.map._get_read_shard(idx) };

shard.get(key).map(|v| v.get())
self.get_key_value(key).map(|(_k, v)| v)
}

/// Returns the key-value pair corresponding to the supplied key.
Expand All @@ -91,13 +79,16 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> ReadOnlyView<K, V, S>
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
let hash = self.map.hash_usize(&key);
let hash = self.map.hash_u64(&key);

let idx = self.map.determine_shard(hash);
let idx = self.map.determine_shard(hash as usize);

let shard = unsafe { self.map._get_read_shard(idx) };

shard.get_key_value(key).map(|(k, v)| (k, v.get()))
shard
.raw_entry()
.from_key_hashed_nocheck(hash, key)
.map(|(k, v)| (k, v.get()))
}

fn shard_read_iter(&'a self) -> impl Iterator<Item = &'a HashMap<K, V, S>> + 'a {
Expand Down

0 comments on commit 3448b6f

Please sign in to comment.