@@ -102,19 +102,6 @@ impl<T> RawVec<T, Global> {
102
102
}
103
103
104
104
impl < T , A : Allocator > RawVec < T , A > {
105
- // Tiny Vecs are dumb. Skip to:
106
- // - 8 if the element size is 1, because any heap allocators is likely
107
- // to round up a request of less than 8 bytes to at least 8 bytes.
108
- // - 4 if elements are moderate-sized (<= 1 KiB).
109
- // - 1 otherwise, to avoid wasting too much space for very short Vecs.
110
- const MIN_NON_ZERO_CAP : usize = if mem:: size_of :: < T > ( ) == 1 {
111
- 8
112
- } else if mem:: size_of :: < T > ( ) <= 1024 {
113
- 4
114
- } else {
115
- 1
116
- } ;
117
-
118
105
/// Like `new`, but parameterized over the choice of allocator for
119
106
/// the returned `RawVec`.
120
107
#[ rustc_allow_const_fn_unstable( const_fn) ]
@@ -381,22 +368,16 @@ impl<T, A: Allocator> RawVec<T, A> {
381
368
// of the code that doesn't depend on `T` as possible is in functions that
382
369
// are non-generic over `T`.
383
370
fn grow_amortized ( & mut self , len : usize , additional : usize ) -> Result < ( ) , TryReserveError > {
384
- // This is ensured by the calling contexts.
385
- debug_assert ! ( additional > 0 ) ;
386
-
387
- // Nothing we can really do about these checks, sadly. (If this method
388
- // is called for a zero-sized `T` after `needs_to_grow()` has
389
- // succeeded, this early return will occur.)
390
- let required_cap = len. checked_add ( additional) . ok_or ( CapacityOverflow ) ?;
391
-
392
- // This guarantees exponential growth. The doubling cannot overflow
393
- // because `cap <= isize::MAX` and the type of `cap` is `usize`.
394
- let cap = cmp:: max ( self . cap * 2 , required_cap) ;
395
- let cap = cmp:: max ( Self :: MIN_NON_ZERO_CAP , cap) ;
396
-
397
- // `finish_grow` is non-generic over `T`.
371
+ // `finish_grow_amortized` is non-generic over `T`.
398
372
let elem_layout = Layout :: new :: < T > ( ) ;
399
- let ptr = finish_grow ( cap, elem_layout, self . current_memory ( ) , & mut self . alloc ) ?;
373
+ let ptr = finish_grow_amortized (
374
+ len,
375
+ additional,
376
+ elem_layout,
377
+ self . cap ,
378
+ self . current_memory ( ) ,
379
+ & mut self . alloc ,
380
+ ) ?;
400
381
self . set_ptr ( ptr) ;
401
382
Ok ( ( ) )
402
383
}
@@ -409,14 +390,15 @@ impl<T, A: Allocator> RawVec<T, A> {
409
390
// `grow_amortized`, but this method is usually instantiated less often so
410
391
// it's less critical.
411
392
fn grow_exact ( & mut self , len : usize , additional : usize ) -> Result < ( ) , TryReserveError > {
412
- // Nothing we can really do about these checks, sadly. (If this method
413
- // is called for a zero-sized `T` after `needs_to_grow()` has
414
- // succeeded, this early return will occur.)
415
- let cap = len. checked_add ( additional) . ok_or ( CapacityOverflow ) ?;
416
-
417
- // `finish_grow` is non-generic over `T`.
393
+ // `finish_grow_exact` is non-generic over `T`.
418
394
let elem_layout = Layout :: new :: < T > ( ) ;
419
- let ptr = finish_grow ( cap, elem_layout, self . current_memory ( ) , & mut self . alloc ) ?;
395
+ let ptr = finish_grow_exact (
396
+ len,
397
+ additional,
398
+ elem_layout,
399
+ self . current_memory ( ) ,
400
+ & mut self . alloc ,
401
+ ) ?;
420
402
self . set_ptr ( ptr) ;
421
403
Ok ( ( ) )
422
404
}
@@ -443,15 +425,85 @@ impl<T, A: Allocator> RawVec<T, A> {
443
425
// significant, because the number of different `A` types seen in practice is
444
426
// much smaller than the number of `T` types.)
445
427
#[ inline( never) ]
446
- fn finish_grow < A > (
447
- cap : usize ,
428
+ fn finish_grow_amortized < A > (
429
+ len : usize ,
430
+ additional : usize ,
431
+ elem_layout : Layout ,
432
+ current_cap : usize ,
433
+ current_memory : Option < ( NonNull < u8 > , Layout ) > ,
434
+ alloc : & mut A ,
435
+ ) -> Result < NonNull < [ u8 ] > , TryReserveError >
436
+ where
437
+ A : Allocator ,
438
+ {
439
+ // This is ensured by the calling contexts.
440
+ debug_assert ! ( additional > 0 ) ;
441
+
442
+ // Tiny Vecs are dumb. Skip to:
443
+ // - 8 if the element size is 1, because any heap allocators is likely
444
+ // to round up a request of less than 8 bytes to at least 8 bytes.
445
+ // - 4 if elements are moderate-sized (<= 1 KiB).
446
+ // - 1 otherwise, to avoid wasting too much space for very short Vecs.
447
+ let min_non_zero_cap: usize = if elem_layout. size ( ) == 1 {
448
+ 8
449
+ } else if elem_layout. size ( ) <= 1024 {
450
+ 4
451
+ } else {
452
+ 1
453
+ } ;
454
+
455
+ // Nothing we can really do about these checks, sadly. (If this method
456
+ // is called for a zero-sized `T` after `needs_to_grow()` has
457
+ // succeeded, this early return will occur.)
458
+ let required_cap = len. checked_add ( additional) . ok_or ( CapacityOverflow ) ?;
459
+
460
+ // This guarantees exponential growth. The doubling cannot overflow
461
+ // because `cap <= isize::MAX` and the type of `cap` is `usize`.
462
+ let cap = cmp:: max ( current_cap * 2 , required_cap) ;
463
+ let cap = cmp:: max ( min_non_zero_cap, cap) ;
464
+
465
+ let array_size = elem_layout. size ( ) . checked_mul ( cap) . ok_or ( CapacityOverflow ) ?;
466
+ alloc_guard ( array_size) ?;
467
+
468
+ let new_layout = unsafe { Layout :: from_size_align_unchecked ( array_size, elem_layout. align ( ) ) } ;
469
+
470
+ let memory = if let Some ( ( ptr, old_layout) ) = current_memory {
471
+ debug_assert_eq ! ( old_layout. align( ) , new_layout. align( ) ) ;
472
+ unsafe {
473
+ // The allocator checks for alignment equality
474
+ intrinsics:: assume ( old_layout. align ( ) == new_layout. align ( ) ) ;
475
+ alloc. grow ( ptr, old_layout, new_layout)
476
+ }
477
+ } else {
478
+ alloc. allocate ( new_layout)
479
+ } ;
480
+
481
+ memory. map_err ( |_| AllocError { layout : new_layout, non_exhaustive : ( ) } . into ( ) )
482
+ }
483
+
484
+ // This function is outside `RawVec` to minimize compile times. See the comment
485
+ // above `RawVec::grow_exact` for details. (The `A` parameter isn't
486
+ // significant, because the number of different `A` types seen in practice is
487
+ // much smaller than the number of `T` types.)
488
+ #[ inline( never) ]
489
+ fn finish_grow_exact < A > (
490
+ len : usize ,
491
+ additional : usize ,
448
492
elem_layout : Layout ,
449
493
current_memory : Option < ( NonNull < u8 > , Layout ) > ,
450
494
alloc : & mut A ,
451
495
) -> Result < NonNull < [ u8 ] > , TryReserveError >
452
496
where
453
497
A : Allocator ,
454
498
{
499
+ // This is ensured by the calling contexts.
500
+ debug_assert ! ( additional > 0 ) ;
501
+
502
+ // Nothing we can really do about these checks, sadly. (If this method
503
+ // is called for a zero-sized `T` after `needs_to_grow()` has
504
+ // succeeded, this early return will occur.)
505
+ let cap = len. checked_add ( additional) . ok_or ( CapacityOverflow ) ?;
506
+
455
507
let array_size = elem_layout. size ( ) . checked_mul ( cap) . ok_or ( CapacityOverflow ) ?;
456
508
alloc_guard ( array_size) ?;
457
509
0 commit comments