@@ -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,50 @@ 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 ( ( ) )
439441 }
440442 }
441443
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+
442452 /// Calculates the buffer's new size given that it'll hold `used_cap +
443453 /// needed_extra_cap` elements. This logic is used in amortized reserve methods.
444454 /// 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+
446458 // 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 ) ?;
449460 // Cannot overflow, because `cap <= isize::MAX`, and type of `cap` is `usize`.
450461 let double_cap = self . cap * 2 ;
451462 // `double_cap` guarantees exponential growth.
452- cmp:: max ( double_cap, required_cap)
463+ Ok ( cmp:: max ( double_cap, required_cap) )
453464 }
454465
455466 /// Ensures that the buffer contains at least enough space to hold
@@ -504,8 +515,9 @@ impl<T, A: Alloc> RawVec<T, A> {
504515 /// # vector.push_all(&[1, 3, 5, 7, 9]);
505516 /// # }
506517 /// ```
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 {
509521 // NOTE: we don't early branch on ZSTs here because we want this
510522 // to actually catch "asking for more than usize::MAX" in that case.
511523 // If we make it past the first branch then we are guaranteed to
@@ -514,33 +526,38 @@ impl<T, A: Alloc> RawVec<T, A> {
514526 // Don't actually need any more capacity.
515527 // Wrapping in case they give a bad `used_cap`
516528 if self . cap ( ) . wrapping_sub ( used_cap) >= needed_extra_cap {
517- return ;
529+ return Ok ( ( ) ) ;
518530 }
519531
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 ( ) ) ?;
521537
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 ( ) ) ;
528538 let res = match self . current_layout ( ) {
529539 Some ( layout) => {
530540 let old_ptr = self . ptr . as_ptr ( ) as * mut u8 ;
531541 self . a . realloc ( old_ptr, layout, new_layout)
532542 }
533543 None => self . a . alloc ( new_layout) ,
534544 } ;
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 ) ;
540547 self . cap = new_cap;
548+
549+ Ok ( ( ) )
541550 }
542551 }
543552
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+ }
544561 /// Attempts to ensure that the buffer contains at least enough space to hold
545562 /// `used_cap + needed_extra_cap` elements. If it doesn't already have
546563 /// enough capacity, will reallocate in place enough space plus comfortable slack
@@ -576,7 +593,8 @@ impl<T, A: Alloc> RawVec<T, A> {
576593 return false ;
577594 }
578595
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" ) ;
580598
581599 // Here, `cap < used_cap + needed_extra_cap <= new_cap`
582600 // (regardless of whether `self.cap - used_cap` wrapped).
@@ -585,7 +603,7 @@ impl<T, A: Alloc> RawVec<T, A> {
585603 let ptr = self . ptr ( ) as * mut _ ;
586604 let new_layout = Layout :: new :: < T > ( ) . repeat ( new_cap) . unwrap ( ) . 0 ;
587605 // FIXME: may crash and burn on over-reserve
588- alloc_guard ( new_layout. size ( ) ) ;
606+ alloc_guard ( new_layout. size ( ) ) . expect ( "capacity overflow" ) ;
589607 match self . a . grow_in_place ( ptr, old_layout, new_layout) {
590608 Ok ( _) => {
591609 self . cap = new_cap;
@@ -709,14 +727,14 @@ unsafe impl<#[may_dangle] T, A: Alloc> Drop for RawVec<T, A> {
709727// all 4GB in user-space. e.g. PAE or x32
710728
711729#[ 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 ( ( ) )
716735 }
717736}
718737
719-
720738#[ cfg( test) ]
721739mod tests {
722740 use super :: * ;
0 commit comments