Skip to content

Commit e2a7538

Browse files
committed
Add hash_table::IterUnsafeMut, iter() method to various iterators
1 parent c5c96af commit e2a7538

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
@@ -1071,6 +1071,24 @@ where
10711071
}
10721072
}
10731073

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

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

@@ -2811,6 +2940,19 @@ where
28112940
{
28122941
inner: RawIntoIter<T, A>,
28132942
}
2943+
impl<T, A> IntoIter<T, A>
2944+
where
2945+
A: Allocator,
2946+
{
2947+
/// Returns a iterator of references over the remaining items.
2948+
#[cfg_attr(feature = "inline-more", inline)]
2949+
pub fn iter(&self) -> Iter<'_, T> {
2950+
Iter {
2951+
inner: self.inner.iter(),
2952+
marker: PhantomData,
2953+
}
2954+
}
2955+
}
28142956

28152957
impl<T, A: Allocator> Default for IntoIter<T, A> {
28162958
#[cfg_attr(feature = "inline-more", inline)]
@@ -2861,12 +3003,7 @@ where
28613003
A: Allocator,
28623004
{
28633005
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2864-
f.debug_list()
2865-
.entries(Iter {
2866-
inner: self.inner.iter(),
2867-
marker: PhantomData,
2868-
})
2869-
.finish()
3006+
f.debug_list().entries(self.iter()).finish()
28703007
}
28713008
}
28723009

@@ -2880,6 +3017,16 @@ where
28803017
pub struct Drain<'a, T, A: Allocator = Global> {
28813018
inner: RawDrain<'a, T, A>,
28823019
}
3020+
impl<'a, T, A: Allocator> Drain<'a, T, A> {
3021+
/// Returns a iterator of references over the remaining items.
3022+
#[cfg_attr(feature = "inline-more", inline)]
3023+
pub fn iter(&self) -> Iter<'_, T> {
3024+
Iter {
3025+
inner: self.inner.iter(),
3026+
marker: PhantomData,
3027+
}
3028+
}
3029+
}
28833030

28843031
impl<T, A: Allocator> Iterator for Drain<'_, T, A> {
28853032
type Item = T;
@@ -2911,12 +3058,7 @@ impl<T, A: Allocator> FusedIterator for Drain<'_, T, A> {}
29113058

29123059
impl<T: fmt::Debug, A: Allocator> fmt::Debug for Drain<'_, T, A> {
29133060
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2914-
f.debug_list()
2915-
.entries(Iter {
2916-
inner: self.inner.iter(),
2917-
marker: PhantomData,
2918-
})
2919-
.finish()
3061+
f.debug_list().entries(self.iter()).finish()
29203062
}
29213063
}
29223064

0 commit comments

Comments
 (0)