Skip to content

Commit f1f33f8

Browse files
authored
Add fallible slice allocation functions (#262)
This change adds slice allocation functions that can fail, to match the scalar allocation functions that can fail.
1 parent b3707e8 commit f1f33f8

File tree

3 files changed

+143
-0
lines changed

3 files changed

+143
-0
lines changed

src/lib.rs

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1351,6 +1351,58 @@ impl Bump {
13511351
}
13521352
}
13531353

1354+
/// Allocates a new slice of size `len` into this `Bump` and returns an
1355+
/// exclusive reference to the copy, failing if the closure return an Err.
1356+
///
1357+
/// The elements of the slice are initialized using the supplied closure.
1358+
/// The closure argument is the position in the slice.
1359+
///
1360+
/// ## Panics
1361+
///
1362+
/// Panics if reserving space for the slice fails.
1363+
///
1364+
/// ## Example
1365+
///
1366+
/// ```
1367+
/// let bump = bumpalo::Bump::new();
1368+
/// let x: Result<&mut [usize], ()> = bump.alloc_slice_try_fill_with(5, |i| Ok(5 * i));
1369+
/// assert_eq!(x, Ok(bump.alloc_slice_copy(&[0, 5, 10, 15, 20])));
1370+
/// ```
1371+
///
1372+
/// ```
1373+
/// let bump = bumpalo::Bump::new();
1374+
/// let x: Result<&mut [usize], ()> = bump.alloc_slice_try_fill_with(
1375+
/// 5,
1376+
/// |n| if n == 2 { Err(()) } else { Ok(n) }
1377+
/// );
1378+
/// assert_eq!(x, Err(()));
1379+
/// ```
1380+
#[inline(always)]
1381+
pub fn alloc_slice_try_fill_with<T, F, E>(&self, len: usize, mut f: F) -> Result<&mut [T], E>
1382+
where
1383+
F: FnMut(usize) -> Result<T, E>,
1384+
{
1385+
let layout = Layout::array::<T>(len).unwrap_or_else(|_| oom());
1386+
let base_ptr = self.alloc_layout(layout);
1387+
let dst = base_ptr.cast::<T>();
1388+
1389+
unsafe {
1390+
for i in 0..len {
1391+
match f(i) {
1392+
Ok(el) => ptr::write(dst.as_ptr().add(i), el),
1393+
Err(e) => {
1394+
self.dealloc(base_ptr, layout);
1395+
return Err(e);
1396+
}
1397+
}
1398+
}
1399+
1400+
let result = slice::from_raw_parts_mut(dst.as_ptr(), len);
1401+
debug_assert_eq!(Layout::for_value(result), layout);
1402+
Ok(result)
1403+
}
1404+
}
1405+
13541406
/// Allocates a new slice of size `len` into this `Bump` and returns an
13551407
/// exclusive reference to the copy.
13561408
///
@@ -1487,6 +1539,45 @@ impl Bump {
14871539
})
14881540
}
14891541

1542+
/// Allocates a new slice of size `len` slice into this `Bump` and return an
1543+
/// exclusive reference to the copy, failing if the iterator returns an Err.
1544+
///
1545+
/// The elements are initialized using the supplied iterator.
1546+
///
1547+
/// ## Panics
1548+
///
1549+
/// Panics if reserving space for the slice fails, or if the supplied
1550+
/// iterator returns fewer elements than it promised.
1551+
///
1552+
/// ## Examples
1553+
///
1554+
/// ```
1555+
/// let bump = bumpalo::Bump::new();
1556+
/// let x: Result<&mut [i32], ()> = bump.alloc_slice_try_fill_iter(
1557+
/// [2, 3, 5].iter().cloned().map(|i| Ok(i * i))
1558+
/// );
1559+
/// assert_eq!(x, Ok(bump.alloc_slice_copy(&[4, 9, 25])));
1560+
/// ```
1561+
///
1562+
/// ```
1563+
/// let bump = bumpalo::Bump::new();
1564+
/// let x: Result<&mut [i32], ()> = bump.alloc_slice_try_fill_iter(
1565+
/// [Ok(2), Err(()), Ok(5)].iter().cloned()
1566+
/// );
1567+
/// assert_eq!(x, Err(()));
1568+
/// ```
1569+
#[inline(always)]
1570+
pub fn alloc_slice_try_fill_iter<T, I, E>(&self, iter: I) -> Result<&mut [T], E>
1571+
where
1572+
I: IntoIterator<Item = Result<T, E>>,
1573+
I::IntoIter: ExactSizeIterator,
1574+
{
1575+
let mut iter = iter.into_iter();
1576+
self.alloc_slice_try_fill_with(iter.len(), |_| {
1577+
iter.next().expect("Iterator supplied too few elements")
1578+
})
1579+
}
1580+
14901581
/// Allocates a new slice of size `iter.len()` slice into this `Bump` and return an
14911582
/// exclusive reference to the copy. Does not panic on failure.
14921583
///

tests/all/alloc_fill.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use bumpalo::Bump;
22
use std::alloc::Layout;
33
use std::cmp;
4+
use std::iter::repeat;
45
use std::mem;
56

67
#[test]
@@ -29,6 +30,35 @@ fn alloc_slice_fill_zero() {
2930
assert_eq!(ptr2 as *mut _ as usize, ptr3.as_ptr() as usize + 1);
3031
}
3132

33+
#[test]
34+
fn alloc_slice_try_fill_with_succeeds() {
35+
let b = Bump::new();
36+
let res: Result<&mut [usize], ()> = b.alloc_slice_try_fill_with(100, |n| Ok(n));
37+
assert_eq!(res.map(|arr| arr[50]), Ok(50));
38+
}
39+
40+
#[test]
41+
fn alloc_slice_try_fill_with_fails() {
42+
let b = Bump::new();
43+
let res: Result<&mut [u16], ()> =
44+
b.alloc_slice_try_fill_with(1000, |n| if n == 100 { Err(()) } else { Ok(42) });
45+
assert_eq!(res, Err(()));
46+
}
47+
48+
#[test]
49+
fn alloc_slice_try_fill_iter_succeeds() {
50+
let b = Bump::new();
51+
let res: Result<&mut [u16], ()> = b.alloc_slice_try_fill_iter(repeat(42).take(10).map(Ok));
52+
assert_eq!(res.map(|arr| arr[5]), Ok(42));
53+
}
54+
55+
#[test]
56+
fn alloc_slice_try_fill_iter_fails() {
57+
let b = Bump::new();
58+
let res: Result<&mut [u16], ()> = b.alloc_slice_try_fill_iter(repeat(()).take(10).map(Err));
59+
assert_eq!(res, Err(()));
60+
}
61+
3262
#[test]
3363
#[should_panic(expected = "out of memory")]
3464
fn alloc_slice_overflow() {

tests/all/alloc_try_with.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
// We only run them when debug_assertions are not set, as we expect them to fail outside release
55
// mode.
66

7+
use std::iter::repeat;
8+
79
use bumpalo::Bump;
810

911
#[test]
@@ -116,3 +118,23 @@ fn alloc_try_with_large_enum_err() {
116118
.alloc_try_with(|| Result::<LargeEnum, _>::Err(()))
117119
.is_err());
118120
}
121+
122+
#[test]
123+
#[cfg_attr(debug_assertions, ignore)]
124+
fn alloc_slice_try_fill_with_large_length() {
125+
let b = Bump::new();
126+
127+
assert!(b
128+
.alloc_slice_try_fill_with(10_000_000, |_| Err::<u8, _>(()))
129+
.is_err());
130+
}
131+
132+
#[test]
133+
#[cfg_attr(debug_assertions, ignore)]
134+
fn alloc_slice_try_fill_iter_large_length() {
135+
let b = Bump::new();
136+
137+
assert!(b
138+
.alloc_slice_try_fill_iter(repeat(Err::<u8, _>(())).take(10_000_000))
139+
.is_err());
140+
}

0 commit comments

Comments
 (0)