@@ -838,6 +838,19 @@ impl<T, A: Allocator> RawTable<T, A> {
838838 ( item. read ( ) , self . bucket_index ( & item) )
839839 }
840840
841+ /// Removes an element from the table, returning it.
842+ ///
843+ /// This also returns an index to the newly free bucket
844+ /// and the former `Tag` for that bucket.
845+ #[ cfg_attr( feature = "inline-more" , inline) ]
846+ #[ allow( clippy:: needless_pass_by_value) ]
847+ pub ( crate ) unsafe fn remove_tagged ( & mut self , item : Bucket < T > ) -> ( T , usize , Tag ) {
848+ let index = self . bucket_index ( & item) ;
849+ let tag = * self . table . ctrl ( index) ;
850+ self . table . erase ( index) ;
851+ ( item. read ( ) , index, tag)
852+ }
853+
841854 /// Finds and removes an element from the table, returning it.
842855 #[ cfg_attr( feature = "inline-more" , inline) ]
843856 pub fn remove_entry ( & mut self , hash : u64 , eq : impl FnMut ( & T ) -> bool ) -> Option < T > {
@@ -1172,8 +1185,8 @@ impl<T, A: Allocator> RawTable<T, A> {
11721185 }
11731186 }
11741187
1175- /// Inserts a new element into the table at the given index, and returns its
1176- /// raw bucket.
1188+ /// Inserts a new element into the table at the given index with the given hash,
1189+ /// and returns its raw bucket.
11771190 ///
11781191 /// # Safety
11791192 ///
@@ -1182,8 +1195,26 @@ impl<T, A: Allocator> RawTable<T, A> {
11821195 /// occurred since that call.
11831196 #[ inline]
11841197 pub unsafe fn insert_at_index ( & mut self , hash : u64 , index : usize , value : T ) -> Bucket < T > {
1198+ self . insert_tagged_at_index ( Tag :: full ( hash) , index, value)
1199+ }
1200+
1201+ /// Inserts a new element into the table at the given index with the given tag,
1202+ /// and returns its raw bucket.
1203+ ///
1204+ /// # Safety
1205+ ///
1206+ /// `index` must point to a slot previously returned by
1207+ /// `find_or_find_insert_index`, and no mutation of the table must have
1208+ /// occurred since that call.
1209+ #[ inline]
1210+ pub ( crate ) unsafe fn insert_tagged_at_index (
1211+ & mut self ,
1212+ tag : Tag ,
1213+ index : usize ,
1214+ value : T ,
1215+ ) -> Bucket < T > {
11851216 let old_ctrl = * self . table . ctrl ( index) ;
1186- self . table . record_item_insert_at ( index, old_ctrl, hash ) ;
1217+ self . table . record_item_insert_at ( index, old_ctrl, tag ) ;
11871218
11881219 let bucket = self . bucket ( index) ;
11891220 bucket. write ( value) ;
@@ -1233,6 +1264,43 @@ impl<T, A: Allocator> RawTable<T, A> {
12331264 }
12341265 }
12351266
1267+ /// Gets a reference to an element in the table at the given bucket index.
1268+ #[ inline]
1269+ pub fn get_bucket ( & self , index : usize ) -> Option < & T > {
1270+ unsafe {
1271+ if index < self . buckets ( ) && self . is_bucket_full ( index) {
1272+ Some ( self . bucket ( index) . as_ref ( ) )
1273+ } else {
1274+ None
1275+ }
1276+ }
1277+ }
1278+
1279+ /// Gets a mutable reference to an element in the table at the given bucket index.
1280+ #[ inline]
1281+ pub fn get_bucket_mut ( & mut self , index : usize ) -> Option < & mut T > {
1282+ unsafe {
1283+ if index < self . buckets ( ) && self . is_bucket_full ( index) {
1284+ Some ( self . bucket ( index) . as_mut ( ) )
1285+ } else {
1286+ None
1287+ }
1288+ }
1289+ }
1290+
1291+ /// Returns a pointer to an element in the table, but only after verifying that
1292+ /// the index is in-bounds and the bucket is occupied.
1293+ #[ inline]
1294+ pub fn checked_bucket ( & self , index : usize ) -> Option < Bucket < T > > {
1295+ unsafe {
1296+ if index < self . buckets ( ) && self . is_bucket_full ( index) {
1297+ Some ( self . bucket ( index) )
1298+ } else {
1299+ None
1300+ }
1301+ }
1302+ }
1303+
12361304 /// Attempts to get mutable references to `N` entries in the table at once.
12371305 ///
12381306 /// Returns an array of length `N` with the results of each query.
@@ -1346,6 +1414,28 @@ impl<T, A: Allocator> RawTable<T, A> {
13461414 RawIterHash :: new ( self , hash)
13471415 }
13481416
1417+ /// Returns an iterator over occupied bucket indices that could match a given hash.
1418+ ///
1419+ /// `RawTable` only stores 7 bits of the hash value, so this iterator may
1420+ /// return items that have a hash value different than the one provided. You
1421+ /// should always validate the returned values before using them.
1422+ ///
1423+ /// It is up to the caller to ensure that the `RawTable` outlives the
1424+ /// `RawIterHashIndices`. Because we cannot make the `next` method unsafe on the
1425+ /// `RawIterHashIndices` struct, we have to make the `iter_hash_buckets` method unsafe.
1426+ #[ cfg_attr( feature = "inline-more" , inline) ]
1427+ pub ( crate ) unsafe fn iter_hash_buckets ( & self , hash : u64 ) -> RawIterHashIndices {
1428+ RawIterHashIndices :: new ( & self . table , hash)
1429+ }
1430+
1431+ /// Returns an iterator over full buckets indices in the table.
1432+ ///
1433+ /// See [`RawTableInner::full_buckets_indices`] for safety conditions.
1434+ #[ inline( always) ]
1435+ pub ( crate ) unsafe fn full_buckets_indices ( & self ) -> FullBucketsIndices {
1436+ self . table . full_buckets_indices ( )
1437+ }
1438+
13491439 /// Returns an iterator which removes all elements from the table without
13501440 /// freeing the memory.
13511441 #[ cfg_attr( feature = "inline-more" , inline) ]
@@ -2405,9 +2495,9 @@ impl RawTableInner {
24052495 }
24062496
24072497 #[ inline]
2408- unsafe fn record_item_insert_at ( & mut self , index : usize , old_ctrl : Tag , hash : u64 ) {
2498+ unsafe fn record_item_insert_at ( & mut self , index : usize , old_ctrl : Tag , new_ctrl : Tag ) {
24092499 self . growth_left -= usize:: from ( old_ctrl. special_is_empty ( ) ) ;
2410- self . set_ctrl_hash ( index, hash ) ;
2500+ self . set_ctrl ( index, new_ctrl ) ;
24112501 self . items += 1 ;
24122502 }
24132503
@@ -3803,6 +3893,7 @@ impl<T> FusedIterator for RawIter<T> {}
38033893/// created will be yielded by that iterator.
38043894/// - The order in which the iterator yields indices of the buckets is unspecified
38053895/// and may change in the future.
3896+ #[ derive( Clone ) ]
38063897pub ( crate ) struct FullBucketsIndices {
38073898 // Mask of full buckets in the current group. Bits are cleared from this
38083899 // mask as each element is processed.
@@ -3820,6 +3911,14 @@ pub(crate) struct FullBucketsIndices {
38203911 items : usize ,
38213912}
38223913
3914+ impl Default for FullBucketsIndices {
3915+ #[ cfg_attr( feature = "inline-more" , inline) ]
3916+ fn default ( ) -> Self {
3917+ // SAFETY: Because the table is static, it always outlives the iter.
3918+ unsafe { RawTableInner :: NEW . full_buckets_indices ( ) }
3919+ }
3920+ }
3921+
38233922impl FullBucketsIndices {
38243923 /// Advances the iterator and returns the next value.
38253924 ///
@@ -4085,12 +4184,12 @@ impl<T, A: Allocator> FusedIterator for RawDrain<'_, T, A> {}
40854184/// - The order in which the iterator yields buckets is unspecified and may
40864185/// change in the future.
40874186pub struct RawIterHash < T > {
4088- inner : RawIterHashInner ,
4187+ inner : RawIterHashIndices ,
40894188 _marker : PhantomData < T > ,
40904189}
40914190
40924191#[ derive( Clone ) ]
4093- struct RawIterHashInner {
4192+ pub ( crate ) struct RawIterHashIndices {
40944193 // See `RawTableInner`'s corresponding fields for details.
40954194 // We can't store a `*const RawTableInner` as it would get
40964195 // invalidated by the user calling `&mut` methods on `RawTable`.
@@ -4113,7 +4212,7 @@ impl<T> RawIterHash<T> {
41134212 #[ cfg_attr( feature = "inline-more" , inline) ]
41144213 unsafe fn new < A : Allocator > ( table : & RawTable < T , A > , hash : u64 ) -> Self {
41154214 RawIterHash {
4116- inner : RawIterHashInner :: new ( & table. table , hash) ,
4215+ inner : RawIterHashIndices :: new ( & table. table , hash) ,
41174216 _marker : PhantomData ,
41184217 }
41194218 }
@@ -4133,22 +4232,29 @@ impl<T> Default for RawIterHash<T> {
41334232 #[ cfg_attr( feature = "inline-more" , inline) ]
41344233 fn default ( ) -> Self {
41354234 Self {
4136- // SAFETY: Because the table is static, it always outlives the iter.
4137- inner : unsafe { RawIterHashInner :: new ( & RawTableInner :: NEW , 0 ) } ,
4235+ inner : RawIterHashIndices :: default ( ) ,
41384236 _marker : PhantomData ,
41394237 }
41404238 }
41414239}
41424240
4143- impl RawIterHashInner {
4241+ impl Default for RawIterHashIndices {
4242+ #[ cfg_attr( feature = "inline-more" , inline) ]
4243+ fn default ( ) -> Self {
4244+ // SAFETY: Because the table is static, it always outlives the iter.
4245+ unsafe { RawIterHashIndices :: new ( & RawTableInner :: NEW , 0 ) }
4246+ }
4247+ }
4248+
4249+ impl RawIterHashIndices {
41444250 #[ cfg_attr( feature = "inline-more" , inline) ]
41454251 unsafe fn new ( table : & RawTableInner , hash : u64 ) -> Self {
41464252 let tag_hash = Tag :: full ( hash) ;
41474253 let probe_seq = table. probe_seq ( hash) ;
41484254 let group = Group :: load ( table. ctrl ( probe_seq. pos ) ) ;
41494255 let bitmask = group. match_tag ( tag_hash) . into_iter ( ) ;
41504256
4151- RawIterHashInner {
4257+ RawIterHashIndices {
41524258 bucket_mask : table. bucket_mask ,
41534259 ctrl : table. ctrl ,
41544260 tag_hash,
@@ -4178,7 +4284,7 @@ impl<T> Iterator for RawIterHash<T> {
41784284 }
41794285}
41804286
4181- impl Iterator for RawIterHashInner {
4287+ impl Iterator for RawIterHashIndices {
41824288 type Item = usize ;
41834289
41844290 fn next ( & mut self ) -> Option < Self :: Item > {
0 commit comments