@@ -15,6 +15,8 @@ use core::ptr::{self, Unique};
15
15
use core:: slice;
16
16
use heap:: { Alloc , Layout , Heap } ;
17
17
use super :: boxed:: Box ;
18
+ use super :: allocator:: CollectionAllocErr ;
19
+ use super :: allocator:: CollectionAllocErr :: * ;
18
20
19
21
/// A low-level utility for more ergonomically allocating, reallocating, and deallocating
20
22
/// a buffer of memory on the heap without having to worry about all the corner cases
@@ -84,7 +86,7 @@ impl<T, A: Alloc> RawVec<T, A> {
84
86
let elem_size = mem:: size_of :: < T > ( ) ;
85
87
86
88
let alloc_size = cap. checked_mul ( elem_size) . expect ( "capacity overflow" ) ;
87
- alloc_guard ( alloc_size) ;
89
+ alloc_guard ( alloc_size) . expect ( "capacity overflow" ) ;
88
90
89
91
// handles ZSTs and `cap = 0` alike
90
92
let ptr = if alloc_size == 0 {
@@ -308,7 +310,7 @@ impl<T, A: Alloc> RawVec<T, A> {
308
310
let new_cap = 2 * self . cap ;
309
311
let new_size = new_cap * elem_size;
310
312
let new_layout = Layout :: from_size_align_unchecked ( new_size, cur. align ( ) ) ;
311
- alloc_guard ( new_size) ;
313
+ alloc_guard ( new_size) . expect ( "capacity overflow" ) ;
312
314
let ptr_res = self . a . realloc ( self . ptr . as_ptr ( ) as * mut u8 ,
313
315
cur,
314
316
new_layout) ;
@@ -367,7 +369,7 @@ impl<T, A: Alloc> RawVec<T, A> {
367
369
// overflow and the alignment is sufficiently small.
368
370
let new_cap = 2 * self . cap ;
369
371
let new_size = new_cap * elem_size;
370
- alloc_guard ( new_size) ;
372
+ alloc_guard ( new_size) . expect ( "capacity overflow" ) ;
371
373
let ptr = self . ptr ( ) as * mut _ ;
372
374
let new_layout = Layout :: from_size_align_unchecked ( new_size, old_layout. align ( ) ) ;
373
375
match self . a . grow_in_place ( ptr, old_layout, new_layout) {
@@ -403,7 +405,9 @@ impl<T, A: Alloc> RawVec<T, A> {
403
405
/// # Aborts
404
406
///
405
407
/// Aborts on OOM
406
- pub fn reserve_exact ( & mut self , used_cap : usize , needed_extra_cap : usize ) {
408
+ pub fn try_reserve_exact ( & mut self , used_cap : usize , needed_extra_cap : usize )
409
+ -> Result < ( ) , CollectionAllocErr > {
410
+
407
411
unsafe {
408
412
// NOTE: we don't early branch on ZSTs here because we want this
409
413
// to actually catch "asking for more than usize::MAX" in that case.
@@ -413,43 +417,51 @@ impl<T, A: Alloc> RawVec<T, A> {
413
417
// Don't actually need any more capacity.
414
418
// Wrapping in case they gave a bad `used_cap`.
415
419
if self . cap ( ) . wrapping_sub ( used_cap) >= needed_extra_cap {
416
- return ;
420
+ return Ok ( ( ) ) ;
417
421
}
418
422
419
423
// Nothing we can really do about these checks :(
420
- let new_cap = used_cap. checked_add ( needed_extra_cap) . expect ( "capacity overflow" ) ;
421
- let new_layout = match Layout :: array :: < T > ( new_cap) {
422
- Some ( layout) => layout,
423
- None => panic ! ( "capacity overflow" ) ,
424
- } ;
425
- alloc_guard ( new_layout. size ( ) ) ;
424
+ let new_cap = used_cap. checked_add ( needed_extra_cap) . ok_or ( CapacityOverflow ) ?;
425
+ let new_layout = Layout :: array :: < T > ( new_cap) . ok_or ( CapacityOverflow ) ?;
426
+
427
+ alloc_guard ( new_layout. size ( ) ) ?;
428
+
426
429
let res = match self . current_layout ( ) {
427
430
Some ( layout) => {
428
431
let old_ptr = self . ptr . as_ptr ( ) as * mut u8 ;
429
432
self . a . realloc ( old_ptr, layout, new_layout)
430
433
}
431
434
None => self . a . alloc ( new_layout) ,
432
435
} ;
433
- let uniq = match res {
434
- Ok ( ptr) => Unique :: new_unchecked ( ptr as * mut T ) ,
435
- Err ( e) => self . a . oom ( e) ,
436
- } ;
437
- self . ptr = uniq;
436
+
437
+ self . ptr = Unique :: new_unchecked ( res? as * mut T ) ;
438
438
self . cap = new_cap;
439
+
440
+ Ok ( ( ) )
441
+ }
442
+ }
443
+
444
+ /// The same as try_reserve_exact, but errors are lowered to a call to oom().
445
+ pub fn reserve_exact ( & mut self , used_cap : usize , needed_extra_cap : usize ) {
446
+ match self . try_reserve_exact ( used_cap, needed_extra_cap) {
447
+ Err ( CapacityOverflow ) => panic ! ( "capacity overflow" ) ,
448
+ Err ( AllocErr ( e) ) => self . a . oom ( e) ,
449
+ Ok ( ( ) ) => { /* yay */ }
439
450
}
440
451
}
441
452
442
453
/// Calculates the buffer's new size given that it'll hold `used_cap +
443
454
/// needed_extra_cap` elements. This logic is used in amortized reserve methods.
444
455
/// Returns `(new_capacity, new_alloc_size)`.
445
- fn amortized_new_size ( & self , used_cap : usize , needed_extra_cap : usize ) -> usize {
456
+ fn amortized_new_size ( & self , used_cap : usize , needed_extra_cap : usize )
457
+ -> Result < usize , CollectionAllocErr > {
458
+
446
459
// Nothing we can really do about these checks :(
447
- let required_cap = used_cap. checked_add ( needed_extra_cap)
448
- . expect ( "capacity overflow" ) ;
460
+ let required_cap = used_cap. checked_add ( needed_extra_cap) . ok_or ( CapacityOverflow ) ?;
449
461
// Cannot overflow, because `cap <= isize::MAX`, and type of `cap` is `usize`.
450
462
let double_cap = self . cap * 2 ;
451
463
// `double_cap` guarantees exponential growth.
452
- cmp:: max ( double_cap, required_cap)
464
+ Ok ( cmp:: max ( double_cap, required_cap) )
453
465
}
454
466
455
467
/// Ensures that the buffer contains at least enough space to hold
@@ -504,7 +516,8 @@ impl<T, A: Alloc> RawVec<T, A> {
504
516
/// # vector.push_all(&[1, 3, 5, 7, 9]);
505
517
/// # }
506
518
/// ```
507
- pub fn reserve ( & mut self , used_cap : usize , needed_extra_cap : usize ) {
519
+ pub fn try_reserve ( & mut self , used_cap : usize , needed_extra_cap : usize )
520
+ -> Result < ( ) , CollectionAllocErr > {
508
521
unsafe {
509
522
// NOTE: we don't early branch on ZSTs here because we want this
510
523
// to actually catch "asking for more than usize::MAX" in that case.
@@ -514,30 +527,36 @@ impl<T, A: Alloc> RawVec<T, A> {
514
527
// Don't actually need any more capacity.
515
528
// Wrapping in case they give a bad `used_cap`
516
529
if self . cap ( ) . wrapping_sub ( used_cap) >= needed_extra_cap {
517
- return ;
530
+ return Ok ( ( ) ) ;
518
531
}
519
532
520
- let new_cap = self . amortized_new_size ( used_cap, needed_extra_cap) ;
533
+ let new_cap = self . amortized_new_size ( used_cap, needed_extra_cap) ?;
534
+ let new_layout = Layout :: array :: < T > ( new_cap) . ok_or ( CapacityOverflow ) ?;
521
535
522
- let new_layout = match Layout :: array :: < T > ( new_cap) {
523
- Some ( layout) => layout,
524
- None => panic ! ( "capacity overflow" ) ,
525
- } ;
526
536
// FIXME: may crash and burn on over-reserve
527
- alloc_guard ( new_layout. size ( ) ) ;
537
+ alloc_guard ( new_layout. size ( ) ) ?;
538
+
528
539
let res = match self . current_layout ( ) {
529
540
Some ( layout) => {
530
541
let old_ptr = self . ptr . as_ptr ( ) as * mut u8 ;
531
542
self . a . realloc ( old_ptr, layout, new_layout)
532
543
}
533
544
None => self . a . alloc ( new_layout) ,
534
545
} ;
535
- let uniq = match res {
536
- Ok ( ptr) => Unique :: new_unchecked ( ptr as * mut T ) ,
537
- Err ( e) => self . a . oom ( e) ,
538
- } ;
539
- self . ptr = uniq;
546
+
547
+ self . ptr = Unique :: new_unchecked ( res? as * mut T ) ;
540
548
self . cap = new_cap;
549
+
550
+ Ok ( ( ) )
551
+ }
552
+ }
553
+
554
+ /// The same as try_reserve, but errors are lowered to a call to oom().
555
+ pub fn reserve ( & mut self , used_cap : usize , needed_extra_cap : usize ) {
556
+ match self . try_reserve ( used_cap, needed_extra_cap) {
557
+ Err ( CapacityOverflow ) => panic ! ( "capacity overflow" ) ,
558
+ Err ( AllocErr ( e) ) => self . a . oom ( e) ,
559
+ Ok ( ( ) ) => { /* yay */ }
541
560
}
542
561
}
543
562
@@ -576,7 +595,8 @@ impl<T, A: Alloc> RawVec<T, A> {
576
595
return false ;
577
596
}
578
597
579
- let new_cap = self . amortized_new_size ( used_cap, needed_extra_cap) ;
598
+ let new_cap = self . amortized_new_size ( used_cap, needed_extra_cap)
599
+ . expect ( "capacity overflow" ) ;
580
600
581
601
// Here, `cap < used_cap + needed_extra_cap <= new_cap`
582
602
// (regardless of whether `self.cap - used_cap` wrapped).
@@ -585,7 +605,7 @@ impl<T, A: Alloc> RawVec<T, A> {
585
605
let ptr = self . ptr ( ) as * mut _ ;
586
606
let new_layout = Layout :: new :: < T > ( ) . repeat ( new_cap) . unwrap ( ) . 0 ;
587
607
// FIXME: may crash and burn on over-reserve
588
- alloc_guard ( new_layout. size ( ) ) ;
608
+ alloc_guard ( new_layout. size ( ) ) . expect ( "capacity overflow" ) ;
589
609
match self . a . grow_in_place ( ptr, old_layout, new_layout) {
590
610
Ok ( _) => {
591
611
self . cap = new_cap;
@@ -709,10 +729,11 @@ unsafe impl<#[may_dangle] T, A: Alloc> Drop for RawVec<T, A> {
709
729
// all 4GB in user-space. e.g. PAE or x32
710
730
711
731
#[ inline]
712
- fn alloc_guard ( alloc_size : usize ) {
713
- if mem:: size_of :: < usize > ( ) < 8 {
714
- assert ! ( alloc_size <= :: core:: isize :: MAX as usize ,
715
- "capacity overflow" ) ;
732
+ fn alloc_guard ( alloc_size : usize ) -> Result < ( ) , CollectionAllocErr > {
733
+ if mem:: size_of :: < usize > ( ) < 8 && alloc_size <= :: core:: isize:: MAX as usize {
734
+ Err ( CapacityOverflow )
735
+ } else {
736
+ Ok ( ( ) )
716
737
}
717
738
}
718
739
0 commit comments