Skip to content

Commit

Permalink
Merge branch 'hashbrown-0.15' (324)
Browse files Browse the repository at this point in the history
  • Loading branch information
xacrimon committed Feb 1, 2025
2 parents 7fb4eb4 + 46005cb commit 54710a6
Show file tree
Hide file tree
Showing 7 changed files with 74 additions and 120 deletions.
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ inline = ["hashbrown/inline-more"]
[dependencies]
lock_api = "0.4.10"
parking_lot_core = "0.9.8"
hashbrown = { version = "0.14.0", default-features = false, features = ["raw"] }
hashbrown = { version = "0.15.1", default-features = false }
serde = { version = "1.0.188", optional = true, features = ["derive"] }
cfg-if = "1.0.0"
rayon = { version = "1.7.0", optional = true }
Expand Down
20 changes: 10 additions & 10 deletions src/iter.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use hashbrown::hash_table;

use super::mapref::multiple::{RefMulti, RefMutMulti};
use crate::lock::{RwLockReadGuardDetached, RwLockWriteGuardDetached};
use crate::t::Map;
Expand Down Expand Up @@ -37,7 +39,7 @@ impl<K: Eq + Hash, V, S: BuildHasher + Clone> OwningIter<K, V, S> {
}
}

type GuardOwningIter<K, V> = hashbrown::raw::RawIntoIter<(K, V)>;
type GuardOwningIter<K, V> = hash_table::IntoIter<(K, V)>;

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

type GuardIter<'a, K, V> = (
Arc<RwLockReadGuardDetached<'a>>,
hashbrown::raw::RawIter<(K, V)>,
hash_table::Iter<'a, (K, V)>,
);

type GuardIterMut<'a, K, V> = (
Arc<RwLockWriteGuardDetached<'a>>,
hashbrown::raw::RawIter<(K, V)>,
hash_table::IterMut<'a, (K, V)>,
);

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

let iter = unsafe { shard.iter() };
let iter = shard.iter();

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

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

let iter = unsafe { shard.iter() };
let iter = shard.iter_mut();

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

Expand All @@ -234,7 +234,7 @@ mod tests {
let mut c = 0;

for shard in map.shards() {
c += unsafe { shard.write().iter().count() };
c += shard.write().iter().count();
}

assert_eq!(c, 1);
Expand Down
91 changes: 36 additions & 55 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ use core::hash::{BuildHasher, Hash, Hasher};
use core::iter::FromIterator;
use core::ops::{BitAnd, BitOr, Shl, Shr, Sub};
use crossbeam_utils::CachePadded;
use hashbrown::hash_table;
use iter::{Iter, IterMut, OwningIter};
use lock::{RwLockReadGuardDetached, RwLockWriteGuardDetached};
pub use mapref::entry::{Entry, OccupiedEntry, VacantEntry};
Expand All @@ -47,7 +48,7 @@ use std::collections::hash_map::RandomState;
pub use t::Map;
use try_result::TryResult;

pub(crate) type HashMap<K, V> = hashbrown::raw::RawTable<(K, V)>;
pub(crate) type HashMap<K, V> = hash_table::HashTable<(K, V)>;

// Temporary reimplementation of [`std::collections::TryReserveError`]
// util [`std::collections::TryReserveError`] stabilises.
Expand Down Expand Up @@ -336,7 +337,7 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap<K, V, S> {
/// };
/// let data = (42, "forty two");
/// let hash = hasher(&data);
/// map.shards_mut()[shard_ind].get_mut().insert(hash, data, hasher);
/// map.shards_mut()[shard_ind].get_mut().insert_unique(hash, data, hasher);
/// assert_eq!(*map.get(&42).unwrap(), "forty two");
/// ```
pub fn shards_mut(&mut self) -> &mut [CachePadded<RwLock<HashMap<K, V>>>] {
Expand Down Expand Up @@ -955,8 +956,8 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>

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

if let Some(bucket) = shard.find(hash, |(k, _v)| key == k.borrow()) {
let ((k, v), _) = unsafe { shard.remove(bucket) };
if let Ok(entry) = shard.find_entry(hash, |(k, _v)| key == k.borrow()) {
let ((k, v), _) = entry.remove();
Some((k, v))
} else {
None
Expand All @@ -974,10 +975,10 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>

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

if let Some(bucket) = shard.find(hash, |(k, _v)| key == k.borrow()) {
let (k, v) = unsafe { bucket.as_ref() };
if let Ok(entry) = shard.find_entry(hash, |(k, _v)| key == k.borrow()) {
let (k, v) = entry.get();
if f(k, v) {
let ((k, v), _) = unsafe { shard.remove(bucket) };
let ((k, v), _) = entry.remove();
Some((k, v))
} else {
None
Expand All @@ -998,10 +999,10 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>

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

if let Some(bucket) = shard.find(hash, |(k, _v)| key == k.borrow()) {
let (k, v) = unsafe { bucket.as_mut() };
if let Ok(mut entry) = shard.find_entry(hash, |(k, _v)| key == k.borrow()) {
let (k, v) = entry.get_mut();
if f(k, v) {
let ((k, v), _) = unsafe { shard.remove(bucket) };
let ((k, v), _) = entry.remove();
Some((k, v))
} else {
None
Expand Down Expand Up @@ -1032,11 +1033,8 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
// SAFETY: The data will not outlive the guard, since we pass the guard to `Ref`.
let (guard, shard) = unsafe { RwLockReadGuardDetached::detach_from(shard) };

if let Some(bucket) = shard.find(hash, |(k, _v)| key == k.borrow()) {
unsafe {
let (k, v) = bucket.as_ref();
Some(Ref::new(guard, k, v))
}
if let Some((k, v)) = shard.find(hash, |(k, _v)| key == k.borrow()) {
unsafe { Some(Ref::new(guard, k, v)) }
} else {
None
}
Expand All @@ -1055,11 +1053,8 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
// SAFETY: The data will not outlive the guard, since we pass the guard to `RefMut`.
let (guard, shard) = unsafe { RwLockWriteGuardDetached::detach_from(shard) };

if let Some(bucket) = shard.find(hash, |(k, _v)| key == k.borrow()) {
unsafe {
let (k, v) = bucket.as_mut();
Some(RefMut::new(guard, k, v))
}
if let Some((k, v)) = shard.find_mut(hash, |(k, _v)| key == k.borrow()) {
unsafe { Some(RefMut::new(guard, k, v)) }
} else {
None
}
Expand All @@ -1081,11 +1076,8 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
// SAFETY: The data will not outlive the guard, since we pass the guard to `Ref`.
let (guard, shard) = unsafe { RwLockReadGuardDetached::detach_from(shard) };

if let Some(bucket) = shard.find(hash, |(k, _v)| key == k.borrow()) {
unsafe {
let (k, v) = bucket.as_ref();
TryResult::Present(Ref::new(guard, k, v))
}
if let Some((k, v)) = shard.find(hash, |(k, _v)| key == k.borrow()) {
unsafe { TryResult::Present(Ref::new(guard, k, v)) }
} else {
TryResult::Absent
}
Expand All @@ -1107,11 +1099,8 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
// SAFETY: The data will not outlive the guard, since we pass the guard to `RefMut`.
let (guard, shard) = unsafe { RwLockWriteGuardDetached::detach_from(shard) };

if let Some(bucket) = shard.find(hash, |(k, _v)| key == k.borrow()) {
unsafe {
let (k, v) = bucket.as_mut();
TryResult::Present(RefMut::new(guard, k, v))
}
if let Some((k, v)) = shard.find_mut(hash, |(k, _v)| key == k.borrow()) {
unsafe { TryResult::Present(RefMut::new(guard, k, v)) }
} else {
TryResult::Absent
}
Expand All @@ -1131,16 +1120,7 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>

fn _retain(&self, mut f: impl FnMut(&K, &mut V) -> bool) {
self.shards.iter().for_each(|s| {
unsafe {
let mut shard = s.write();
// Here we only use `iter` as a temporary, preventing use-after-free
for bucket in shard.iter() {
let (k, v) = bucket.as_mut();
if !f(&*k, v) {
shard.erase(bucket);
}
}
}
s.write().retain(|(k, v)| f(k, v));
});
}

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

match shard.find_or_find_insert_slot(
match shard.entry(
hash,
|(k, _v)| k == &key,
|(k, _v)| {
Expand All @@ -1196,8 +1176,12 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
hasher.finish()
},
) {
Ok(elem) => Entry::Occupied(unsafe { OccupiedEntry::new(guard, key, shard, elem) }),
Err(slot) => Entry::Vacant(unsafe { VacantEntry::new(guard, key, hash, shard, slot) }),
hash_table::Entry::Occupied(entry) => {
Entry::Occupied(unsafe { OccupiedEntry::new(guard, key, entry) })
}
hash_table::Entry::Vacant(entry) => {
Entry::Vacant(unsafe { VacantEntry::new(guard, key, entry) })
}
}
}

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

match shard.find_or_find_insert_slot(
match shard.entry(
hash,
|(k, _v)| k == &key,
|(k, _v)| {
Expand All @@ -1222,11 +1206,11 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
hasher.finish()
},
) {
Ok(elem) => Some(Entry::Occupied(unsafe {
OccupiedEntry::new(guard, key, shard, elem)
hash_table::Entry::Occupied(entry) => Some(Entry::Occupied(unsafe {
OccupiedEntry::new(guard, key, entry)
})),
Err(slot) => Some(Entry::Vacant(unsafe {
VacantEntry::new(guard, key, hash, shard, slot)
hash_table::Entry::Vacant(entry) => Some(Entry::Vacant(unsafe {
VacantEntry::new(guard, key, entry)
})),
}
}
Expand Down Expand Up @@ -1359,15 +1343,12 @@ where
.iter()
.map(|shard_lock| {
let shard = shard_lock.read();
let hashtable_size = shard.allocation_info().1.size();
let hashtable_size = shard.allocation_size();

// Safety: The iterator is dropped before the HashTable
let iter = unsafe { shard.iter() };
let entry_size_iter = iter.map(|bucket| {
// Safety: The iterator returns buckets with valid pointers to entries
let (key, value) = unsafe { bucket.as_ref() };
key.extra_size() + value.extra_size()
});
let iter = shard.iter();
let entry_size_iter =
iter.map(|(key, value)| key.extra_size() + value.extra_size());

core::mem::size_of::<CachePadded<RwLock<HashMap<K, V>>>>()
+ hashtable_size
Expand Down
Loading

0 comments on commit 54710a6

Please sign in to comment.