Skip to content

Commit dd6f585

Browse files
committed
implement HashMap::into_iter
1 parent ab036e1 commit dd6f585

4 files changed

Lines changed: 451 additions & 185 deletions

File tree

src/map.rs

Lines changed: 90 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,22 @@ use std::collections::hash_map::RandomState;
77
use std::fmt;
88
use std::hash::{BuildHasher, Hash};
99
use std::marker::PhantomData;
10+
use std::mem::ManuallyDrop;
1011

1112
/// A concurrent hash table.
1213
///
1314
/// Most hash table operations require a [`Guard`](crate::Guard), which can be acquired through
1415
/// [`HashMap::guard`] or using the [`HashMap::pin`] API. See the [crate-level documentation](crate#usage)
1516
/// for details.
1617
pub struct HashMap<K, V, S = RandomState> {
17-
raw: raw::HashMap<K, V, S>,
18+
raw: ManuallyDrop<raw::HashMap<K, V, S>>,
19+
}
20+
21+
impl<K, V, S> Drop for HashMap<K, V, S> {
22+
fn drop(&mut self) {
23+
// Safety: We don't access `self` after taking the inner map.
24+
raw::drop_map(unsafe { ManuallyDrop::take(&mut self.raw) });
25+
}
1826
}
1927

2028
// Safety: `HashMap` acts as a single-threaded collection on a single thread.
@@ -131,7 +139,12 @@ impl<K, V, S> HashMapBuilder<K, V, S> {
131139
/// Construct a [`HashMap`] from the builder, using the configured options.
132140
pub fn build(self) -> HashMap<K, V, S> {
133141
HashMap {
134-
raw: raw::HashMap::new(self.capacity, self.hasher, self.collector, self.resize_mode),
142+
raw: ManuallyDrop::new(raw::HashMap::new(
143+
self.capacity,
144+
self.hasher,
145+
self.collector,
146+
self.resize_mode,
147+
)),
135148
}
136149
}
137150
}
@@ -251,7 +264,7 @@ impl<K, V, S> HashMap<K, V, S> {
251264
///
252265
/// Warning: `hash_builder` is normally randomly generated, and is designed
253266
/// to allow HashMaps to be resistant to attacks that cause many collisions
254-
/// and very poor performance. Setting it manually using this function can
267+
/// and very actuallypoor performance. Setting it manually using this function can
255268
/// expose a DoS attack vector.
256269
///
257270
/// The `hash_builder` passed should implement the [`BuildHasher`] trait for
@@ -298,12 +311,12 @@ impl<K, V, S> HashMap<K, V, S> {
298311
/// ```
299312
pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> HashMap<K, V, S> {
300313
HashMap {
301-
raw: raw::HashMap::new(
314+
raw: ManuallyDrop::new(raw::HashMap::new(
302315
capacity,
303316
hash_builder,
304317
Collector::default(),
305318
ResizeMode::default(),
306-
),
319+
)),
307320
}
308321
}
309322

@@ -1100,6 +1113,37 @@ where
11001113
}
11011114
}
11021115

1116+
impl<K, V, S> IntoIterator for HashMap<K, V, S> {
1117+
type Item = (K, V);
1118+
type IntoIter = IntoIter<K, V>;
1119+
1120+
/// Creates a consuming iterator, that is, one that moves each key-value
1121+
/// pair out of the map in arbitrary order. The map cannot be used after
1122+
/// calling this.
1123+
///
1124+
/// ```
1125+
/// use papaya::HashMap;
1126+
///
1127+
/// let map = HashMap::from([
1128+
/// ("a", 1),
1129+
/// ("b", 2),
1130+
/// ("c", 3),
1131+
/// ]);
1132+
///
1133+
/// let v: Vec<(&str, i32)> = map.into_iter().collect();
1134+
/// ```
1135+
fn into_iter(self) -> Self::IntoIter {
1136+
let mut map = ManuallyDrop::new(self);
1137+
1138+
// Safety: We don't access `self` after taking the inner map.
1139+
let raw = unsafe { ManuallyDrop::take(&mut map.raw) };
1140+
1141+
IntoIter {
1142+
raw: raw.into_iter(),
1143+
}
1144+
}
1145+
}
1146+
11031147
/// An operation to perform on given entry in a [`HashMap`].
11041148
///
11051149
/// See [`HashMap::compute`] for details.
@@ -1194,7 +1238,8 @@ where
11941238
S: BuildHasher,
11951239
{
11961240
fn extend<T: IntoIterator<Item = (K, V)>>(&mut self, iter: T) {
1197-
// from `hashbrown::HashMap::extend`:
1241+
// From `hashbrown::HashMap::extend`:
1242+
//
11981243
// Keys may be already present or show multiple times in the iterator.
11991244
// Reserve the entire hint lower bound if the map is empty.
12001245
// Otherwise reserve half the hint (rounded up), so the map
@@ -1620,18 +1665,22 @@ where
16201665
}
16211666
}
16221667

1668+
impl<K, V, G> Clone for Iter<'_, K, V, G> {
1669+
fn clone(&self) -> Self {
1670+
Self {
1671+
raw: self.raw.clone(),
1672+
}
1673+
}
1674+
}
1675+
16231676
impl<K, V, G> fmt::Debug for Iter<'_, K, V, G>
16241677
where
16251678
K: fmt::Debug,
16261679
V: fmt::Debug,
16271680
G: Guard,
16281681
{
16291682
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1630-
f.debug_list()
1631-
.entries(Iter {
1632-
raw: self.raw.clone(),
1633-
})
1634-
.finish()
1683+
f.debug_list().entries(self.raw.clone()).finish()
16351684
}
16361685
}
16371686

@@ -1657,12 +1706,7 @@ where
16571706
V: fmt::Debug,
16581707
{
16591708
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1660-
f.debug_list()
1661-
.entries(IterMut {
1662-
// Safety: We only create a single clone.
1663-
raw: unsafe { self.raw.clone() },
1664-
})
1665-
.finish()
1709+
f.debug_list().entries(self.raw.iter()).finish()
16661710
}
16671711
}
16681712

@@ -1727,3 +1771,32 @@ where
17271771
f.debug_tuple("Values").field(&self.iter).finish()
17281772
}
17291773
}
1774+
1775+
/// An owned iterator over the entries of a `HashMap`.
1776+
///
1777+
/// This `struct` is created by the [`into_iter`] method on [`HashMap`]
1778+
/// (provided by the [`IntoIterator`] trait). See its documentation for more.
1779+
///
1780+
/// [`into_iter`]: IntoIterator::into_iter
1781+
pub struct IntoIter<K, V> {
1782+
pub(crate) raw: raw::IntoIter<K, V>,
1783+
}
1784+
1785+
impl<K, V> Iterator for IntoIter<K, V> {
1786+
type Item = (K, V);
1787+
1788+
#[inline]
1789+
fn next(&mut self) -> Option<Self::Item> {
1790+
self.raw.next()
1791+
}
1792+
}
1793+
1794+
impl<K, V> fmt::Debug for IntoIter<K, V>
1795+
where
1796+
K: fmt::Debug,
1797+
V: fmt::Debug,
1798+
{
1799+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1800+
f.debug_list().entries(self.raw.iter()).finish()
1801+
}
1802+
}

0 commit comments

Comments
 (0)