Skip to content

Commit 46005cb

Browse files
committed
upgrade to hashbrown 0.15 with HashTable API
1 parent 22bd6af commit 46005cb

File tree

7 files changed

+74
-120
lines changed

7 files changed

+74
-120
lines changed

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ inline = ["hashbrown/inline-more"]
2121
[dependencies]
2222
lock_api = "0.4.10"
2323
parking_lot_core = "0.9.8"
24-
hashbrown = { version = "0.14.0", default-features = false, features = ["raw"] }
24+
hashbrown = { version = "0.15.1", default-features = false }
2525
serde = { version = "1.0.188", optional = true, features = ["derive"] }
2626
cfg-if = "1.0.0"
2727
rayon = { version = "1.7.0", optional = true }

src/iter.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use hashbrown::hash_table;
2+
13
use super::mapref::multiple::{RefMulti, RefMutMulti};
24
use crate::lock::{RwLockReadGuardDetached, RwLockWriteGuardDetached};
35
use crate::t::Map;
@@ -37,7 +39,7 @@ impl<K: Eq + Hash, V, S: BuildHasher + Clone> OwningIter<K, V, S> {
3739
}
3840
}
3941

40-
type GuardOwningIter<K, V> = hashbrown::raw::RawIntoIter<(K, V)>;
42+
type GuardOwningIter<K, V> = hash_table::IntoIter<(K, V)>;
4143

4244
impl<K: Eq + Hash, V, S: BuildHasher + Clone> Iterator for OwningIter<K, V, S> {
4345
type Item = (K, V);
@@ -71,12 +73,12 @@ impl<K: Eq + Hash, V, S: BuildHasher + Clone> Iterator for OwningIter<K, V, S> {
7173

7274
type GuardIter<'a, K, V> = (
7375
Arc<RwLockReadGuardDetached<'a>>,
74-
hashbrown::raw::RawIter<(K, V)>,
76+
hash_table::Iter<'a, (K, V)>,
7577
);
7678

7779
type GuardIterMut<'a, K, V> = (
7880
Arc<RwLockWriteGuardDetached<'a>>,
79-
hashbrown::raw::RawIter<(K, V)>,
81+
hash_table::IterMut<'a, (K, V)>,
8082
);
8183

8284
/// Iterator over a DashMap yielding immutable references.
@@ -124,9 +126,8 @@ impl<'a, K: Eq + Hash + 'a, V: 'a, S: 'a + BuildHasher + Clone, M: Map<'a, K, V,
124126
fn next(&mut self) -> Option<Self::Item> {
125127
loop {
126128
if let Some(current) = self.current.as_mut() {
127-
if let Some(b) = current.1.next() {
129+
if let Some((k, v)) = current.1.next() {
128130
return unsafe {
129-
let (k, v) = b.as_ref();
130131
let guard = current.0.clone();
131132
Some(RefMulti::new(guard, k, v))
132133
};
@@ -142,7 +143,7 @@ impl<'a, K: Eq + Hash + 'a, V: 'a, S: 'a + BuildHasher + Clone, M: Map<'a, K, V,
142143
// and with any refs produced by the iterator
143144
let (guard, shard) = unsafe { RwLockReadGuardDetached::detach_from(guard) };
144145

145-
let iter = unsafe { shard.iter() };
146+
let iter = shard.iter();
146147

147148
self.current = Some((Arc::new(guard), iter));
148149

@@ -191,9 +192,8 @@ impl<'a, K: Eq + Hash + 'a, V: 'a, S: 'a + BuildHasher + Clone, M: Map<'a, K, V,
191192
fn next(&mut self) -> Option<Self::Item> {
192193
loop {
193194
if let Some(current) = self.current.as_mut() {
194-
if let Some(b) = current.1.next() {
195+
if let Some((k, v)) = current.1.next() {
195196
return unsafe {
196-
let (k, v) = b.as_mut();
197197
let guard = current.0.clone();
198198
Some(RefMutMulti::new(guard, k, v))
199199
};
@@ -210,7 +210,7 @@ impl<'a, K: Eq + Hash + 'a, V: 'a, S: 'a + BuildHasher + Clone, M: Map<'a, K, V,
210210
// and with any refs produced by the iterator
211211
let (guard, shard) = unsafe { RwLockWriteGuardDetached::detach_from(guard) };
212212

213-
let iter = unsafe { shard.iter() };
213+
let iter = shard.iter_mut();
214214

215215
self.current = Some((Arc::new(guard), iter));
216216

@@ -234,7 +234,7 @@ mod tests {
234234
let mut c = 0;
235235

236236
for shard in map.shards() {
237-
c += unsafe { shard.write().iter().count() };
237+
c += shard.write().iter().count();
238238
}
239239

240240
assert_eq!(c, 1);

src/lib.rs

Lines changed: 36 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ use core::hash::{BuildHasher, Hash, Hasher};
3535
use core::iter::FromIterator;
3636
use core::ops::{BitAnd, BitOr, Shl, Shr, Sub};
3737
use crossbeam_utils::CachePadded;
38+
use hashbrown::hash_table;
3839
use iter::{Iter, IterMut, OwningIter};
3940
use lock::{RwLockReadGuardDetached, RwLockWriteGuardDetached};
4041
pub use mapref::entry::{Entry, OccupiedEntry, VacantEntry};
@@ -47,7 +48,7 @@ use std::collections::hash_map::RandomState;
4748
pub use t::Map;
4849
use try_result::TryResult;
4950

50-
pub(crate) type HashMap<K, V> = hashbrown::raw::RawTable<(K, V)>;
51+
pub(crate) type HashMap<K, V> = hash_table::HashTable<(K, V)>;
5152

5253
// Temporary reimplementation of [`std::collections::TryReserveError`]
5354
// util [`std::collections::TryReserveError`] stabilises.
@@ -340,7 +341,7 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap<K, V, S> {
340341
/// };
341342
/// let data = (42, "forty two");
342343
/// let hash = hasher(&data);
343-
/// map.shards_mut()[shard_ind].get_mut().insert(hash, data, hasher);
344+
/// map.shards_mut()[shard_ind].get_mut().insert_unique(hash, data, hasher);
344345
/// assert_eq!(*map.get(&42).unwrap(), "forty two");
345346
/// ```
346347
pub fn shards_mut(&mut self) -> &mut [CachePadded<RwLock<HashMap<K, V>>>] {
@@ -959,8 +960,8 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
959960

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

962-
if let Some(bucket) = shard.find(hash, |(k, _v)| key == k.borrow()) {
963-
let ((k, v), _) = unsafe { shard.remove(bucket) };
963+
if let Ok(entry) = shard.find_entry(hash, |(k, _v)| key == k.borrow()) {
964+
let ((k, v), _) = entry.remove();
964965
Some((k, v))
965966
} else {
966967
None
@@ -978,10 +979,10 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
978979

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

981-
if let Some(bucket) = shard.find(hash, |(k, _v)| key == k.borrow()) {
982-
let (k, v) = unsafe { bucket.as_ref() };
982+
if let Ok(entry) = shard.find_entry(hash, |(k, _v)| key == k.borrow()) {
983+
let (k, v) = entry.get();
983984
if f(k, v) {
984-
let ((k, v), _) = unsafe { shard.remove(bucket) };
985+
let ((k, v), _) = entry.remove();
985986
Some((k, v))
986987
} else {
987988
None
@@ -1002,10 +1003,10 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
10021003

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

1005-
if let Some(bucket) = shard.find(hash, |(k, _v)| key == k.borrow()) {
1006-
let (k, v) = unsafe { bucket.as_mut() };
1006+
if let Ok(mut entry) = shard.find_entry(hash, |(k, _v)| key == k.borrow()) {
1007+
let (k, v) = entry.get_mut();
10071008
if f(k, v) {
1008-
let ((k, v), _) = unsafe { shard.remove(bucket) };
1009+
let ((k, v), _) = entry.remove();
10091010
Some((k, v))
10101011
} else {
10111012
None
@@ -1036,11 +1037,8 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
10361037
// SAFETY: The data will not outlive the guard, since we pass the guard to `Ref`.
10371038
let (guard, shard) = unsafe { RwLockReadGuardDetached::detach_from(shard) };
10381039

1039-
if let Some(bucket) = shard.find(hash, |(k, _v)| key == k.borrow()) {
1040-
unsafe {
1041-
let (k, v) = bucket.as_ref();
1042-
Some(Ref::new(guard, k, v))
1043-
}
1040+
if let Some((k, v)) = shard.find(hash, |(k, _v)| key == k.borrow()) {
1041+
unsafe { Some(Ref::new(guard, k, v)) }
10441042
} else {
10451043
None
10461044
}
@@ -1059,11 +1057,8 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
10591057
// SAFETY: The data will not outlive the guard, since we pass the guard to `RefMut`.
10601058
let (guard, shard) = unsafe { RwLockWriteGuardDetached::detach_from(shard) };
10611059

1062-
if let Some(bucket) = shard.find(hash, |(k, _v)| key == k.borrow()) {
1063-
unsafe {
1064-
let (k, v) = bucket.as_mut();
1065-
Some(RefMut::new(guard, k, v))
1066-
}
1060+
if let Some((k, v)) = shard.find_mut(hash, |(k, _v)| key == k.borrow()) {
1061+
unsafe { Some(RefMut::new(guard, k, v)) }
10671062
} else {
10681063
None
10691064
}
@@ -1085,11 +1080,8 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
10851080
// SAFETY: The data will not outlive the guard, since we pass the guard to `Ref`.
10861081
let (guard, shard) = unsafe { RwLockReadGuardDetached::detach_from(shard) };
10871082

1088-
if let Some(bucket) = shard.find(hash, |(k, _v)| key == k.borrow()) {
1089-
unsafe {
1090-
let (k, v) = bucket.as_ref();
1091-
TryResult::Present(Ref::new(guard, k, v))
1092-
}
1083+
if let Some((k, v)) = shard.find(hash, |(k, _v)| key == k.borrow()) {
1084+
unsafe { TryResult::Present(Ref::new(guard, k, v)) }
10931085
} else {
10941086
TryResult::Absent
10951087
}
@@ -1111,11 +1103,8 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
11111103
// SAFETY: The data will not outlive the guard, since we pass the guard to `RefMut`.
11121104
let (guard, shard) = unsafe { RwLockWriteGuardDetached::detach_from(shard) };
11131105

1114-
if let Some(bucket) = shard.find(hash, |(k, _v)| key == k.borrow()) {
1115-
unsafe {
1116-
let (k, v) = bucket.as_mut();
1117-
TryResult::Present(RefMut::new(guard, k, v))
1118-
}
1106+
if let Some((k, v)) = shard.find_mut(hash, |(k, _v)| key == k.borrow()) {
1107+
unsafe { TryResult::Present(RefMut::new(guard, k, v)) }
11191108
} else {
11201109
TryResult::Absent
11211110
}
@@ -1135,16 +1124,7 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
11351124

11361125
fn _retain(&self, mut f: impl FnMut(&K, &mut V) -> bool) {
11371126
self.shards.iter().for_each(|s| {
1138-
unsafe {
1139-
let mut shard = s.write();
1140-
// Here we only use `iter` as a temporary, preventing use-after-free
1141-
for bucket in shard.iter() {
1142-
let (k, v) = bucket.as_mut();
1143-
if !f(&*k, v) {
1144-
shard.erase(bucket);
1145-
}
1146-
}
1147-
}
1127+
s.write().retain(|(k, v)| f(k, v));
11481128
});
11491129
}
11501130

@@ -1191,7 +1171,7 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
11911171
// SAFETY: The data will not outlive the guard, since we pass the guard to `Entry`.
11921172
let (guard, shard) = unsafe { RwLockWriteGuardDetached::detach_from(shard) };
11931173

1194-
match shard.find_or_find_insert_slot(
1174+
match shard.entry(
11951175
hash,
11961176
|(k, _v)| k == &key,
11971177
|(k, _v)| {
@@ -1200,8 +1180,12 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
12001180
hasher.finish()
12011181
},
12021182
) {
1203-
Ok(elem) => Entry::Occupied(unsafe { OccupiedEntry::new(guard, key, shard, elem) }),
1204-
Err(slot) => Entry::Vacant(unsafe { VacantEntry::new(guard, key, hash, shard, slot) }),
1183+
hash_table::Entry::Occupied(entry) => {
1184+
Entry::Occupied(unsafe { OccupiedEntry::new(guard, key, entry) })
1185+
}
1186+
hash_table::Entry::Vacant(entry) => {
1187+
Entry::Vacant(unsafe { VacantEntry::new(guard, key, entry) })
1188+
}
12051189
}
12061190
}
12071191

@@ -1217,7 +1201,7 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
12171201
// SAFETY: The data will not outlive the guard, since we pass the guard to `Entry`.
12181202
let (guard, shard) = unsafe { RwLockWriteGuardDetached::detach_from(shard) };
12191203

1220-
match shard.find_or_find_insert_slot(
1204+
match shard.entry(
12211205
hash,
12221206
|(k, _v)| k == &key,
12231207
|(k, _v)| {
@@ -1226,11 +1210,11 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
12261210
hasher.finish()
12271211
},
12281212
) {
1229-
Ok(elem) => Some(Entry::Occupied(unsafe {
1230-
OccupiedEntry::new(guard, key, shard, elem)
1213+
hash_table::Entry::Occupied(entry) => Some(Entry::Occupied(unsafe {
1214+
OccupiedEntry::new(guard, key, entry)
12311215
})),
1232-
Err(slot) => Some(Entry::Vacant(unsafe {
1233-
VacantEntry::new(guard, key, hash, shard, slot)
1216+
hash_table::Entry::Vacant(entry) => Some(Entry::Vacant(unsafe {
1217+
VacantEntry::new(guard, key, entry)
12341218
})),
12351219
}
12361220
}
@@ -1363,15 +1347,12 @@ where
13631347
.iter()
13641348
.map(|shard_lock| {
13651349
let shard = shard_lock.read();
1366-
let hashtable_size = shard.allocation_info().1.size();
1350+
let hashtable_size = shard.allocation_size();
13671351

13681352
// Safety: The iterator is dropped before the HashTable
1369-
let iter = unsafe { shard.iter() };
1370-
let entry_size_iter = iter.map(|bucket| {
1371-
// Safety: The iterator returns buckets with valid pointers to entries
1372-
let (key, value) = unsafe { bucket.as_ref() };
1373-
key.extra_size() + value.extra_size()
1374-
});
1353+
let iter = shard.iter();
1354+
let entry_size_iter =
1355+
iter.map(|(key, value)| key.extra_size() + value.extra_size());
13751356

13761357
core::mem::size_of::<CachePadded<RwLock<HashMap<K, V>>>>()
13771358
+ hashtable_size

0 commit comments

Comments
 (0)