Skip to content

Commit fc595f6

Browse files
committed
Add hash_table::UnsafeIter, iter() method to various iterators
1 parent bba4a01 commit fc595f6

File tree

1 file changed

+177
-19
lines changed

1 file changed

+177
-19
lines changed

src/table.rs

Lines changed: 177 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use core::{fmt, iter::FusedIterator, marker::PhantomData};
1+
use core::{fmt, iter::FusedIterator, marker::PhantomData, ptr::NonNull};
22

33
use crate::{
44
control::Tag,
@@ -1071,6 +1071,29 @@ where
10711071
}
10721072
}
10731073

1074+
/// An iterator visiting all elements in arbitrary order,
1075+
/// with pointers to the elements.
1076+
/// The iterator element type is `NonNull<T>`.
1077+
///
1078+
/// This iterator is intended for APIs where only part of the elements are
1079+
/// mutable, with the remainder being immutable. In these cases, wrapping
1080+
/// the ordinary mutable iterator is incorrect because all components of
1081+
/// the element type will be [invariant]. A correct implementation will use
1082+
/// an appropriate [`PhantomData`] marker to make the immutable parts
1083+
/// [covariant] and the mutable parts invariant.
1084+
///
1085+
/// [invariant]: https://doc.rust-lang.org/stable/reference/subtyping.html#r-subtyping.variance.invariant
1086+
/// [covariant]: https://doc.rust-lang.org/stable/reference/subtyping.html#r-subtyping.variance.covariant
1087+
///
1088+
/// See the documentation for [`UnsafeIter`] for more information on how
1089+
/// to correctly use this.
1090+
pub fn unsafe_iter(&mut self) -> UnsafeIter<'_, T> {
1091+
UnsafeIter {
1092+
inner: unsafe { self.raw.iter() },
1093+
marker: PhantomData,
1094+
}
1095+
}
1096+
10741097
/// An iterator producing the `usize` indices of all occupied buckets.
10751098
///
10761099
/// The order in which the iterator yields indices is unspecified
@@ -2508,6 +2531,16 @@ pub struct IterMut<'a, T> {
25082531
inner: RawIter<T>,
25092532
marker: PhantomData<&'a mut T>,
25102533
}
2534+
impl<'a, T> IterMut<'a, T> {
2535+
/// Returns a iterator of references over the remaining items.
2536+
#[cfg_attr(feature = "inline-more", inline)]
2537+
pub fn iter(&self) -> Iter<'_, T> {
2538+
Iter {
2539+
inner: self.inner.clone(),
2540+
marker: PhantomData,
2541+
}
2542+
}
2543+
}
25112544

25122545
impl<T> Default for IterMut<'_, T> {
25132546
#[cfg_attr(feature = "inline-more", inline)]
@@ -2556,12 +2589,124 @@ where
25562589
T: fmt::Debug,
25572590
{
25582591
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2559-
f.debug_list()
2560-
.entries(Iter {
2561-
inner: self.inner.clone(),
2562-
marker: PhantomData,
2563-
})
2564-
.finish()
2592+
f.debug_list().entries(self.iter()).finish()
2593+
}
2594+
}
2595+
2596+
/// An unsafe iterator over the entries of a `HashTable` in arbitrary order.
2597+
/// The iterator element type is `NonNull<T>`.
2598+
///
2599+
/// This `struct` is created by the [`unsafe_iter`] method on [`HashTable`].
2600+
///
2601+
/// This is used for implementations of iterators with "mixed" mutability on
2602+
/// the iterated elements. For example, a mutable iterator for a map may return
2603+
/// an immutable key alongside a mutable value, even though these are both
2604+
/// stored inside the table.
2605+
///
2606+
/// If you have no idea what any of this means, you probably should be using
2607+
/// [`IterMut`] instead, as it does not have any safety requirements.
2608+
///
2609+
/// # Safety
2610+
///
2611+
/// In order to correctly use this iterator, it should be wrapped in a safe
2612+
/// iterator struct with the appropriate [`PhantomData`] marker to indicate the
2613+
/// correct [variance].
2614+
///
2615+
/// For example, below is a simplified [`hash_map::IterMut`] implementation
2616+
/// that correctly returns a [covariant] key, and an [invariant] value:
2617+
///
2618+
/// [variance]: https://doc.rust-lang.org/stable/reference/subtyping.html#r-subtyping.variance
2619+
/// [covariant]: https://doc.rust-lang.org/stable/reference/subtyping.html#r-subtyping.variance.covariant
2620+
/// [invariant]: https://doc.rust-lang.org/stable/reference/subtyping.html#r-subtyping.variance.invariant
2621+
/// [`hash_map::IterMut`]: crate::hash_map::IterMut
2622+
///
2623+
/// ```rust
2624+
/// use core::marker::PhantomData;
2625+
/// use hashbrown::hash_table;
2626+
///
2627+
/// pub struct IterMut<'a, K, V> {
2628+
/// inner: hash_table::UnsafeIter<'a, (K, V)>,
2629+
/// // Covariant over keys, invariant over values
2630+
/// marker: PhantomData<(&'a K, &'a mut V)>,
2631+
/// }
2632+
/// impl<'a, K, V> Iterator for IterMut<'a, K, V> {
2633+
/// // Immutable keys, mutable values
2634+
/// type Item = (&'a K, &'a mut V);
2635+
///
2636+
/// fn next(&mut self) -> Option<Self::Item> {
2637+
/// // SAFETY: The lifetime of the dereferenced pointer is derived from
2638+
/// // the lifetime of its iterator, ensuring that it's always valid.
2639+
/// // Additionally, we match the mutability in `self.marker` to ensure
2640+
/// // the correct variance.
2641+
/// let (ref key, ref mut val) = unsafe { *self.inner.next() }?;
2642+
/// Some((key, val))
2643+
/// }
2644+
/// }
2645+
/// ```
2646+
pub struct UnsafeIter<'a, T> {
2647+
inner: RawIter<T>,
2648+
marker: PhantomData<&'a ()>,
2649+
}
2650+
impl<'a, T> UnsafeIter<'a, T> {
2651+
/// Returns a iterator of references over the remaining items.
2652+
#[cfg_attr(feature = "inline-more", inline)]
2653+
pub fn iter(&self) -> Iter<'_, T> {
2654+
Iter {
2655+
inner: self.inner.clone(),
2656+
marker: PhantomData,
2657+
}
2658+
}
2659+
}
2660+
2661+
impl<T> Default for UnsafeIter<'_, T> {
2662+
#[cfg_attr(feature = "inline-more", inline)]
2663+
fn default() -> Self {
2664+
UnsafeIter {
2665+
inner: Default::default(),
2666+
marker: PhantomData,
2667+
}
2668+
}
2669+
}
2670+
impl<'a, T> Iterator for UnsafeIter<'a, T> {
2671+
type Item = NonNull<T>;
2672+
2673+
fn next(&mut self) -> Option<Self::Item> {
2674+
// Avoid `Option::map` because it bloats LLVM IR.
2675+
match self.inner.next() {
2676+
Some(bucket) => Some(unsafe { NonNull::new_unchecked(bucket.as_ptr()) }),
2677+
None => None,
2678+
}
2679+
}
2680+
2681+
fn size_hint(&self) -> (usize, Option<usize>) {
2682+
self.inner.size_hint()
2683+
}
2684+
2685+
fn fold<B, F>(self, init: B, mut f: F) -> B
2686+
where
2687+
Self: Sized,
2688+
F: FnMut(B, Self::Item) -> B,
2689+
{
2690+
self.inner.fold(init, |acc, bucket| unsafe {
2691+
f(acc, NonNull::new_unchecked(bucket.as_ptr()))
2692+
})
2693+
}
2694+
}
2695+
2696+
impl<T> ExactSizeIterator for UnsafeIter<'_, T> {
2697+
fn len(&self) -> usize {
2698+
self.inner.len()
2699+
}
2700+
}
2701+
2702+
impl<T> FusedIterator for UnsafeIter<'_, T> {}
2703+
2704+
impl<T> fmt::Debug for UnsafeIter<'_, T>
2705+
where
2706+
T: fmt::Debug,
2707+
{
2708+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2709+
f.debug_list().entries(self.iter()).finish()
25652710
}
25662711
}
25672712

@@ -2815,6 +2960,19 @@ where
28152960
{
28162961
inner: RawIntoIter<T, A>,
28172962
}
2963+
impl<T, A> IntoIter<T, A>
2964+
where
2965+
A: Allocator,
2966+
{
2967+
/// Returns a iterator of references over the remaining items.
2968+
#[cfg_attr(feature = "inline-more", inline)]
2969+
pub fn iter(&self) -> Iter<'_, T> {
2970+
Iter {
2971+
inner: self.inner.iter(),
2972+
marker: PhantomData,
2973+
}
2974+
}
2975+
}
28182976

28192977
impl<T, A: Allocator> Default for IntoIter<T, A> {
28202978
#[cfg_attr(feature = "inline-more", inline)]
@@ -2865,12 +3023,7 @@ where
28653023
A: Allocator,
28663024
{
28673025
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2868-
f.debug_list()
2869-
.entries(Iter {
2870-
inner: self.inner.iter(),
2871-
marker: PhantomData,
2872-
})
2873-
.finish()
3026+
f.debug_list().entries(self.iter()).finish()
28743027
}
28753028
}
28763029

@@ -2884,6 +3037,16 @@ where
28843037
pub struct Drain<'a, T, A: Allocator = Global> {
28853038
inner: RawDrain<'a, T, A>,
28863039
}
3040+
impl<'a, T, A: Allocator> Drain<'a, T, A> {
3041+
/// Returns a iterator of references over the remaining items.
3042+
#[cfg_attr(feature = "inline-more", inline)]
3043+
pub fn iter(&self) -> Iter<'_, T> {
3044+
Iter {
3045+
inner: self.inner.iter(),
3046+
marker: PhantomData,
3047+
}
3048+
}
3049+
}
28873050

28883051
impl<T, A: Allocator> Iterator for Drain<'_, T, A> {
28893052
type Item = T;
@@ -2915,12 +3078,7 @@ impl<T, A: Allocator> FusedIterator for Drain<'_, T, A> {}
29153078

29163079
impl<T: fmt::Debug, A: Allocator> fmt::Debug for Drain<'_, T, A> {
29173080
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2918-
f.debug_list()
2919-
.entries(Iter {
2920-
inner: self.inner.iter(),
2921-
marker: PhantomData,
2922-
})
2923-
.finish()
3081+
f.debug_list().entries(self.iter()).finish()
29243082
}
29253083
}
29263084

0 commit comments

Comments
 (0)