@@ -201,9 +201,16 @@ impl<T: Clone> ExtendFromSlice<T> for Vec<T> {
201
201
}
202
202
}
203
203
204
+ /// Error type for APIs with fallible heap allocation
204
205
#[ derive( Debug ) ]
205
- enum CollectionAllocErr {
206
+ pub enum CollectionAllocErr {
207
+ /// Overflow `usize::MAX` or other error during size computation
206
208
CapacityOverflow ,
209
+ /// The allocator return an error
210
+ AllocErr {
211
+ /// The layout that was passed to the allocator
212
+ layout : Layout ,
213
+ } ,
207
214
}
208
215
209
216
impl From < LayoutErr > for CollectionAllocErr {
@@ -212,6 +219,14 @@ impl From<LayoutErr> for CollectionAllocErr {
212
219
}
213
220
}
214
221
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
+
215
230
/// FIXME: use `Layout::array` when we require a Rust version where it’s stable
216
231
/// https://github.com/rust-lang/rust/issues/55724
217
232
fn layout_array < T > ( n : usize ) -> Result < Layout , CollectionAllocErr > {
@@ -714,48 +729,61 @@ impl<A: Array> SmallVec<A> {
714
729
715
730
/// Re-allocate to set the capacity to `max(new_cap, inline_size())`.
716
731
///
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`.
718
734
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 > {
719
742
unsafe {
720
743
let ( ptr, & mut len, cap) = self . triple_mut ( ) ;
721
744
let unspilled = !self . spilled ( ) ;
722
745
assert ! ( new_cap >= len) ;
723
746
if new_cap <= self . inline_size ( ) {
724
747
if unspilled {
725
- return ;
748
+ return Ok ( ( ) ) ;
726
749
}
727
750
self . data = SmallVecData :: from_inline ( MaybeUninit :: uninit ( ) ) ;
728
751
ptr:: copy_nonoverlapping ( ptr, self . data . inline_mut ( ) , len) ;
729
752
self . capacity = len;
730
753
} 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) ?;
733
755
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 } ) ?
735
757
. cast ( )
736
758
. as_ptr ( ) ;
737
759
ptr:: copy_nonoverlapping ( ptr, new_alloc, len) ;
738
760
self . data = SmallVecData :: from_heap ( new_alloc, len) ;
739
761
self . capacity = new_cap;
740
762
if unspilled {
741
- return ;
763
+ return Ok ( ( ) ) ;
742
764
}
743
765
} else {
744
- return ;
766
+ return Ok ( ( ) ) ;
745
767
}
746
768
deallocate ( ptr, cap) ;
769
+ Ok ( ( ) )
747
770
}
748
771
}
749
772
750
773
/// Reserve capacity for `additional` more elements to be inserted.
751
774
///
752
775
/// May reserve more space to avoid frequent reallocations.
753
776
///
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`.
757
778
#[ inline]
758
779
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 > {
759
787
// prefer triple_mut() even if triple() would work
760
788
// so that the optimizer removes duplicated calls to it
761
789
// from callers like insert()
@@ -764,21 +792,30 @@ impl<A: Array> SmallVec<A> {
764
792
let new_cap = len
765
793
. checked_add ( additional)
766
794
. 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 ( ( ) )
769
799
}
770
800
}
771
801
772
802
/// Reserve the minimum capacity for `additional` more elements to be inserted.
773
803
///
774
804
/// Panics if the new capacity overflows `usize`.
775
805
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 > {
776
811
let ( _, & mut len, cap) = self . triple_mut ( ) ;
777
812
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 ( ( ) )
782
819
}
783
820
}
784
821
0 commit comments