Skip to content

Commit 6b79f32

Browse files
committed
Add hash_table::UnsafeIter, iter() method to various iterators
1 parent 4ae9aaa commit 6b79f32

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
@@ -2581,6 +2604,16 @@ pub struct IterMut<'a, T> {
25812604
inner: RawIter<T>,
25822605
marker: PhantomData<&'a mut T>,
25832606
}
2607+
impl<'a, T> IterMut<'a, T> {
2608+
/// Returns a iterator of references over the remaining items.
2609+
#[cfg_attr(feature = "inline-more", inline)]
2610+
pub fn iter(&self) -> Iter<'_, T> {
2611+
Iter {
2612+
inner: self.inner.clone(),
2613+
marker: PhantomData,
2614+
}
2615+
}
2616+
}
25842617

25852618
impl<T> Default for IterMut<'_, T> {
25862619
#[cfg_attr(feature = "inline-more", inline)]
@@ -2629,12 +2662,124 @@ where
26292662
T: fmt::Debug,
26302663
{
26312664
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2632-
f.debug_list()
2633-
.entries(Iter {
2634-
inner: self.inner.clone(),
2635-
marker: PhantomData,
2636-
})
2637-
.finish()
2665+
f.debug_list().entries(self.iter()).finish()
2666+
}
2667+
}
2668+
2669+
/// An unsafe iterator over the entries of a `HashTable` in arbitrary order.
2670+
/// The iterator element type is `NonNull<T>`.
2671+
///
2672+
/// This `struct` is created by the [`unsafe_iter`] method on [`HashTable`].
2673+
///
2674+
/// This is used for implementations of iterators with "mixed" mutability on
2675+
/// the iterated elements. For example, a mutable iterator for a map may return
2676+
/// an immutable key alongside a mutable value, even though these are both
2677+
/// stored inside the table.
2678+
///
2679+
/// If you have no idea what any of this means, you probably should be using
2680+
/// [`IterMut`] instead, as it does not have any safety requirements.
2681+
///
2682+
/// # Safety
2683+
///
2684+
/// In order to correctly use this iterator, it should be wrapped in a safe
2685+
/// iterator struct with the appropriate [`PhantomData`] marker to indicate the
2686+
/// correct [variance].
2687+
///
2688+
/// For example, below is a simplified [`hash_map::IterMut`] implementation
2689+
/// that correctly returns a [covariant] key, and an [invariant] value:
2690+
///
2691+
/// [variance]: https://doc.rust-lang.org/stable/reference/subtyping.html#r-subtyping.variance
2692+
/// [covariant]: https://doc.rust-lang.org/stable/reference/subtyping.html#r-subtyping.variance.covariant
2693+
/// [invariant]: https://doc.rust-lang.org/stable/reference/subtyping.html#r-subtyping.variance.invariant
2694+
/// [`hash_map::IterMut`]: crate::hash_map::IterMut
2695+
///
2696+
/// ```rust
2697+
/// use core::marker::PhantomData;
2698+
/// use hashbrown::hash_table;
2699+
///
2700+
/// pub struct IterMut<'a, K, V> {
2701+
/// inner: hash_table::UnsafeIter<'a, (K, V)>,
2702+
/// // Covariant over keys, invariant over values
2703+
/// marker: PhantomData<(&'a K, &'a mut V)>,
2704+
/// }
2705+
/// impl<'a, K, V> Iterator for IterMut<'a, K, V> {
2706+
/// // Immutable keys, mutable values
2707+
/// type Item = (&'a K, &'a mut V);
2708+
///
2709+
/// fn next(&mut self) -> Option<Self::Item> {
2710+
/// // SAFETY: The lifetime of the dereferenced pointer is derived from
2711+
/// // the lifetime of its iterator, ensuring that it's always valid.
2712+
/// // Additionally, we match the mutability in `self.marker` to ensure
2713+
/// // the correct variance.
2714+
/// let (ref key, ref mut val) = unsafe { *self.inner.next() }?;
2715+
/// Some((key, val))
2716+
/// }
2717+
/// }
2718+
/// ```
2719+
pub struct UnsafeIter<'a, T> {
2720+
inner: RawIter<T>,
2721+
marker: PhantomData<&'a ()>,
2722+
}
2723+
impl<'a, T> UnsafeIter<'a, T> {
2724+
/// Returns a iterator of references over the remaining items.
2725+
#[cfg_attr(feature = "inline-more", inline)]
2726+
pub fn iter(&self) -> Iter<'_, T> {
2727+
Iter {
2728+
inner: self.inner.clone(),
2729+
marker: PhantomData,
2730+
}
2731+
}
2732+
}
2733+
2734+
impl<T> Default for UnsafeIter<'_, T> {
2735+
#[cfg_attr(feature = "inline-more", inline)]
2736+
fn default() -> Self {
2737+
UnsafeIter {
2738+
inner: Default::default(),
2739+
marker: PhantomData,
2740+
}
2741+
}
2742+
}
2743+
impl<'a, T> Iterator for UnsafeIter<'a, T> {
2744+
type Item = NonNull<T>;
2745+
2746+
fn next(&mut self) -> Option<Self::Item> {
2747+
// Avoid `Option::map` because it bloats LLVM IR.
2748+
match self.inner.next() {
2749+
Some(bucket) => Some(unsafe { NonNull::new_unchecked(bucket.as_ptr()) }),
2750+
None => None,
2751+
}
2752+
}
2753+
2754+
fn size_hint(&self) -> (usize, Option<usize>) {
2755+
self.inner.size_hint()
2756+
}
2757+
2758+
fn fold<B, F>(self, init: B, mut f: F) -> B
2759+
where
2760+
Self: Sized,
2761+
F: FnMut(B, Self::Item) -> B,
2762+
{
2763+
self.inner.fold(init, |acc, bucket| unsafe {
2764+
f(acc, NonNull::new_unchecked(bucket.as_ptr()))
2765+
})
2766+
}
2767+
}
2768+
2769+
impl<T> ExactSizeIterator for UnsafeIter<'_, T> {
2770+
fn len(&self) -> usize {
2771+
self.inner.len()
2772+
}
2773+
}
2774+
2775+
impl<T> FusedIterator for UnsafeIter<'_, T> {}
2776+
2777+
impl<T> fmt::Debug for UnsafeIter<'_, T>
2778+
where
2779+
T: fmt::Debug,
2780+
{
2781+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2782+
f.debug_list().entries(self.iter()).finish()
26382783
}
26392784
}
26402785

@@ -2888,6 +3033,19 @@ where
28883033
{
28893034
inner: RawIntoIter<T, A>,
28903035
}
3036+
impl<T, A> IntoIter<T, A>
3037+
where
3038+
A: Allocator,
3039+
{
3040+
/// Returns a iterator of references over the remaining items.
3041+
#[cfg_attr(feature = "inline-more", inline)]
3042+
pub fn iter(&self) -> Iter<'_, T> {
3043+
Iter {
3044+
inner: self.inner.iter(),
3045+
marker: PhantomData,
3046+
}
3047+
}
3048+
}
28913049

28923050
impl<T, A: Allocator> Default for IntoIter<T, A> {
28933051
#[cfg_attr(feature = "inline-more", inline)]
@@ -2938,12 +3096,7 @@ where
29383096
A: Allocator,
29393097
{
29403098
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2941-
f.debug_list()
2942-
.entries(Iter {
2943-
inner: self.inner.iter(),
2944-
marker: PhantomData,
2945-
})
2946-
.finish()
3099+
f.debug_list().entries(self.iter()).finish()
29473100
}
29483101
}
29493102

@@ -2957,6 +3110,16 @@ where
29573110
pub struct Drain<'a, T, A: Allocator = Global> {
29583111
inner: RawDrain<'a, T, A>,
29593112
}
3113+
impl<'a, T, A: Allocator> Drain<'a, T, A> {
3114+
/// Returns a iterator of references over the remaining items.
3115+
#[cfg_attr(feature = "inline-more", inline)]
3116+
pub fn iter(&self) -> Iter<'_, T> {
3117+
Iter {
3118+
inner: self.inner.iter(),
3119+
marker: PhantomData,
3120+
}
3121+
}
3122+
}
29603123

29613124
impl<T, A: Allocator> Iterator for Drain<'_, T, A> {
29623125
type Item = T;
@@ -2988,12 +3151,7 @@ impl<T, A: Allocator> FusedIterator for Drain<'_, T, A> {}
29883151

29893152
impl<T: fmt::Debug, A: Allocator> fmt::Debug for Drain<'_, T, A> {
29903153
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2991-
f.debug_list()
2992-
.entries(Iter {
2993-
inner: self.inner.iter(),
2994-
marker: PhantomData,
2995-
})
2996-
.finish()
3154+
f.debug_list().entries(self.iter()).finish()
29973155
}
29983156
}
29993157

0 commit comments

Comments
 (0)