Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
157 changes: 145 additions & 12 deletions src/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,22 @@ use std::collections::hash_map::RandomState;
use std::fmt;
use std::hash::{BuildHasher, Hash};
use std::marker::PhantomData;
use std::mem::ManuallyDrop;

/// A concurrent hash table.
///
/// Most hash table operations require a [`Guard`](crate::Guard), which can be acquired through
/// [`HashMap::guard`] or using the [`HashMap::pin`] API. See the [crate-level documentation](crate#usage)
/// for details.
pub struct HashMap<K, V, S = RandomState> {
raw: raw::HashMap<K, V, S>,
raw: ManuallyDrop<raw::HashMap<K, V, S>>,
}

impl<K, V, S> Drop for HashMap<K, V, S> {
fn drop(&mut self) {
// Safety: We don't access `self` after taking the inner map.
raw::drop_map(unsafe { ManuallyDrop::take(&mut self.raw) });
}
}

// Safety: `HashMap` acts as a single-threaded collection on a single thread.
Expand All @@ -32,7 +40,7 @@ unsafe impl<K: Send, V: Send, S: Send> Send for HashMap<K, V, S> {}
// Additionally, `HashMap` owns its `seize::Collector` and never exposes it,
// so multiple threads cannot be involved in reclamation without sharing the
// `HashMap` itself. If this was not true, we would require stricter bounds
// on `HashMap` operations themselves.
// on the `HashMap` operations themselves.
unsafe impl<K: Send + Sync, V: Send + Sync, S: Sync> Sync for HashMap<K, V, S> {}

/// A builder for a [`HashMap`].
Expand Down Expand Up @@ -131,7 +139,12 @@ impl<K, V, S> HashMapBuilder<K, V, S> {
/// Construct a [`HashMap`] from the builder, using the configured options.
pub fn build(self) -> HashMap<K, V, S> {
HashMap {
raw: raw::HashMap::new(self.capacity, self.hasher, self.collector, self.resize_mode),
raw: ManuallyDrop::new(raw::HashMap::new(
self.capacity,
self.hasher,
self.collector,
self.resize_mode,
)),
}
}
}
Expand Down Expand Up @@ -298,12 +311,12 @@ impl<K, V, S> HashMap<K, V, S> {
/// ```
pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> HashMap<K, V, S> {
HashMap {
raw: raw::HashMap::new(
raw: ManuallyDrop::new(raw::HashMap::new(
capacity,
hash_builder,
Collector::default(),
ResizeMode::default(),
),
)),
}
}

Expand Down Expand Up @@ -1006,6 +1019,35 @@ where
}
}

/// An iterator visiting all key-value pairs in arbitrary order, with mutable references
/// to the values. The iterator element type is `(&K, &mut V)`.
///
/// # Examples
///
/// ```
/// use papaya::HashMap;
///
/// let mut map = HashMap::from([
/// ("a", 1),
/// ("b", 2),
/// ("c", 3),
/// ]);
///
/// // Update all values.
/// for (_, val) in map.iter_mut() {
/// *val *= 2;
/// }
///
/// for (key, val) in map.pin().iter() {
/// println!("key: {key} val: {val}");
/// }
#[inline]
pub fn iter_mut(&mut self) -> IterMut<'_, K, V> {
IterMut {
raw: self.raw.iter_mut(),
}
}

/// An iterator visiting all keys in arbitrary order.
/// The iterator element type is `&K`.
///
Expand Down Expand Up @@ -1071,6 +1113,37 @@ where
}
}

impl<K, V, S> IntoIterator for HashMap<K, V, S> {
type Item = (K, V);
type IntoIter = IntoIter<K, V>;

/// Creates a consuming iterator, that is, one that moves each key-value
/// pair out of the map in arbitrary order. The map cannot be used after
/// calling this.
///
/// ```
/// use papaya::HashMap;
///
/// let map = HashMap::from([
/// ("a", 1),
/// ("b", 2),
/// ("c", 3),
/// ]);
///
/// let v: Vec<(&str, i32)> = map.into_iter().collect();
/// ```
fn into_iter(self) -> Self::IntoIter {
let mut map = ManuallyDrop::new(self);

// Safety: We don't access `self` after taking the inner map.
let raw = unsafe { ManuallyDrop::take(&mut map.raw) };

IntoIter {
raw: raw.into_iter(),
}
}
}

/// An operation to perform on given entry in a [`HashMap`].
///
/// See [`HashMap::compute`] for details.
Expand Down Expand Up @@ -1165,7 +1238,8 @@ where
S: BuildHasher,
{
fn extend<T: IntoIterator<Item = (K, V)>>(&mut self, iter: T) {
// from `hashbrown::HashMap::extend`:
// From `hashbrown::HashMap::extend`:
//
// Keys may be already present or show multiple times in the iterator.
// Reserve the entire hint lower bound if the map is empty.
// Otherwise reserve half the hint (rounded up), so the map
Expand Down Expand Up @@ -1572,7 +1646,7 @@ where
}
}

/// An iterator over a map's entries.
/// An iterator over the entries of a `HashMap`.
///
/// This struct is created by the [`iter`](HashMap::iter) method on [`HashMap`]. See its documentation for details.
pub struct Iter<'g, K, V, G> {
Expand All @@ -1591,18 +1665,48 @@ where
}
}

impl<K, V, G> Clone for Iter<'_, K, V, G> {
fn clone(&self) -> Self {
Self {
raw: self.raw.clone(),
}
}
}

impl<K, V, G> fmt::Debug for Iter<'_, K, V, G>
where
K: fmt::Debug,
V: fmt::Debug,
G: Guard,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list()
.entries(Iter {
raw: self.raw.clone(),
})
.finish()
f.debug_list().entries(self.raw.clone()).finish()
}
}

/// A mutable iterator over the entries of a `HashMap`.
///
/// This struct is created by the [`iter_mut`](HashMap::iter_mut) method on [`HashMap`]. See its documentation for details.
pub struct IterMut<'map, K, V> {
raw: raw::IterMut<'map, K, V>,
}

impl<'map, K, V> Iterator for IterMut<'map, K, V> {
type Item = (&'map K, &'map mut V);

#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.raw.next()
}
}

impl<K, V> fmt::Debug for IterMut<'_, K, V>
where
K: fmt::Debug,
V: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.raw.iter()).finish()
}
}

Expand Down Expand Up @@ -1667,3 +1771,32 @@ where
f.debug_tuple("Values").field(&self.iter).finish()
}
}

/// An owned iterator over the entries of a `HashMap`.
///
/// This `struct` is created by the [`into_iter`] method on [`HashMap`]
/// (provided by the [`IntoIterator`] trait). See its documentation for more.
///
/// [`into_iter`]: IntoIterator::into_iter
pub struct IntoIter<K, V> {
pub(crate) raw: raw::IntoIter<K, V>,
}

impl<K, V> Iterator for IntoIter<K, V> {
type Item = (K, V);

#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.raw.next()
}
}

impl<K, V> fmt::Debug for IntoIter<K, V>
where
K: fmt::Debug,
V: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.raw.iter()).finish()
}
}
19 changes: 19 additions & 0 deletions src/raw/alloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,25 @@ impl<T> Table<T> {
}
}

// Returns the entry at the given index.
//
// # Safety
//
// The index must be in-bounds for the length of the table.
#[inline]
pub unsafe fn entry_mut(&mut self, i: usize) -> *mut T {
debug_assert!(i < self.len());

// Safety: The caller guarantees the index is in-bounds.
let entry = unsafe {
let meta = self.raw.add(mem::size_of::<TableLayout<T>>());
let entries = meta.add(self.len()).cast::<AtomicPtr<T>>();
&mut *entries.add(i)
};

*entry.get_mut()
}

/// Returns the length of the table.
#[inline]
pub fn len(&self) -> usize {
Expand Down
Loading
Loading