Skip to content

Commit 89c7f05

Browse files
committed
Add hash_table::IterUnsafeMut, iter() method to various iterators
1 parent ae0a4f2 commit 89c7f05

File tree

1 file changed

+160
-18
lines changed

1 file changed

+160
-18
lines changed

src/table.rs

Lines changed: 160 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,6 +1073,24 @@ where
10731073
}
10741074
}
10751075

1076+
/// A version of [`iter_mut`](Self::iter_mut) which is variant over
1077+
/// elements, and thus unsafe.
1078+
///
1079+
/// See the documentation for [`IterUnsafeMut`] for more information on how
1080+
/// to correctly use this.
1081+
///
1082+
/// # Safety
1083+
///
1084+
/// Any part of the returned elements which is mutated must be made invariant.
1085+
/// See the documentation for [`IterUnsafeMut`] for an example and further
1086+
/// explanation.
1087+
pub unsafe fn iter_unsafe_mut(&mut self) -> IterUnsafeMut<'_, T> {
1088+
IterUnsafeMut {
1089+
inner: unsafe { self.raw.iter() },
1090+
marker: PhantomData,
1091+
}
1092+
}
1093+
10761094
/// An iterator producing the `usize` indices of all occupied buckets.
10771095
///
10781096
/// The order in which the iterator yields indices is unspecified
@@ -2510,6 +2528,16 @@ pub struct IterMut<'a, T> {
25102528
inner: RawIter<T>,
25112529
marker: PhantomData<&'a mut T>,
25122530
}
2531+
impl<'a, T> IterMut<'a, T> {
2532+
/// Returns a iterator of references over the remaining items.
2533+
#[cfg_attr(feature = "inline-more", inline)]
2534+
pub fn iter(&self) -> Iter<'_, T> {
2535+
Iter {
2536+
inner: self.inner.clone(),
2537+
marker: PhantomData,
2538+
}
2539+
}
2540+
}
25132541

25142542
impl<T> Default for IterMut<'_, T> {
25152543
#[cfg_attr(feature = "inline-more", inline)]
@@ -2558,12 +2586,113 @@ where
25582586
T: fmt::Debug,
25592587
{
25602588
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2561-
f.debug_list()
2562-
.entries(Iter {
2563-
inner: self.inner.clone(),
2564-
marker: PhantomData,
2565-
})
2566-
.finish()
2589+
f.debug_list().entries(self.iter()).finish()
2590+
}
2591+
}
2592+
2593+
/// An unsafe version of [`IterMut`] which is *variant* over `T`.
2594+
///
2595+
/// This is used for implementations of mutable iterators where mutation is only
2596+
/// allowed on part of the value in the table. For example, a mutable iterator
2597+
/// for a map may return an immutable key alongside a mutable value, even though
2598+
/// these are both stored inside the table.
2599+
///
2600+
/// # Safety
2601+
///
2602+
/// In order to correctly use this iterator, it should be wrapped in a safe
2603+
/// iterator struct with the appropriate [`PhantomData`] marker to indicate the
2604+
/// correct variance.
2605+
///
2606+
/// For example, a [`hash_map::IterMut`] implementation correctly returning
2607+
/// a variant key, and an invariant value:
2608+
///
2609+
/// [`hash_map::IterMut`]: crate::hash_map::IterMut
2610+
///
2611+
/// ```rust
2612+
/// use core::marker::PhantomData;
2613+
/// use hashbrown::hash_table;
2614+
///
2615+
/// pub struct IterMut<'a, K, V> {
2616+
/// inner: hash_table::IterMut<'a, (K, V)>,
2617+
/// // Variant over keys, invariant over values
2618+
/// marker: PhantomData<(&'a K, &'a mut V)>,
2619+
/// }
2620+
/// impl<'a, K, V> Iterator for IterMut<'a, K, V> {
2621+
/// // Immutable keys, mutable values
2622+
/// type Item = (&'a K, &'a mut V);
2623+
///
2624+
/// fn next(&mut self) -> Option<Self::Item> {
2625+
/// // Even though the key is mutably borrowed here, this is sound
2626+
/// // because we never actually mutate the key before yielding the
2627+
/// // immutable reference
2628+
/// let (ref key, ref mut val) = self.inner.next()?;
2629+
/// Some((key, val))
2630+
/// }
2631+
/// }
2632+
/// ```
2633+
pub struct IterUnsafeMut<'a, T> {
2634+
inner: RawIter<T>,
2635+
marker: PhantomData<&'a T>,
2636+
}
2637+
impl<'a, T> IterUnsafeMut<'a, T> {
2638+
/// Returns a iterator of references over the remaining items.
2639+
#[cfg_attr(feature = "inline-more", inline)]
2640+
pub fn iter(&self) -> Iter<'_, T> {
2641+
Iter {
2642+
inner: self.inner.clone(),
2643+
marker: PhantomData,
2644+
}
2645+
}
2646+
}
2647+
2648+
impl<T> Default for IterUnsafeMut<'_, T> {
2649+
#[cfg_attr(feature = "inline-more", inline)]
2650+
fn default() -> Self {
2651+
IterUnsafeMut {
2652+
inner: Default::default(),
2653+
marker: PhantomData,
2654+
}
2655+
}
2656+
}
2657+
impl<'a, T> Iterator for IterUnsafeMut<'a, T> {
2658+
type Item = &'a mut T;
2659+
2660+
fn next(&mut self) -> Option<Self::Item> {
2661+
// Avoid `Option::map` because it bloats LLVM IR.
2662+
match self.inner.next() {
2663+
Some(bucket) => Some(unsafe { bucket.as_mut() }),
2664+
None => None,
2665+
}
2666+
}
2667+
2668+
fn size_hint(&self) -> (usize, Option<usize>) {
2669+
self.inner.size_hint()
2670+
}
2671+
2672+
fn fold<B, F>(self, init: B, mut f: F) -> B
2673+
where
2674+
Self: Sized,
2675+
F: FnMut(B, Self::Item) -> B,
2676+
{
2677+
self.inner
2678+
.fold(init, |acc, bucket| unsafe { f(acc, bucket.as_mut()) })
2679+
}
2680+
}
2681+
2682+
impl<T> ExactSizeIterator for IterUnsafeMut<'_, T> {
2683+
fn len(&self) -> usize {
2684+
self.inner.len()
2685+
}
2686+
}
2687+
2688+
impl<T> FusedIterator for IterUnsafeMut<'_, T> {}
2689+
2690+
impl<T> fmt::Debug for IterUnsafeMut<'_, T>
2691+
where
2692+
T: fmt::Debug,
2693+
{
2694+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2695+
f.debug_list().entries(self.iter()).finish()
25672696
}
25682697
}
25692698

@@ -2817,6 +2946,19 @@ where
28172946
{
28182947
inner: RawIntoIter<T, A>,
28192948
}
2949+
impl<T, A> IntoIter<T, A>
2950+
where
2951+
A: Allocator,
2952+
{
2953+
/// Returns a iterator of references over the remaining items.
2954+
#[cfg_attr(feature = "inline-more", inline)]
2955+
pub fn iter(&self) -> Iter<'_, T> {
2956+
Iter {
2957+
inner: self.inner.iter(),
2958+
marker: PhantomData,
2959+
}
2960+
}
2961+
}
28202962

28212963
impl<T, A: Allocator> Default for IntoIter<T, A> {
28222964
#[cfg_attr(feature = "inline-more", inline)]
@@ -2867,12 +3009,7 @@ where
28673009
A: Allocator,
28683010
{
28693011
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2870-
f.debug_list()
2871-
.entries(Iter {
2872-
inner: self.inner.iter(),
2873-
marker: PhantomData,
2874-
})
2875-
.finish()
3012+
f.debug_list().entries(self.iter()).finish()
28763013
}
28773014
}
28783015

@@ -2886,6 +3023,16 @@ where
28863023
pub struct Drain<'a, T, A: Allocator = Global> {
28873024
inner: RawDrain<'a, T, A>,
28883025
}
3026+
impl<'a, T, A: Allocator> Drain<'a, T, A> {
3027+
/// Returns a iterator of references over the remaining items.
3028+
#[cfg_attr(feature = "inline-more", inline)]
3029+
pub fn iter(&self) -> Iter<'_, T> {
3030+
Iter {
3031+
inner: self.inner.iter(),
3032+
marker: PhantomData,
3033+
}
3034+
}
3035+
}
28893036

28903037
impl<T, A: Allocator> Iterator for Drain<'_, T, A> {
28913038
type Item = T;
@@ -2917,12 +3064,7 @@ impl<T, A: Allocator> FusedIterator for Drain<'_, T, A> {}
29173064

29183065
impl<T: fmt::Debug, A: Allocator> fmt::Debug for Drain<'_, T, A> {
29193066
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2920-
f.debug_list()
2921-
.entries(Iter {
2922-
inner: self.inner.iter(),
2923-
marker: PhantomData,
2924-
})
2925-
.finish()
3067+
f.debug_list().entries(self.iter()).finish()
29263068
}
29273069
}
29283070

0 commit comments

Comments
 (0)