Skip to content

Commit 4ee5f49

Browse files
committed
try_with_capacity for RawVec
1 parent cdaa12e commit 4ee5f49

File tree

2 files changed

+26
-19
lines changed

2 files changed

+26
-19
lines changed

library/alloc/src/raw_vec.rs

+22-16
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ use crate::collections::TryReserveErrorKind::*;
1717
#[cfg(test)]
1818
mod tests;
1919

20-
#[cfg(not(no_global_oom_handling))]
2120
enum AllocInit {
2221
/// The contents of the new memory are uninitialized.
2322
Uninitialized,
@@ -93,6 +92,8 @@ impl<T> RawVec<T, Global> {
9392
/// zero-sized. Note that if `T` is zero-sized this means you will
9493
/// *not* get a `RawVec` with the requested capacity.
9594
///
95+
/// Non-fallible version of `try_with_capacity`
96+
///
9697
/// # Panics
9798
///
9899
/// Panics if the requested capacity exceeds `isize::MAX` bytes.
@@ -104,7 +105,7 @@ impl<T> RawVec<T, Global> {
104105
#[must_use]
105106
#[inline]
106107
pub fn with_capacity(capacity: usize) -> Self {
107-
Self::with_capacity_in(capacity, Global)
108+
handle_reserve(Self::try_allocate_in(capacity, AllocInit::Uninitialized, Global))
108109
}
109110

110111
/// Like `with_capacity`, but guarantees the buffer is zeroed.
@@ -142,15 +143,15 @@ impl<T, A: Allocator> RawVec<T, A> {
142143
#[cfg(not(no_global_oom_handling))]
143144
#[inline]
144145
pub fn with_capacity_in(capacity: usize, alloc: A) -> Self {
145-
Self::allocate_in(capacity, AllocInit::Uninitialized, alloc)
146+
handle_reserve(Self::try_allocate_in(capacity, AllocInit::Uninitialized, alloc))
146147
}
147148

148149
/// Like `with_capacity_zeroed`, but parameterized over the choice
149150
/// of allocator for the returned `RawVec`.
150151
#[cfg(not(no_global_oom_handling))]
151152
#[inline]
152153
pub fn with_capacity_zeroed_in(capacity: usize, alloc: A) -> Self {
153-
Self::allocate_in(capacity, AllocInit::Zeroed, alloc)
154+
handle_reserve(Self::try_allocate_in(capacity, AllocInit::Zeroed, alloc))
154155
}
155156

156157
/// Converts the entire buffer into `Box<[MaybeUninit<T>]>` with the specified `len`.
@@ -179,39 +180,44 @@ impl<T, A: Allocator> RawVec<T, A> {
179180
}
180181
}
181182

182-
#[cfg(not(no_global_oom_handling))]
183-
fn allocate_in(capacity: usize, init: AllocInit, alloc: A) -> Self {
183+
fn try_allocate_in(
184+
capacity: usize,
185+
init: AllocInit,
186+
alloc: A,
187+
) -> Result<Self, TryReserveError> {
184188
// Don't allocate here because `Drop` will not deallocate when `capacity` is 0.
189+
185190
if T::IS_ZST || capacity == 0 {
186-
Self::new_in(alloc)
191+
Ok(Self::new_in(alloc))
187192
} else {
188193
// We avoid `unwrap_or_else` here because it bloats the amount of
189194
// LLVM IR generated.
190195
let layout = match Layout::array::<T>(capacity) {
191196
Ok(layout) => layout,
192-
Err(_) => capacity_overflow(),
197+
Err(_) => return Err(CapacityOverflow.into()),
193198
};
194-
match alloc_guard(layout.size()) {
195-
Ok(_) => {}
196-
Err(_) => capacity_overflow(),
199+
200+
if let Err(err) = alloc_guard(layout.size()) {
201+
return Err(err);
197202
}
203+
198204
let result = match init {
199205
AllocInit::Uninitialized => alloc.allocate(layout),
200206
AllocInit::Zeroed => alloc.allocate_zeroed(layout),
201207
};
202208
let ptr = match result {
203209
Ok(ptr) => ptr,
204-
Err(_) => handle_alloc_error(layout),
210+
Err(_) => return Err(AllocError { layout, non_exhaustive: () }.into()),
205211
};
206212

207213
// Allocators currently return a `NonNull<[u8]>` whose length
208214
// matches the size requested. If that ever changes, the capacity
209215
// here should change to `ptr.len() / mem::size_of::<T>()`.
210-
Self {
216+
Ok(Self {
211217
ptr: unsafe { Unique::new_unchecked(ptr.cast().as_ptr()) },
212218
cap: unsafe { Cap(capacity) },
213219
alloc,
214-
}
220+
})
215221
}
216222
}
217223

@@ -536,11 +542,11 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawVec<T, A> {
536542
// Central function for reserve error handling.
537543
#[cfg(not(no_global_oom_handling))]
538544
#[inline]
539-
fn handle_reserve(result: Result<(), TryReserveError>) {
545+
fn handle_reserve<T>(result: Result<T, TryReserveError>) -> T {
540546
match result.map_err(|e| e.kind()) {
547+
Ok(res) => res,
541548
Err(CapacityOverflow) => capacity_overflow(),
542549
Err(AllocError { layout, .. }) => handle_alloc_error(layout),
543-
Ok(()) => { /* yay */ }
544550
}
545551
}
546552

library/alloc/src/raw_vec/tests.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -105,13 +105,14 @@ fn zst() {
105105
let v: RawVec<ZST> = RawVec::with_capacity_in(100, Global);
106106
zst_sanity(&v);
107107

108-
let v: RawVec<ZST> = RawVec::allocate_in(0, AllocInit::Uninitialized, Global);
108+
let v: RawVec<ZST> = RawVec::try_allocate_in(0, AllocInit::Uninitialized, Global).unwrap();
109109
zst_sanity(&v);
110110

111-
let v: RawVec<ZST> = RawVec::allocate_in(100, AllocInit::Uninitialized, Global);
111+
let v: RawVec<ZST> = RawVec::try_allocate_in(100, AllocInit::Uninitialized, Global).unwrap();
112112
zst_sanity(&v);
113113

114-
let mut v: RawVec<ZST> = RawVec::allocate_in(usize::MAX, AllocInit::Uninitialized, Global);
114+
let mut v: RawVec<ZST> =
115+
RawVec::try_allocate_in(usize::MAX, AllocInit::Uninitialized, Global).unwrap();
115116
zst_sanity(&v);
116117

117118
// Check all these operations work as expected with zero-sized elements.

0 commit comments

Comments
 (0)