Skip to content

Commit 68222f6

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

File tree

1 file changed

+156
-18
lines changed

1 file changed

+156
-18
lines changed

src/table.rs

Lines changed: 156 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,15 +2580,112 @@ 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+
/// ```rust
2604+
/// pub struct IterMut<'a, K, V> {
2605+
/// inner: hash_table::IterMut<'a, (K, V)>,
2606+
/// // Variant over keys, invariant over values
2607+
/// marker: PhantomData<(&'a K, &'a mut V)>,
2608+
/// }
2609+
/// impl<'a, K, V> Iterator for IterMut<'a, K, V> {
2610+
/// // Immutable keys, mutable values
2611+
/// type Item = (&'a K, &'a mut V);
2612+
///
2613+
/// fn next(&mut self) -> Option<Self::Item> {
2614+
/// // Even though the key is mutably borrowed here, this is sound
2615+
/// // because we never actually mutate the key before yielding the
2616+
/// // immutable reference
2617+
/// let (ref key, ref mut val) = self.inner.next()?;
2618+
/// Some((key, val))
2619+
/// }
2620+
/// }
2621+
/// ```
2622+
pub struct IterUnsafeMut<'a, T> {
2623+
inner: RawIter<T>,
2624+
marker: PhantomData<&'a T>,
2625+
}
2626+
impl<'a, T> IterUnsafeMut<'a, T> {
2627+
/// Returns a iterator of references over the remaining items.
2628+
#[cfg_attr(feature = "inline-more", inline)]
2629+
pub fn iter(&self) -> Iter<'_, T> {
2630+
Iter {
2631+
inner: self.inner.clone(),
2632+
marker: PhantomData,
2633+
}
2634+
}
2635+
}
2636+
2637+
impl<T> Default for IterUnsafeMut<'_, T> {
2638+
#[cfg_attr(feature = "inline-more", inline)]
2639+
fn default() -> Self {
2640+
IterUnsafeMut {
2641+
inner: Default::default(),
2642+
marker: PhantomData,
2643+
}
2644+
}
2645+
}
2646+
impl<'a, T> Iterator for IterUnsafeMut<'a, T> {
2647+
type Item = &'a mut T;
2648+
2649+
fn next(&mut self) -> Option<Self::Item> {
2650+
// Avoid `Option::map` because it bloats LLVM IR.
2651+
match self.inner.next() {
2652+
Some(bucket) => Some(unsafe { bucket.as_mut() }),
2653+
None => None,
2654+
}
2655+
}
2656+
2657+
fn size_hint(&self) -> (usize, Option<usize>) {
2658+
self.inner.size_hint()
2659+
}
2660+
2661+
fn fold<B, F>(self, init: B, mut f: F) -> B
2662+
where
2663+
Self: Sized,
2664+
F: FnMut(B, Self::Item) -> B,
2665+
{
2666+
self.inner
2667+
.fold(init, |acc, bucket| unsafe { f(acc, bucket.as_mut()) })
2668+
}
2669+
}
2670+
2671+
impl<T> ExactSizeIterator for IterUnsafeMut<'_, T> {
2672+
fn len(&self) -> usize {
2673+
self.inner.len()
25612674
}
25622675
}
25632676

2677+
impl<T> FusedIterator for IterUnsafeMut<'_, T> {}
2678+
2679+
impl<T> fmt::Debug for IterUnsafeMut<'_, T>
2680+
where
2681+
T: fmt::Debug,
2682+
{
2683+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2684+
f.debug_list().entries(self.iter()).finish()
2685+
}
2686+
}
2687+
2688+
25642689
/// An iterator producing the `usize` indices of all occupied buckets,
25652690
/// within the range `0..table.num_buckets()`.
25662691
///
@@ -2811,6 +2936,19 @@ where
28112936
{
28122937
inner: RawIntoIter<T, A>,
28132938
}
2939+
impl<T, A> IntoIter<T, A>
2940+
where
2941+
A: Allocator,
2942+
{
2943+
/// Returns a iterator of references over the remaining items.
2944+
#[cfg_attr(feature = "inline-more", inline)]
2945+
pub fn iter(&self) -> Iter<'_, T> {
2946+
Iter {
2947+
inner: self.inner.iter(),
2948+
marker: PhantomData,
2949+
}
2950+
}
2951+
}
28142952

28152953
impl<T, A: Allocator> Default for IntoIter<T, A> {
28162954
#[cfg_attr(feature = "inline-more", inline)]
@@ -2861,12 +2999,7 @@ where
28612999
A: Allocator,
28623000
{
28633001
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()
3002+
f.debug_list().entries(self.iter()).finish()
28703003
}
28713004
}
28723005

@@ -2880,6 +3013,16 @@ where
28803013
pub struct Drain<'a, T, A: Allocator = Global> {
28813014
inner: RawDrain<'a, T, A>,
28823015
}
3016+
impl<'a, T, A: Allocator> Drain<'a, T, A> {
3017+
/// Returns a iterator of references over the remaining items.
3018+
#[cfg_attr(feature = "inline-more", inline)]
3019+
pub fn iter(&self) -> Iter<'_, T> {
3020+
Iter {
3021+
inner: self.inner.iter(),
3022+
marker: PhantomData,
3023+
}
3024+
}
3025+
}
28833026

28843027
impl<T, A: Allocator> Iterator for Drain<'_, T, A> {
28853028
type Item = T;
@@ -2911,12 +3054,7 @@ impl<T, A: Allocator> FusedIterator for Drain<'_, T, A> {}
29113054

29123055
impl<T: fmt::Debug, A: Allocator> fmt::Debug for Drain<'_, T, A> {
29133056
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()
3057+
f.debug_list().entries(self.iter()).finish()
29203058
}
29213059
}
29223060

0 commit comments

Comments
 (0)