Skip to content

Commit f2f2882

Browse files
committed
Auto merge of #427 - moulins:lifetimeless-raw-iter-hash, r=Amanieu
Remove lifetime on RawIterHash, for more flexibility & to match RawIter Note: this is a breaking change. I've also copied the documentation of `RawIter`, with some minor adjustments. Closes #415.
2 parents 4ba7f33 + 3002488 commit f2f2882

File tree

1 file changed

+55
-28
lines changed

1 file changed

+55
-28
lines changed

src/raw/mod.rs

Lines changed: 55 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1420,7 +1420,7 @@ impl<T, A: Allocator + Clone> RawTable<T, A> {
14201420
/// `RawIterHash` struct, we have to make the `iter_hash` method unsafe.
14211421
#[cfg_attr(feature = "inline-more", inline)]
14221422
#[cfg(feature = "raw")]
1423-
pub unsafe fn iter_hash(&self, hash: u64) -> RawIterHash<'_, T, A> {
1423+
pub unsafe fn iter_hash(&self, hash: u64) -> RawIterHash<T> {
14241424
RawIterHash::new(self, hash)
14251425
}
14261426

@@ -3203,13 +3203,28 @@ impl<T, A: Allocator + Clone> FusedIterator for RawDrain<'_, T, A> {}
32033203
/// `RawTable` only stores 7 bits of the hash value, so this iterator may return
32043204
/// items that have a hash value different than the one provided. You should
32053205
/// always validate the returned values before using them.
3206-
pub struct RawIterHash<'a, T, A: Allocator + Clone = Global> {
3207-
inner: RawIterHashInner<'a, A>,
3206+
///
3207+
/// For maximum flexibility this iterator is not bound by a lifetime, but you
3208+
/// must observe several rules when using it:
3209+
/// - You must not free the hash table while iterating (including via growing/shrinking).
3210+
/// - It is fine to erase a bucket that has been yielded by the iterator.
3211+
/// - Erasing a bucket that has not yet been yielded by the iterator may still
3212+
/// result in the iterator yielding that bucket.
3213+
/// - It is unspecified whether an element inserted after the iterator was
3214+
/// created will be yielded by that iterator.
3215+
/// - The order in which the iterator yields buckets is unspecified and may
3216+
/// change in the future.
3217+
pub struct RawIterHash<T> {
3218+
inner: RawIterHashInner,
32083219
_marker: PhantomData<T>,
32093220
}
32103221

3211-
struct RawIterHashInner<'a, A: Allocator + Clone> {
3212-
table: &'a RawTableInner<A>,
3222+
struct RawIterHashInner {
3223+
// See `RawTableInner`'s corresponding fields for details.
3224+
// We can't store a `*const RawTableInner` as it would get
3225+
// invalidated by the user calling `&mut` methods on `RawTable`.
3226+
bucket_mask: usize,
3227+
ctrl: NonNull<u8>,
32133228

32143229
// The top 7 bits of the hash.
32153230
h2_hash: u8,
@@ -3223,65 +3238,77 @@ struct RawIterHashInner<'a, A: Allocator + Clone> {
32233238
bitmask: BitMaskIter,
32243239
}
32253240

3226-
impl<'a, T, A: Allocator + Clone> RawIterHash<'a, T, A> {
3241+
impl<T> RawIterHash<T> {
32273242
#[cfg_attr(feature = "inline-more", inline)]
32283243
#[cfg(feature = "raw")]
3229-
fn new(table: &'a RawTable<T, A>, hash: u64) -> Self {
3244+
unsafe fn new<A: Allocator + Clone>(table: &RawTable<T, A>, hash: u64) -> Self {
32303245
RawIterHash {
32313246
inner: RawIterHashInner::new(&table.table, hash),
32323247
_marker: PhantomData,
32333248
}
32343249
}
32353250
}
3236-
impl<'a, A: Allocator + Clone> RawIterHashInner<'a, A> {
3251+
impl RawIterHashInner {
32373252
#[cfg_attr(feature = "inline-more", inline)]
32383253
#[cfg(feature = "raw")]
3239-
fn new(table: &'a RawTableInner<A>, hash: u64) -> Self {
3240-
unsafe {
3241-
let h2_hash = h2(hash);
3242-
let probe_seq = table.probe_seq(hash);
3243-
let group = Group::load(table.ctrl(probe_seq.pos));
3244-
let bitmask = group.match_byte(h2_hash).into_iter();
3245-
3246-
RawIterHashInner {
3247-
table,
3248-
h2_hash,
3249-
probe_seq,
3250-
group,
3251-
bitmask,
3252-
}
3254+
unsafe fn new<A: Allocator + Clone>(table: &RawTableInner<A>, hash: u64) -> Self {
3255+
let h2_hash = h2(hash);
3256+
let probe_seq = table.probe_seq(hash);
3257+
let group = Group::load(table.ctrl(probe_seq.pos));
3258+
let bitmask = group.match_byte(h2_hash).into_iter();
3259+
3260+
RawIterHashInner {
3261+
bucket_mask: table.bucket_mask,
3262+
ctrl: table.ctrl,
3263+
h2_hash,
3264+
probe_seq,
3265+
group,
3266+
bitmask,
32533267
}
32543268
}
32553269
}
32563270

3257-
impl<'a, T, A: Allocator + Clone> Iterator for RawIterHash<'a, T, A> {
3271+
impl<T> Iterator for RawIterHash<T> {
32583272
type Item = Bucket<T>;
32593273

32603274
fn next(&mut self) -> Option<Bucket<T>> {
32613275
unsafe {
32623276
match self.inner.next() {
3263-
Some(index) => Some(self.inner.table.bucket(index)),
3277+
Some(index) => {
3278+
// Can't use `RawTable::bucket` here as we don't have
3279+
// an actual `RawTable` reference to use.
3280+
debug_assert!(index <= self.inner.bucket_mask);
3281+
let bucket = Bucket::from_base_index(self.inner.ctrl.cast(), index);
3282+
Some(bucket)
3283+
}
32643284
None => None,
32653285
}
32663286
}
32673287
}
32683288
}
32693289

3270-
impl<'a, A: Allocator + Clone> Iterator for RawIterHashInner<'a, A> {
3290+
impl Iterator for RawIterHashInner {
32713291
type Item = usize;
32723292

32733293
fn next(&mut self) -> Option<Self::Item> {
32743294
unsafe {
32753295
loop {
32763296
if let Some(bit) = self.bitmask.next() {
3277-
let index = (self.probe_seq.pos + bit) & self.table.bucket_mask;
3297+
let index = (self.probe_seq.pos + bit) & self.bucket_mask;
32783298
return Some(index);
32793299
}
32803300
if likely(self.group.match_empty().any_bit_set()) {
32813301
return None;
32823302
}
3283-
self.probe_seq.move_next(self.table.bucket_mask);
3284-
self.group = Group::load(self.table.ctrl(self.probe_seq.pos));
3303+
self.probe_seq.move_next(self.bucket_mask);
3304+
3305+
// Can't use `RawTableInner::ctrl` here as we don't have
3306+
// an actual `RawTableInner` reference to use.
3307+
let index = self.probe_seq.pos;
3308+
debug_assert!(index < self.bucket_mask + 1 + Group::WIDTH);
3309+
let group_ctrl = self.ctrl.as_ptr().add(index);
3310+
3311+
self.group = Group::load(group_ctrl);
32853312
self.bitmask = self.group.match_byte(self.h2_hash).into_iter();
32863313
}
32873314
}

0 commit comments

Comments
 (0)