@@ -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,50 @@ 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 ( ( ) )
439
441
}
440
442
}
441
443
444
+ pub fn reserve_exact ( & mut self , used_cap : usize , needed_extra_cap : usize ) {
445
+ match self . try_reserve_exact ( used_cap, needed_extra_cap) {
446
+ Err ( CapacityOverflow ) => panic ! ( "capacity overflow" ) ,
447
+ Err ( AllocErr ( e) ) => self . a . oom ( e) ,
448
+ Ok ( ( ) ) => { /* yay */ }
449
+ }
450
+ }
451
+
442
452
/// Calculates the buffer's new size given that it'll hold `used_cap +
443
453
/// needed_extra_cap` elements. This logic is used in amortized reserve methods.
444
454
/// Returns `(new_capacity, new_alloc_size)`.
445
- fn amortized_new_size ( & self , used_cap : usize , needed_extra_cap : usize ) -> usize {
455
+ fn amortized_new_size ( & self , used_cap : usize , needed_extra_cap : usize )
456
+ -> Result < usize , CollectionAllocErr > {
457
+
446
458
// Nothing we can really do about these checks :(
447
- let required_cap = used_cap. checked_add ( needed_extra_cap)
448
- . expect ( "capacity overflow" ) ;
459
+ let required_cap = used_cap. checked_add ( needed_extra_cap) . ok_or ( CapacityOverflow ) ?;
449
460
// Cannot overflow, because `cap <= isize::MAX`, and type of `cap` is `usize`.
450
461
let double_cap = self . cap * 2 ;
451
462
// `double_cap` guarantees exponential growth.
452
- cmp:: max ( double_cap, required_cap)
463
+ Ok ( cmp:: max ( double_cap, required_cap) )
453
464
}
454
465
455
466
/// Ensures that the buffer contains at least enough space to hold
@@ -504,8 +515,9 @@ impl<T, A: Alloc> RawVec<T, A> {
504
515
/// # vector.push_all(&[1, 3, 5, 7, 9]);
505
516
/// # }
506
517
/// ```
507
- pub fn reserve ( & mut self , used_cap : usize , needed_extra_cap : usize ) {
508
- unsafe {
518
+ pub fn try_reserve ( & mut self , used_cap : usize , needed_extra_cap : usize )
519
+ -> Result < ( ) , CollectionAllocErr > {
520
+ unsafe {
509
521
// NOTE: we don't early branch on ZSTs here because we want this
510
522
// to actually catch "asking for more than usize::MAX" in that case.
511
523
// If we make it past the first branch then we are guaranteed to
@@ -514,33 +526,38 @@ impl<T, A: Alloc> RawVec<T, A> {
514
526
// Don't actually need any more capacity.
515
527
// Wrapping in case they give a bad `used_cap`
516
528
if self . cap ( ) . wrapping_sub ( used_cap) >= needed_extra_cap {
517
- return ;
529
+ return Ok ( ( ) ) ;
518
530
}
519
531
520
- let new_cap = self . amortized_new_size ( used_cap, needed_extra_cap) ;
532
+ let new_cap = self . amortized_new_size ( used_cap, needed_extra_cap) ?;
533
+ let new_layout = Layout :: array :: < T > ( new_cap) . ok_or ( CapacityOverflow ) ?;
534
+
535
+ // FIXME: may crash and burn on over-reserve
536
+ alloc_guard ( new_layout. size ( ) ) ?;
521
537
522
- let new_layout = match Layout :: array :: < T > ( new_cap) {
523
- Some ( layout) => layout,
524
- None => panic ! ( "capacity overflow" ) ,
525
- } ;
526
- // FIXME: may crash and burn on over-reserve
527
- alloc_guard ( new_layout. size ( ) ) ;
528
538
let res = match self . current_layout ( ) {
529
539
Some ( layout) => {
530
540
let old_ptr = self . ptr . as_ptr ( ) as * mut u8 ;
531
541
self . a . realloc ( old_ptr, layout, new_layout)
532
542
}
533
543
None => self . a . alloc ( new_layout) ,
534
544
} ;
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;
545
+
546
+ self . ptr = Unique :: new_unchecked ( res? as * mut T ) ;
540
547
self . cap = new_cap;
548
+
549
+ Ok ( ( ) )
541
550
}
542
551
}
543
552
553
+ /// The same as try_reserve, but errors are lowered to a call to oom().
554
+ pub fn reserve ( & mut self , used_cap : usize , needed_extra_cap : usize ) {
555
+ match self . try_reserve ( used_cap, needed_extra_cap) {
556
+ Err ( CapacityOverflow ) => panic ! ( "capacity overflow" ) ,
557
+ Err ( AllocErr ( e) ) => self . a . oom ( e) ,
558
+ Ok ( ( ) ) => { /* yay */ }
559
+ }
560
+ }
544
561
/// Attempts to ensure that the buffer contains at least enough space to hold
545
562
/// `used_cap + needed_extra_cap` elements. If it doesn't already have
546
563
/// enough capacity, will reallocate in place enough space plus comfortable slack
@@ -576,7 +593,8 @@ impl<T, A: Alloc> RawVec<T, A> {
576
593
return false ;
577
594
}
578
595
579
- let new_cap = self . amortized_new_size ( used_cap, needed_extra_cap) ;
596
+ let new_cap = self . amortized_new_size ( used_cap, needed_extra_cap)
597
+ . expect ( "capacity overflow" ) ;
580
598
581
599
// Here, `cap < used_cap + needed_extra_cap <= new_cap`
582
600
// (regardless of whether `self.cap - used_cap` wrapped).
@@ -585,7 +603,7 @@ impl<T, A: Alloc> RawVec<T, A> {
585
603
let ptr = self . ptr ( ) as * mut _ ;
586
604
let new_layout = Layout :: new :: < T > ( ) . repeat ( new_cap) . unwrap ( ) . 0 ;
587
605
// FIXME: may crash and burn on over-reserve
588
- alloc_guard ( new_layout. size ( ) ) ;
606
+ alloc_guard ( new_layout. size ( ) ) . expect ( "capacity overflow" ) ;
589
607
match self . a . grow_in_place ( ptr, old_layout, new_layout) {
590
608
Ok ( _) => {
591
609
self . cap = new_cap;
@@ -709,14 +727,14 @@ unsafe impl<#[may_dangle] T, A: Alloc> Drop for RawVec<T, A> {
709
727
// all 4GB in user-space. e.g. PAE or x32
710
728
711
729
#[ 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" ) ;
730
+ fn alloc_guard ( alloc_size : usize ) -> Result < ( ) , CollectionAllocErr > {
731
+ if mem:: size_of :: < usize > ( ) < 8 && alloc_size > :: core:: isize:: MAX as usize {
732
+ Err ( CapacityOverflow )
733
+ } else {
734
+ Ok ( ( ) )
716
735
}
717
736
}
718
737
719
-
720
738
#[ cfg( test) ]
721
739
mod tests {
722
740
use super :: * ;
0 commit comments