@@ -201,9 +201,16 @@ impl<T: Clone> ExtendFromSlice<T> for Vec<T> {
201201 }
202202}
203203
204+ /// Error type for APIs with fallible heap allocation
204205#[ derive( Debug ) ]
205- enum CollectionAllocErr {
206+ pub enum CollectionAllocErr {
207+ /// Overflow `usize::MAX` or other error during size computation
206208 CapacityOverflow ,
209+ /// The allocator return an error
210+ AllocErr {
211+ /// The layout that was passed to the allocator
212+ layout : Layout ,
213+ } ,
207214}
208215
209216impl From < LayoutErr > for CollectionAllocErr {
@@ -212,6 +219,14 @@ impl From<LayoutErr> for CollectionAllocErr {
212219 }
213220}
214221
222+ fn infallible < T > ( result : Result < T , CollectionAllocErr > ) -> T {
223+ match result {
224+ Ok ( x) => x,
225+ Err ( CollectionAllocErr :: CapacityOverflow ) => panic ! ( "capacity overflow" ) ,
226+ Err ( CollectionAllocErr :: AllocErr { layout } ) => alloc:: alloc:: handle_alloc_error ( layout) ,
227+ }
228+ }
229+
215230/// FIXME: use `Layout::array` when we require a Rust version where it’s stable
216231/// https://github.com/rust-lang/rust/issues/55724
217232fn layout_array < T > ( n : usize ) -> Result < Layout , CollectionAllocErr > {
@@ -714,48 +729,61 @@ impl<A: Array> SmallVec<A> {
714729
715730 /// Re-allocate to set the capacity to `max(new_cap, inline_size())`.
716731 ///
717- /// Panics if `new_cap` is less than the vector's length.
732+ /// Panics if `new_cap` is less than the vector's length
733+ /// or if the capacity computation overflows `usize`.
718734 pub fn grow ( & mut self , new_cap : usize ) {
735+ infallible ( self . try_grow ( new_cap) )
736+ }
737+
738+ /// Re-allocate to set the capacity to `max(new_cap, inline_size())`.
739+ ///
740+ /// Panics if `new_cap` is less than the vector's length
741+ pub fn try_grow ( & mut self , new_cap : usize ) -> Result < ( ) , CollectionAllocErr > {
719742 unsafe {
720743 let ( ptr, & mut len, cap) = self . triple_mut ( ) ;
721744 let unspilled = !self . spilled ( ) ;
722745 assert ! ( new_cap >= len) ;
723746 if new_cap <= self . inline_size ( ) {
724747 if unspilled {
725- return ;
748+ return Ok ( ( ) ) ;
726749 }
727750 self . data = SmallVecData :: from_inline ( MaybeUninit :: uninit ( ) ) ;
728751 ptr:: copy_nonoverlapping ( ptr, self . data . inline_mut ( ) , len) ;
729752 self . capacity = len;
730753 } else if new_cap != cap {
731- // Panic on overflow
732- let layout = layout_array :: < A :: Item > ( new_cap) . unwrap ( ) ;
754+ let layout = layout_array :: < A :: Item > ( new_cap) ?;
733755 let new_alloc = NonNull :: new ( alloc:: alloc:: alloc ( layout) )
734- . unwrap_or_else ( || alloc :: alloc :: handle_alloc_error ( layout) )
756+ . ok_or ( CollectionAllocErr :: AllocErr { layout } ) ?
735757 . cast ( )
736758 . as_ptr ( ) ;
737759 ptr:: copy_nonoverlapping ( ptr, new_alloc, len) ;
738760 self . data = SmallVecData :: from_heap ( new_alloc, len) ;
739761 self . capacity = new_cap;
740762 if unspilled {
741- return ;
763+ return Ok ( ( ) ) ;
742764 }
743765 } else {
744- return ;
766+ return Ok ( ( ) ) ;
745767 }
746768 deallocate ( ptr, cap) ;
769+ Ok ( ( ) )
747770 }
748771 }
749772
750773 /// Reserve capacity for `additional` more elements to be inserted.
751774 ///
752775 /// May reserve more space to avoid frequent reallocations.
753776 ///
754- /// If the new capacity would overflow `usize` then it will be set to `usize::max_value()`
755- /// instead. (This means that inserting `additional` new elements is not guaranteed to be
756- /// possible after calling this function.)
777+ /// Panics if the capacity computation overflows `usize`.
757778 #[ inline]
758779 pub fn reserve ( & mut self , additional : usize ) {
780+ infallible ( self . try_reserve ( additional) )
781+ }
782+
783+ /// Reserve capacity for `additional` more elements to be inserted.
784+ ///
785+ /// May reserve more space to avoid frequent reallocations.
786+ pub fn try_reserve ( & mut self , additional : usize ) -> Result < ( ) , CollectionAllocErr > {
759787 // prefer triple_mut() even if triple() would work
760788 // so that the optimizer removes duplicated calls to it
761789 // from callers like insert()
@@ -764,21 +792,30 @@ impl<A: Array> SmallVec<A> {
764792 let new_cap = len
765793 . checked_add ( additional)
766794 . and_then ( usize:: checked_next_power_of_two)
767- . unwrap_or ( usize:: max_value ( ) ) ;
768- self . grow ( new_cap) ;
795+ . ok_or ( CollectionAllocErr :: CapacityOverflow ) ?;
796+ self . try_grow ( new_cap)
797+ } else {
798+ Ok ( ( ) )
769799 }
770800 }
771801
772802 /// Reserve the minimum capacity for `additional` more elements to be inserted.
773803 ///
774804 /// Panics if the new capacity overflows `usize`.
775805 pub fn reserve_exact ( & mut self , additional : usize ) {
806+ infallible ( self . try_reserve_exact ( additional) )
807+ }
808+
809+ /// Reserve the minimum capacity for `additional` more elements to be inserted.
810+ pub fn try_reserve_exact ( & mut self , additional : usize ) -> Result < ( ) , CollectionAllocErr > {
776811 let ( _, & mut len, cap) = self . triple_mut ( ) ;
777812 if cap - len < additional {
778- match len. checked_add ( additional) {
779- Some ( cap) => self . grow ( cap) ,
780- None => panic ! ( "reserve_exact overflow" ) ,
781- }
813+ let new_cap = len
814+ . checked_add ( additional)
815+ . ok_or ( CollectionAllocErr :: CapacityOverflow ) ?;
816+ self . try_grow ( new_cap)
817+ } else {
818+ Ok ( ( ) )
782819 }
783820 }
784821
0 commit comments