@@ -240,6 +240,41 @@ fn calculate_layout<T>(buckets: usize) -> Option<(Layout, usize)> {
240
240
data. extend ( ctrl) . ok ( )
241
241
}
242
242
243
+ /// Helper which allows the max calculation for ctrl_align to be statically computed for each T
244
+ /// while keeping the rest of `calculate_layout_for` independent of `T`
245
+ #[ derive( Copy , Clone ) ]
246
+ struct TableLayout {
247
+ size : usize ,
248
+ ctrl_align : usize ,
249
+ }
250
+
251
+ impl TableLayout {
252
+ #[ inline]
253
+ fn new < T > ( ) -> Self {
254
+ let layout = Layout :: new :: < T > ( ) ;
255
+ Self {
256
+ size : layout. size ( ) ,
257
+ ctrl_align : usize:: max ( layout. align ( ) , Group :: WIDTH ) ,
258
+ }
259
+ }
260
+
261
+ #[ inline]
262
+ fn calculate_layout_for ( self , buckets : usize ) -> Option < ( Layout , usize ) > {
263
+ debug_assert ! ( buckets. is_power_of_two( ) ) ;
264
+
265
+ let TableLayout { size, ctrl_align } = self ;
266
+ // Manual layout calculation since Layout methods are not yet stable.
267
+ let ctrl_offset =
268
+ size. checked_mul ( buckets) ?. checked_add ( ctrl_align - 1 ) ? & !( ctrl_align - 1 ) ;
269
+ let len = ctrl_offset. checked_add ( buckets + Group :: WIDTH ) ?;
270
+
271
+ Some ( (
272
+ unsafe { Layout :: from_size_align_unchecked ( len, ctrl_align) } ,
273
+ ctrl_offset,
274
+ ) )
275
+ }
276
+ }
277
+
243
278
/// Returns a Layout which describes the allocation required for a hash table,
244
279
/// and the offset of the control bytes in the allocation.
245
280
/// (the offset is also one past last element of buckets)
@@ -248,26 +283,7 @@ fn calculate_layout<T>(buckets: usize) -> Option<(Layout, usize)> {
248
283
#[ cfg_attr( feature = "inline-more" , inline) ]
249
284
#[ cfg( not( feature = "nightly" ) ) ]
250
285
fn calculate_layout < T > ( buckets : usize ) -> Option < ( Layout , usize ) > {
251
- calculate_layout_for ( Layout :: new :: < T > ( ) , buckets)
252
- }
253
-
254
- #[ inline]
255
- fn calculate_layout_for ( layout : Layout , buckets : usize ) -> Option < ( Layout , usize ) > {
256
- debug_assert ! ( buckets. is_power_of_two( ) ) ;
257
-
258
- // Manual layout calculation since Layout methods are not yet stable.
259
- let ctrl_align = usize:: max ( layout. align ( ) , Group :: WIDTH ) ;
260
- let ctrl_offset = layout
261
- . size ( )
262
- . checked_mul ( buckets) ?
263
- . checked_add ( ctrl_align - 1 ) ?
264
- & !( ctrl_align - 1 ) ;
265
- let len = ctrl_offset. checked_add ( buckets + Group :: WIDTH ) ?;
266
-
267
- Some ( (
268
- unsafe { Layout :: from_size_align_unchecked ( len, ctrl_align) } ,
269
- ctrl_offset,
270
- ) )
286
+ TableLayout :: new :: < T > ( ) . calculate_layout_for ( buckets)
271
287
}
272
288
273
289
/// A reference to a hash table bucket containing a `T`.
@@ -411,7 +427,7 @@ impl<T> RawTable<T> {
411
427
debug_assert ! ( buckets. is_power_of_two( ) ) ;
412
428
413
429
Ok ( Self {
414
- table : RawTableInner :: new_uninitialized ( Layout :: new :: < T > ( ) , buckets, fallability) ?,
430
+ table : RawTableInner :: new_uninitialized ( TableLayout :: new :: < T > ( ) , buckets, fallability) ?,
415
431
marker : PhantomData ,
416
432
} )
417
433
}
@@ -424,7 +440,7 @@ impl<T> RawTable<T> {
424
440
) -> Result < Self , TryReserveError > {
425
441
Ok ( Self {
426
442
table : RawTableInner :: fallible_with_capacity (
427
- Layout :: new :: < T > ( ) ,
443
+ TableLayout :: new :: < T > ( ) ,
428
444
capacity,
429
445
fallability,
430
446
) ?,
@@ -452,7 +468,7 @@ impl<T> RawTable<T> {
452
468
/// Deallocates the table without dropping any entries.
453
469
#[ cfg_attr( feature = "inline-more" , inline) ]
454
470
unsafe fn free_buckets ( & mut self ) {
455
- self . table . free_buckets ( Layout :: new :: < T > ( ) )
471
+ self . table . free_buckets ( TableLayout :: new :: < T > ( ) )
456
472
}
457
473
458
474
/// Returns pointer to one past last element of data table.
@@ -719,7 +735,7 @@ impl<T> RawTable<T> {
719
735
unsafe {
720
736
let mut new_table =
721
737
self . table
722
- . prepare_resize ( Layout :: new :: < T > ( ) , capacity, fallability) ?;
738
+ . prepare_resize ( TableLayout :: new :: < T > ( ) , capacity, fallability) ?;
723
739
724
740
// Copy all elements to the new table.
725
741
for item in self . iter ( ) {
@@ -988,14 +1004,14 @@ impl RawTableInner {
988
1004
989
1005
#[ inline]
990
1006
unsafe fn new_uninitialized (
991
- t_layout : Layout ,
1007
+ table_layout : TableLayout ,
992
1008
buckets : usize ,
993
1009
fallability : Fallibility ,
994
1010
) -> Result < Self , TryReserveError > {
995
1011
debug_assert ! ( buckets. is_power_of_two( ) ) ;
996
1012
997
1013
// Avoid `Option::ok_or_else` because it bloats LLVM IR.
998
- let ( layout, ctrl_offset) = match calculate_layout_for ( t_layout , buckets) {
1014
+ let ( layout, ctrl_offset) = match table_layout . calculate_layout_for ( buckets) {
999
1015
Some ( lco) => lco,
1000
1016
None => return Err ( fallability. capacity_overflow ( ) ) ,
1001
1017
} ;
@@ -1016,7 +1032,7 @@ impl RawTableInner {
1016
1032
1017
1033
#[ inline]
1018
1034
fn fallible_with_capacity (
1019
- t_layout : Layout ,
1035
+ table_layout : TableLayout ,
1020
1036
capacity : usize ,
1021
1037
fallability : Fallibility ,
1022
1038
) -> Result < Self , TryReserveError > {
@@ -1027,7 +1043,7 @@ impl RawTableInner {
1027
1043
let buckets =
1028
1044
capacity_to_buckets ( capacity) . ok_or_else ( || fallability. capacity_overflow ( ) ) ?;
1029
1045
1030
- let result = Self :: new_uninitialized ( t_layout , buckets, fallability) ?;
1046
+ let result = Self :: new_uninitialized ( table_layout , buckets, fallability) ?;
1031
1047
result. ctrl ( 0 ) . write_bytes ( EMPTY , result. num_ctrl_bytes ( ) ) ;
1032
1048
1033
1049
Ok ( result)
@@ -1261,14 +1277,15 @@ impl RawTableInner {
1261
1277
#[ inline]
1262
1278
unsafe fn prepare_resize (
1263
1279
& self ,
1264
- layout_t : Layout ,
1280
+ table_layout : TableLayout ,
1265
1281
capacity : usize ,
1266
1282
fallability : Fallibility ,
1267
1283
) -> Result < crate :: scopeguard:: ScopeGuard < Self , impl FnMut ( & mut Self ) > , TryReserveError > {
1268
1284
debug_assert ! ( self . items <= capacity) ;
1269
1285
1270
1286
// Allocate and initialize the new table.
1271
- let mut new_table = RawTableInner :: fallible_with_capacity ( layout_t, capacity, fallability) ?;
1287
+ let mut new_table =
1288
+ RawTableInner :: fallible_with_capacity ( table_layout, capacity, fallability) ?;
1272
1289
new_table. growth_left -= self . items ;
1273
1290
new_table. items = self . items ;
1274
1291
@@ -1280,15 +1297,15 @@ impl RawTableInner {
1280
1297
// the comment at the bottom of this function.
1281
1298
Ok ( guard ( new_table, move |self_| {
1282
1299
if !self_. is_empty_singleton ( ) {
1283
- self_. free_buckets ( layout_t ) ;
1300
+ self_. free_buckets ( table_layout ) ;
1284
1301
}
1285
1302
} ) )
1286
1303
}
1287
1304
1288
1305
#[ inline]
1289
- unsafe fn free_buckets ( & mut self , t_layout : Layout ) {
1306
+ unsafe fn free_buckets ( & mut self , table_layout : TableLayout ) {
1290
1307
// Avoid `Option::unwrap_or_else` because it bloats LLVM IR.
1291
- let ( layout, ctrl_offset) = match calculate_layout_for ( t_layout , self . buckets ( ) ) {
1308
+ let ( layout, ctrl_offset) = match table_layout . calculate_layout_for ( self . buckets ( ) ) {
1292
1309
Some ( lco) => lco,
1293
1310
None => hint:: unreachable_unchecked ( ) ,
1294
1311
} ;
0 commit comments