Skip to content

Commit 3448b6f

Browse files
authored
Only hash keys once, taking advantage of hashbrown raw entry api (xacrimon#259)
1 parent ea4ea24 commit 3448b6f

File tree

2 files changed

+62
-67
lines changed

2 files changed

+62
-67
lines changed

src/lib.rs

+54-50
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ use core::fmt;
3434
use core::hash::{BuildHasher, Hash, Hasher};
3535
use core::iter::FromIterator;
3636
use core::ops::{BitAnd, BitOr, Shl, Shr, Sub};
37+
use hashbrown::hash_map::RawEntryMut;
3738
use iter::{Iter, IterMut, OwningIter};
3839
use mapref::entry::{Entry, OccupiedEntry, VacantEntry};
3940
use mapref::multiple::RefMulti;
@@ -295,11 +296,15 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap<K, V, S> {
295296
/// Hash a given item to produce a usize.
296297
/// Uses the provided or default HashBuilder.
297298
pub fn hash_usize<T: Hash>(&self, item: &T) -> usize {
299+
self.hash_u64(item) as usize
300+
}
301+
302+
fn hash_u64<T: Hash>(&self, item: &T) -> u64 {
298303
let mut hasher = self.hasher.build_hasher();
299304

300305
item.hash(&mut hasher);
301306

302-
hasher.finish() as usize
307+
hasher.finish()
303308
}
304309

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

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

921-
let idx = self.determine_shard(hash);
926+
let idx = self.determine_shard(hash as usize);
922927

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

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

937-
let idx = self.determine_shard(hash);
942+
let idx = self.determine_shard(hash as usize);
938943

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

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

951-
let idx = self.determine_shard(hash);
956+
let idx = self.determine_shard(hash as usize);
952957

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

955-
if let Some((kptr, vptr)) = shard.get_key_value(key) {
956-
unsafe {
957-
let kptr: *const K = kptr;
958-
let vptr: *mut V = vptr.as_ptr();
959-
960-
if f(&*kptr, &mut *vptr) {
961-
shard.remove_entry(key).map(|(k, v)| (k, v.into_inner()))
962-
} else {
963-
None
964-
}
960+
if let RawEntryMut::Occupied(entry) =
961+
shard.raw_entry_mut().from_key_hashed_nocheck(hash, key)
962+
{
963+
if f(&entry.key(), &entry.get().get()) {
964+
let (k, v) = entry.remove_entry();
965+
Some((k, v.into_inner()))
966+
} else {
967+
None
965968
}
966969
} else {
967970
None
@@ -973,22 +976,21 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
973976
K: Borrow<Q>,
974977
Q: Hash + Eq + ?Sized,
975978
{
976-
let hash = self.hash_usize(&key);
979+
let hash = self.hash_u64(&key);
977980

978-
let idx = self.determine_shard(hash);
981+
let idx = self.determine_shard(hash as usize);
979982

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

982-
if let Some((kptr, vptr)) = shard.get_key_value(key) {
983-
unsafe {
984-
let kptr: *const K = kptr;
985-
let vptr: *mut V = vptr.as_ptr();
986-
987-
if f(&*kptr, &mut *vptr) {
988-
shard.remove_entry(key).map(|(k, v)| (k, v.into_inner()))
989-
} else {
990-
None
991-
}
985+
if let RawEntryMut::Occupied(mut entry) =
986+
shard.raw_entry_mut().from_key_hashed_nocheck(hash, key)
987+
{
988+
let (k, v) = entry.get_key_value_mut();
989+
if f(k, v.get_mut()) {
990+
let (k, v) = entry.remove_entry();
991+
Some((k, v.into_inner()))
992+
} else {
993+
None
992994
}
993995
} else {
994996
None
@@ -1008,13 +1010,13 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
10081010
K: Borrow<Q>,
10091011
Q: Hash + Eq + ?Sized,
10101012
{
1011-
let hash = self.hash_usize(&key);
1013+
let hash = self.hash_u64(&key);
10121014

1013-
let idx = self.determine_shard(hash);
1015+
let idx = self.determine_shard(hash as usize);
10141016

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

1017-
if let Some((kptr, vptr)) = shard.get_key_value(key) {
1019+
if let Some((kptr, vptr)) = shard.raw_entry().from_key_hashed_nocheck(hash, key) {
10181020
unsafe {
10191021
let kptr: *const K = kptr;
10201022
let vptr: *const V = vptr.get();
@@ -1030,16 +1032,18 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
10301032
K: Borrow<Q>,
10311033
Q: Hash + Eq + ?Sized,
10321034
{
1033-
let hash = self.hash_usize(&key);
1035+
let hash = self.hash_u64(&key);
10341036

1035-
let idx = self.determine_shard(hash);
1037+
let idx = self.determine_shard(hash as usize);
10361038

1037-
let shard = unsafe { self._yield_write_shard(idx) };
1039+
let mut shard = unsafe { self._yield_write_shard(idx) };
10381040

1039-
if let Some((kptr, vptr)) = shard.get_key_value(key) {
1041+
if let RawEntryMut::Occupied(mut entry) =
1042+
shard.raw_entry_mut().from_key_hashed_nocheck(hash, key)
1043+
{
10401044
unsafe {
1041-
let kptr: *const K = kptr;
1042-
let vptr: *mut V = vptr.as_ptr();
1045+
let kptr: *const K = entry.key();
1046+
let vptr: *mut V = entry.get_mut().as_ptr();
10431047
Some(RefMut::new(shard, kptr, vptr))
10441048
}
10451049
} else {
@@ -1052,16 +1056,16 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
10521056
K: Borrow<Q>,
10531057
Q: Hash + Eq + ?Sized,
10541058
{
1055-
let hash = self.hash_usize(&key);
1059+
let hash = self.hash_u64(&key);
10561060

1057-
let idx = self.determine_shard(hash);
1061+
let idx = self.determine_shard(hash as usize);
10581062

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

1064-
if let Some((kptr, vptr)) = shard.get_key_value(key) {
1068+
if let Some((kptr, vptr)) = shard.raw_entry().from_key_hashed_nocheck(hash, key) {
10651069
unsafe {
10661070
let kptr: *const K = kptr;
10671071
let vptr: *const V = vptr.get();
@@ -1077,16 +1081,16 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
10771081
K: Borrow<Q>,
10781082
Q: Hash + Eq + ?Sized,
10791083
{
1080-
let hash = self.hash_usize(&key);
1084+
let hash = self.hash_u64(&key);
10811085

1082-
let idx = self.determine_shard(hash);
1086+
let idx = self.determine_shard(hash as usize);
10831087

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

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

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

1150-
let idx = self.determine_shard(hash);
1154+
let idx = self.determine_shard(hash as usize);
11511155

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

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

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

1168-
let idx = self.determine_shard(hash);
1172+
let idx = self.determine_shard(hash as usize);
11691173

11701174
let shard = match unsafe { self._try_yield_write_shard(idx) } {
11711175
Some(shard) => shard,
11721176
None => return None,
11731177
};
11741178

1175-
if let Some((kptr, vptr)) = shard.get_key_value(&key) {
1179+
if let Some((kptr, vptr)) = shard.raw_entry().from_key_hashed_nocheck(hash, &key) {
11761180
unsafe {
11771181
let kptr: *const K = kptr;
11781182
let vptr: *mut V = vptr.as_ptr();

src/read_only.rs

+8-17
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,7 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> ReadOnlyView<K, V, S>
6161
K: Borrow<Q>,
6262
Q: Hash + Eq + ?Sized,
6363
{
64-
let hash = self.map.hash_usize(&key);
65-
66-
let idx = self.map.determine_shard(hash);
67-
68-
let shard = unsafe { self.map._get_read_shard(idx) };
69-
70-
shard.contains_key(key)
64+
self.get(key).is_some()
7165
}
7266

7367
/// Returns a reference to the value corresponding to the key.
@@ -76,13 +70,7 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> ReadOnlyView<K, V, S>
7670
K: Borrow<Q>,
7771
Q: Hash + Eq + ?Sized,
7872
{
79-
let hash = self.map.hash_usize(&key);
80-
81-
let idx = self.map.determine_shard(hash);
82-
83-
let shard = unsafe { self.map._get_read_shard(idx) };
84-
85-
shard.get(key).map(|v| v.get())
73+
self.get_key_value(key).map(|(_k, v)| v)
8674
}
8775

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

96-
let idx = self.map.determine_shard(hash);
84+
let idx = self.map.determine_shard(hash as usize);
9785

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

100-
shard.get_key_value(key).map(|(k, v)| (k, v.get()))
88+
shard
89+
.raw_entry()
90+
.from_key_hashed_nocheck(hash, key)
91+
.map(|(k, v)| (k, v.get()))
10192
}
10293

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

0 commit comments

Comments
 (0)