@@ -15,7 +15,7 @@ enum VacantEntryKind<'a, T> {
15
15
/// It is part of the [`Entry`] enum.
16
16
// SAFETY: The kind accurately describes the state of the subtable.
17
17
pub struct VacantEntry < ' a , T > {
18
- tables : & ' a mut TableSeq < T > ,
18
+ tables : * mut TableSeq < T > ,
19
19
subtable : usize ,
20
20
kind : VacantEntryKind < ' a , T > ,
21
21
}
@@ -26,14 +26,15 @@ enum OccupiedEntryKind<'a, T> {
26
26
PairTable ( usize ) ,
27
27
// On both SmallTable and LargeTable the `bool` is true iff the OccupiedEntry is the only entry in the table.
28
28
SmallTable ( SmallSubtableOccupiedEntry < ' a , T > , bool ) ,
29
- LargeTable ( hashbrown:: hash_table:: OccupiedEntry < ' a , T > , bool ) ,
29
+ // We need MaybeUninit here because we may deallocate the HashTable, at which point the OccupiedEntry becomes invalid.
30
+ LargeTable ( MaybeUninit < hashbrown:: hash_table:: OccupiedEntry < ' a , T > > , bool ) ,
30
31
}
31
32
32
33
/// A view into an occupied entry in a [`TableSeq`]'s subtable.
33
34
/// It is part of the [`Entry`] enum.
34
35
// SAFETY: The kind accurately describes the state of the subtable.
35
36
pub struct OccupiedEntry < ' a , T > {
36
- tables : & ' a mut TableSeq < T > ,
37
+ tables : * mut TableSeq < T > ,
37
38
subtable : usize ,
38
39
entry_ptr : * mut T ,
39
40
kind : OccupiedEntryKind < ' a , T > ,
@@ -154,7 +155,7 @@ impl<T> TableSeq<T> {
154
155
tables : self ,
155
156
subtable,
156
157
entry_ptr : & mut * entry. get_mut ( ) ,
157
- kind : OccupiedEntryKind :: LargeTable ( entry, is_single)
158
+ kind : OccupiedEntryKind :: LargeTable ( MaybeUninit :: new ( entry) , is_single)
158
159
} ) ,
159
160
hashbrown:: hash_table:: Entry :: Vacant ( entry) =>
160
161
Entry :: Vacant ( VacantEntry {
@@ -228,11 +229,11 @@ impl<'a, T> VacantEntry<'a, T> {
228
229
let chunk_index = self . subtable >> CHUNK_SHIFT ;
229
230
let allocator_index = self . subtable >> ALLOCATOR_SHIFT ;
230
231
231
- let chunk_alloc = unsafe { tables. allocators . get_unchecked_mut ( allocator_index) } ;
232
- let chunk = unsafe { tables. chunks . get_unchecked_mut ( chunk_index) } ;
232
+ let chunk_alloc = unsafe { ( * tables) . allocators . get_unchecked_mut ( allocator_index) } ;
233
+ let chunk = unsafe { ( * tables) . chunks . get_unchecked_mut ( chunk_index) } ;
233
234
match kind {
234
235
VacantEntryKind :: EmptyChunk => unsafe {
235
- tables. entries += 1 ;
236
+ ( * tables) . entries += 1 ;
236
237
let size_class = SizeClass :: class_for_index ( 0 ) ;
237
238
238
239
chunk. node = chunk_alloc. alloc ( size_class) ;
@@ -247,7 +248,7 @@ impl<'a, T> VacantEntry<'a, T> {
247
248
}
248
249
} ,
249
250
VacantEntryKind :: EmptyTable => unsafe {
250
- tables. entries += 1 ;
251
+ ( * tables) . entries += 1 ;
251
252
let mut node = chunk. node ( chunk_alloc) ;
252
253
253
254
let entry_offset = chunk. meta . entry_offset ( chunk_slot) ;
@@ -267,7 +268,7 @@ impl<'a, T> VacantEntry<'a, T> {
267
268
VacantEntryKind :: SingletonTable => unsafe {
268
269
let mut node = chunk. node ( chunk_alloc) ;
269
270
let entry_offset = chunk. meta . entry_offset ( chunk_slot) ;
270
- tables. entries += 1 ;
271
+ ( * tables) . entries += 1 ;
271
272
272
273
node. make_entry_gap_resize ( entry_offset, chunk, chunk_alloc) ;
273
274
@@ -285,7 +286,7 @@ impl<'a, T> VacantEntry<'a, T> {
285
286
VacantEntryKind :: PairTable ( hash, pair_hashes) => unsafe {
286
287
let mut node = chunk. node ( chunk_alloc) ;
287
288
let entry_offset = chunk. meta . entry_offset ( chunk_slot) ;
288
- tables. entries += 1 ;
289
+ ( * tables) . entries += 1 ;
289
290
290
291
let found_pair = node. entry_ptr ( entry_offset) . cast :: < [ T ; 2 ] > ( ) . read ( ) ;
291
292
let table_offset = chunk. meta . table_offset ( chunk_slot) ;
@@ -299,7 +300,7 @@ impl<'a, T> VacantEntry<'a, T> {
299
300
300
301
let table_ptr = node. table_ptr ( table_offset) ;
301
302
302
- let table_alloc = & mut tables. allocators [ allocator_index ^ 1 ] ;
303
+ let table_alloc = & mut ( * tables) . allocators [ allocator_index ^ 1 ] ;
303
304
let ( entry_ptr, table) =
304
305
SmallSubtable :: new ( found_pair, pair_hashes, value, hash, table_alloc) ;
305
306
@@ -317,9 +318,9 @@ impl<'a, T> VacantEntry<'a, T> {
317
318
}
318
319
} ,
319
320
VacantEntryKind :: SmallTable ( vacant_entry) => {
320
- let table_alloc = & mut tables. allocators [ allocator_index ^ 1 ] ;
321
+ let table_alloc = unsafe { & mut ( * tables) . allocators [ allocator_index ^ 1 ] } ;
321
322
let mut new_entry = unsafe { vacant_entry. insert ( value, table_alloc) } ;
322
- tables. entries += 1 ;
323
+ unsafe { ( * tables) . entries += 1 } ;
323
324
OccupiedEntry {
324
325
tables,
325
326
subtable,
@@ -329,20 +330,20 @@ impl<'a, T> VacantEntry<'a, T> {
329
330
} ,
330
331
VacantEntryKind :: LargeTable ( vacant_entry) => {
331
332
let mut new_entry = vacant_entry. insert ( value) ;
332
- tables. entries += 1 ;
333
+ unsafe { ( * tables) . entries += 1 } ;
333
334
OccupiedEntry {
334
335
tables,
335
336
subtable,
336
337
entry_ptr : & mut * new_entry. get_mut ( ) ,
337
- kind : OccupiedEntryKind :: LargeTable ( new_entry, false )
338
+ kind : OccupiedEntryKind :: LargeTable ( MaybeUninit :: new ( new_entry) , false )
338
339
}
339
340
} ,
340
341
}
341
342
}
342
343
343
344
/// Converts the `VacantEntry` into a mutable reference to the underlying `TableSeq`.
344
345
pub fn into_tables ( self ) -> & ' a mut TableSeq < T > {
345
- self . tables
346
+ unsafe { & mut * self . tables }
346
347
}
347
348
/// Returns the subtable index of the `VacantEntry`.
348
349
pub fn subtable ( & self ) -> usize {
@@ -365,7 +366,7 @@ impl<'a, T> OccupiedEntry<'a, T> {
365
366
}
366
367
/// Converts the `OccupiedEntry` into a mutable reference to the underlying `TableSeq`.
367
368
pub fn into_tables ( self ) -> & ' a mut TableSeq < T > {
368
- self . tables
369
+ unsafe { & mut * self . tables }
369
370
}
370
371
/// Returns the subtable index of the `OccupiedEntry`.
371
372
pub fn subtable ( & self ) -> usize {
@@ -378,15 +379,15 @@ impl<'a, T> OccupiedEntry<'a, T> {
378
379
let chunk_index = subtable >> CHUNK_SHIFT ;
379
380
let allocator_index = subtable >> ALLOCATOR_SHIFT ;
380
381
381
- let chunk = unsafe { tables. chunks . get_unchecked_mut ( chunk_index) } ;
382
- let chunk_alloc = unsafe { tables. allocators . get_unchecked_mut ( allocator_index) } ;
382
+ let chunk = unsafe { ( * tables) . chunks . get_unchecked_mut ( chunk_index) } ;
383
+ let chunk_alloc = unsafe { ( * tables) . allocators . get_unchecked_mut ( allocator_index) } ;
383
384
384
385
match kind {
385
386
OccupiedEntryKind :: SingletonTable => unsafe {
386
387
let mut node = chunk. node ( chunk_alloc) ;
387
388
let entry_offset = chunk. meta . entry_offset ( chunk_slot) ;
388
389
389
- tables. entries -= 1 ;
390
+ ( * tables) . entries -= 1 ;
390
391
let value = entry_ptr. read ( ) ;
391
392
392
393
node. close_entry_gap_resize ( entry_offset, chunk, chunk_alloc) ;
@@ -404,7 +405,7 @@ impl<'a, T> OccupiedEntry<'a, T> {
404
405
let mut node = chunk. node ( chunk_alloc) ;
405
406
let entry_offset = chunk. meta . entry_offset ( chunk_slot) + index;
406
407
407
- tables. entries -= 1 ;
408
+ ( * tables) . entries -= 1 ;
408
409
let value = entry_ptr. read ( ) ;
409
410
410
411
node. close_entry_gap_resize ( entry_offset, chunk, chunk_alloc) ;
@@ -414,8 +415,8 @@ impl<'a, T> OccupiedEntry<'a, T> {
414
415
} ,
415
416
OccupiedEntryKind :: SmallTable ( entry, will_delete) => unsafe {
416
417
let mut node = chunk. node ( chunk_alloc) ;
417
- let table_alloc = & mut tables. allocators [ allocator_index ^ 1 ] ;
418
- tables. entries -= 1 ;
418
+ let table_alloc = & mut ( * tables) . allocators [ allocator_index ^ 1 ] ;
419
+ ( * tables) . entries -= 1 ;
419
420
let ( removed, entry) = entry. remove ( table_alloc) ;
420
421
421
422
// TODO earlier shrinking
@@ -424,7 +425,7 @@ impl<'a, T> OccupiedEntry<'a, T> {
424
425
let table_offset = chunk. meta . table_offset ( chunk_slot) ;
425
426
table. drop_and_dealloc ( table_alloc) ;
426
427
let chunk_alloc =
427
- tables. allocators . get_unchecked_mut ( allocator_index) ;
428
+ ( * tables) . allocators . get_unchecked_mut ( allocator_index) ;
428
429
node. close_table_gap_resize ( table_offset, chunk, chunk_alloc) ;
429
430
chunk. meta . make_empty ( chunk_slot) ;
430
431
if chunk. meta . is_empty ( ) {
@@ -439,8 +440,8 @@ impl<'a, T> OccupiedEntry<'a, T> {
439
440
( removed, VacantEntry { tables, subtable, kind } )
440
441
} ,
441
442
OccupiedEntryKind :: LargeTable ( entry, will_delete) => unsafe {
442
- tables. entries -= 1 ;
443
- let ( removed, entry) = entry. remove ( ) ;
443
+ ( * tables) . entries -= 1 ;
444
+ let ( removed, entry) = entry. assume_init ( ) . remove ( ) ;
444
445
445
446
// TODO external -> internal shrinking
446
447
let kind = if will_delete {
0 commit comments