@@ -15,6 +15,8 @@ use core::ptr::{self, Unique};
1515use core:: slice;
1616use heap:: { Alloc , Layout , Heap } ;
1717use super :: boxed:: Box ;
18+ use super :: allocator:: CollectionAllocErr ;
19+ use super :: allocator:: CollectionAllocErr :: * ;
1820
1921/// A low-level utility for more ergonomically allocating, reallocating, and deallocating
2022/// 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> {
8486 let elem_size = mem:: size_of :: < T > ( ) ;
8587
8688 let alloc_size = cap. checked_mul ( elem_size) . expect ( "capacity overflow" ) ;
87- alloc_guard ( alloc_size) ;
89+ alloc_guard ( alloc_size) . expect ( "capacity overflow" ) ;
8890
8991 // handles ZSTs and `cap = 0` alike
9092 let ptr = if alloc_size == 0 {
@@ -308,7 +310,7 @@ impl<T, A: Alloc> RawVec<T, A> {
308310 let new_cap = 2 * self . cap ;
309311 let new_size = new_cap * elem_size;
310312 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" ) ;
312314 let ptr_res = self . a . realloc ( self . ptr . as_ptr ( ) as * mut u8 ,
313315 cur,
314316 new_layout) ;
@@ -367,7 +369,7 @@ impl<T, A: Alloc> RawVec<T, A> {
367369 // overflow and the alignment is sufficiently small.
368370 let new_cap = 2 * self . cap ;
369371 let new_size = new_cap * elem_size;
370- alloc_guard ( new_size) ;
372+ alloc_guard ( new_size) . expect ( "capacity overflow" ) ;
371373 let ptr = self . ptr ( ) as * mut _ ;
372374 let new_layout = Layout :: from_size_align_unchecked ( new_size, old_layout. align ( ) ) ;
373375 match self . a . grow_in_place ( ptr, old_layout, new_layout) {
@@ -403,7 +405,9 @@ impl<T, A: Alloc> RawVec<T, A> {
403405 /// # Aborts
404406 ///
405407 /// 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+
407411 unsafe {
408412 // NOTE: we don't early branch on ZSTs here because we want this
409413 // to actually catch "asking for more than usize::MAX" in that case.
@@ -413,43 +417,51 @@ impl<T, A: Alloc> RawVec<T, A> {
413417 // Don't actually need any more capacity.
414418 // Wrapping in case they gave a bad `used_cap`.
415419 if self . cap ( ) . wrapping_sub ( used_cap) >= needed_extra_cap {
416- return ;
420+ return Ok ( ( ) ) ;
417421 }
418422
419423 // 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+
426429 let res = match self . current_layout ( ) {
427430 Some ( layout) => {
428431 let old_ptr = self . ptr . as_ptr ( ) as * mut u8 ;
429432 self . a . realloc ( old_ptr, layout, new_layout)
430433 }
431434 None => self . a . alloc ( new_layout) ,
432435 } ;
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 ) ;
438438 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 */ }
439450 }
440451 }
441452
442453 /// Calculates the buffer's new size given that it'll hold `used_cap +
443454 /// needed_extra_cap` elements. This logic is used in amortized reserve methods.
444455 /// 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+
446459 // 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 ) ?;
449461 // Cannot overflow, because `cap <= isize::MAX`, and type of `cap` is `usize`.
450462 let double_cap = self . cap * 2 ;
451463 // `double_cap` guarantees exponential growth.
452- cmp:: max ( double_cap, required_cap)
464+ Ok ( cmp:: max ( double_cap, required_cap) )
453465 }
454466
455467 /// Ensures that the buffer contains at least enough space to hold
@@ -504,7 +516,8 @@ impl<T, A: Alloc> RawVec<T, A> {
504516 /// # vector.push_all(&[1, 3, 5, 7, 9]);
505517 /// # }
506518 /// ```
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 > {
508521 unsafe {
509522 // NOTE: we don't early branch on ZSTs here because we want this
510523 // to actually catch "asking for more than usize::MAX" in that case.
@@ -514,30 +527,36 @@ impl<T, A: Alloc> RawVec<T, A> {
514527 // Don't actually need any more capacity.
515528 // Wrapping in case they give a bad `used_cap`
516529 if self . cap ( ) . wrapping_sub ( used_cap) >= needed_extra_cap {
517- return ;
530+ return Ok ( ( ) ) ;
518531 }
519532
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 ) ?;
521535
522- let new_layout = match Layout :: array :: < T > ( new_cap) {
523- Some ( layout) => layout,
524- None => panic ! ( "capacity overflow" ) ,
525- } ;
526536 // FIXME: may crash and burn on over-reserve
527- alloc_guard ( new_layout. size ( ) ) ;
537+ alloc_guard ( new_layout. size ( ) ) ?;
538+
528539 let res = match self . current_layout ( ) {
529540 Some ( layout) => {
530541 let old_ptr = self . ptr . as_ptr ( ) as * mut u8 ;
531542 self . a . realloc ( old_ptr, layout, new_layout)
532543 }
533544 None => self . a . alloc ( new_layout) ,
534545 } ;
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 ) ;
540548 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 */ }
541560 }
542561 }
543562
@@ -576,7 +595,8 @@ impl<T, A: Alloc> RawVec<T, A> {
576595 return false ;
577596 }
578597
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" ) ;
580600
581601 // Here, `cap < used_cap + needed_extra_cap <= new_cap`
582602 // (regardless of whether `self.cap - used_cap` wrapped).
@@ -585,7 +605,7 @@ impl<T, A: Alloc> RawVec<T, A> {
585605 let ptr = self . ptr ( ) as * mut _ ;
586606 let new_layout = Layout :: new :: < T > ( ) . repeat ( new_cap) . unwrap ( ) . 0 ;
587607 // FIXME: may crash and burn on over-reserve
588- alloc_guard ( new_layout. size ( ) ) ;
608+ alloc_guard ( new_layout. size ( ) ) . expect ( "capacity overflow" ) ;
589609 match self . a . grow_in_place ( ptr, old_layout, new_layout) {
590610 Ok ( _) => {
591611 self . cap = new_cap;
@@ -709,10 +729,11 @@ unsafe impl<#[may_dangle] T, A: Alloc> Drop for RawVec<T, A> {
709729// all 4GB in user-space. e.g. PAE or x32
710730
711731#[ 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 ( ( ) )
716737 }
717738}
718739
0 commit comments