@@ -17,10 +17,19 @@ use crate::collections::TryReserveErrorKind::*;
17
17
#[ cfg( test) ]
18
18
mod tests;
19
19
20
+ // One central function responsible for reporting capacity overflows. This'll
21
+ // ensure that the code generation related to these panics is minimal as there's
22
+ // only one location which panics rather than a bunch throughout the module.
20
23
#[ cfg( not( no_global_oom_handling) ) ]
24
+ #[ cfg_attr( not( feature = "panic_immediate_abort" ) , inline( never) ) ]
25
+ fn capacity_overflow ( ) -> ! {
26
+ panic ! ( "capacity overflow" ) ;
27
+ }
28
+
21
29
enum AllocInit {
22
30
/// The contents of the new memory are uninitialized.
23
31
Uninitialized ,
32
+ #[ cfg( not( no_global_oom_handling) ) ]
24
33
/// The new memory is guaranteed to be zeroed.
25
34
Zeroed ,
26
35
}
@@ -93,6 +102,8 @@ impl<T> RawVec<T, Global> {
93
102
/// zero-sized. Note that if `T` is zero-sized this means you will
94
103
/// *not* get a `RawVec` with the requested capacity.
95
104
///
105
+ /// Non-fallible version of `try_with_capacity`
106
+ ///
96
107
/// # Panics
97
108
///
98
109
/// Panics if the requested capacity exceeds `isize::MAX` bytes.
@@ -104,7 +115,7 @@ impl<T> RawVec<T, Global> {
104
115
#[ must_use]
105
116
#[ inline]
106
117
pub fn with_capacity ( capacity : usize ) -> Self {
107
- Self :: with_capacity_in ( capacity, Global )
118
+ handle_reserve ( Self :: try_allocate_in ( capacity, AllocInit :: Uninitialized , Global ) )
108
119
}
109
120
110
121
/// Like `with_capacity`, but guarantees the buffer is zeroed.
@@ -142,15 +153,22 @@ impl<T, A: Allocator> RawVec<T, A> {
142
153
#[ cfg( not( no_global_oom_handling) ) ]
143
154
#[ inline]
144
155
pub fn with_capacity_in ( capacity : usize , alloc : A ) -> Self {
145
- Self :: allocate_in ( capacity, AllocInit :: Uninitialized , alloc)
156
+ handle_reserve ( Self :: try_allocate_in ( capacity, AllocInit :: Uninitialized , alloc) )
157
+ }
158
+
159
+ /// Like `try_with_capacity`, but parameterized over the choice of
160
+ /// allocator for the returned `RawVec`.
161
+ #[ inline]
162
+ pub fn try_with_capacity_in ( capacity : usize , alloc : A ) -> Result < Self , TryReserveError > {
163
+ Self :: try_allocate_in ( capacity, AllocInit :: Uninitialized , alloc)
146
164
}
147
165
148
166
/// Like `with_capacity_zeroed`, but parameterized over the choice
149
167
/// of allocator for the returned `RawVec`.
150
168
#[ cfg( not( no_global_oom_handling) ) ]
151
169
#[ inline]
152
170
pub fn with_capacity_zeroed_in ( capacity : usize , alloc : A ) -> Self {
153
- Self :: allocate_in ( capacity, AllocInit :: Zeroed , alloc)
171
+ handle_reserve ( Self :: try_allocate_in ( capacity, AllocInit :: Zeroed , alloc) )
154
172
}
155
173
156
174
/// Converts the entire buffer into `Box<[MaybeUninit<T>]>` with the specified `len`.
@@ -179,35 +197,41 @@ impl<T, A: Allocator> RawVec<T, A> {
179
197
}
180
198
}
181
199
182
- #[ cfg( not( no_global_oom_handling) ) ]
183
- fn allocate_in ( capacity : usize , init : AllocInit , alloc : A ) -> Self {
200
+ fn try_allocate_in (
201
+ capacity : usize ,
202
+ init : AllocInit ,
203
+ alloc : A ,
204
+ ) -> Result < Self , TryReserveError > {
184
205
// Don't allocate here because `Drop` will not deallocate when `capacity` is 0.
206
+
185
207
if T :: IS_ZST || capacity == 0 {
186
- Self :: new_in ( alloc)
208
+ Ok ( Self :: new_in ( alloc) )
187
209
} else {
188
210
// We avoid `unwrap_or_else` here because it bloats the amount of
189
211
// LLVM IR generated.
190
212
let layout = match Layout :: array :: < T > ( capacity) {
191
213
Ok ( layout) => layout,
192
- Err ( _) => capacity_overflow ( ) ,
214
+ Err ( _) => return Err ( CapacityOverflow . into ( ) ) ,
193
215
} ;
194
- match alloc_guard ( layout . size ( ) ) {
195
- Ok ( _ ) => { }
196
- Err ( _ ) => capacity_overflow ( ) ,
216
+
217
+ if let Err ( err ) = alloc_guard ( layout . size ( ) ) {
218
+ return Err ( err ) ;
197
219
}
220
+
198
221
let result = match init {
199
222
AllocInit :: Uninitialized => alloc. allocate ( layout) ,
223
+ #[ cfg( not( no_global_oom_handling) ) ]
200
224
AllocInit :: Zeroed => alloc. allocate_zeroed ( layout) ,
201
225
} ;
202
226
let ptr = match result {
203
227
Ok ( ptr) => ptr,
204
- Err ( _) => handle_alloc_error ( layout) ,
228
+ Err ( _) => return Err ( AllocError { layout, non_exhaustive : ( ) } . into ( ) ) ,
205
229
} ;
206
230
207
231
// Allocators currently return a `NonNull<[u8]>` whose length
208
232
// matches the size requested. If that ever changes, the capacity
209
233
// here should change to `ptr.len() / mem::size_of::<T>()`.
210
- Self { ptr : Unique :: from ( ptr. cast ( ) ) , cap : unsafe { Cap ( capacity) } , alloc }
234
+ Ok ( Self { ptr : Unique :: from ( ptr. cast ( ) ) , cap : unsafe { Cap ( capacity) } , alloc } )
211
235
}
212
236
}
213
237
@@ -537,11 +561,11 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawVec<T, A> {
537
561
// Central function for reserve error handling.
538
562
#[ cfg( not( no_global_oom_handling) ) ]
539
563
#[ inline]
540
- fn handle_reserve ( result : Result < ( ) , TryReserveError > ) {
564
+ fn handle_reserve < T > ( result : Result < T , TryReserveError > ) -> T {
541
565
match result. map_err ( |e| e. kind ( ) ) {
566
+ Ok ( res) => res,
542
567
Err ( CapacityOverflow ) => capacity_overflow ( ) ,
543
568
Err ( AllocError { layout, .. } ) => handle_alloc_error ( layout) ,
544
- Ok ( ( ) ) => { /* yay */ }
545
569
}
546
570
}
547
571
@@ -561,12 +585,3 @@ fn alloc_guard(alloc_size: usize) -> Result<(), TryReserveError> {
561
585
Ok ( ( ) )
562
586
}
563
587
}
564
-
565
- // One central function responsible for reporting capacity overflows. This'll
566
- // ensure that the code generation related to these panics is minimal as there's
567
- // only one location which panics rather than a bunch throughout the module.
568
- #[ cfg( not( no_global_oom_handling) ) ]
569
- #[ cfg_attr( not( feature = "panic_immediate_abort" ) , inline( never) ) ]
570
- fn capacity_overflow ( ) -> ! {
571
- panic ! ( "capacity overflow" ) ;
572
- }
0 commit comments