Skip to content

Commit 0713b5f

Browse files
c-cubefitzgen
andauthored
add try_ functions for slices and str (#260)
* add `try_` functions for slices and `str` * Apply suggestions from code review Co-authored-by: Nick Fitzgerald <[email protected]> * avoid referencing unitialized memory --------- Co-authored-by: Nick Fitzgerald <[email protected]>
1 parent 8392c63 commit 0713b5f

File tree

1 file changed

+167
-0
lines changed

1 file changed

+167
-0
lines changed

src/lib.rs

+167
Original file line numberDiff line numberDiff line change
@@ -1180,6 +1180,35 @@ impl Bump {
11801180
}
11811181
}
11821182

1183+
/// Like `alloc_slice_copy`, but does not panic in case of allocation failure.
1184+
///
1185+
/// ## Example
1186+
///
1187+
/// ```
1188+
/// let bump = bumpalo::Bump::new();
1189+
/// let x = bump.try_alloc_slice_copy(&[1, 2, 3]);
1190+
/// assert_eq!(x, Ok(&mut[1, 2, 3] as &mut [_]));
1191+
///
1192+
///
1193+
/// let bump = bumpalo::Bump::new();
1194+
/// bump.set_allocation_limit(Some(4));
1195+
/// let x = bump.try_alloc_slice_copy(&[1, 2, 3, 4, 5, 6]);
1196+
/// assert_eq!(x, Err(bumpalo::AllocErr)); // too big
1197+
/// ```
1198+
#[inline(always)]
1199+
pub fn try_alloc_slice_copy<T>(&self, src: &[T]) -> Result<&mut [T], AllocErr>
1200+
where
1201+
T: Copy,
1202+
{
1203+
let layout = Layout::for_value(src);
1204+
let dst = self.try_alloc_layout(layout)?.cast::<T>();
1205+
let result = unsafe {
1206+
core::ptr::copy_nonoverlapping(src.as_ptr(), dst.as_ptr(), src.len());
1207+
slice::from_raw_parts_mut(dst.as_ptr(), src.len())
1208+
};
1209+
Ok(result)
1210+
}
1211+
11831212
/// `Clone` a slice into this `Bump` and return an exclusive reference to
11841213
/// the clone. Prefer [`alloc_slice_copy`](#method.alloc_slice_copy) if `T` is `Copy`.
11851214
///
@@ -1222,6 +1251,24 @@ impl Bump {
12221251
}
12231252
}
12241253

1254+
/// Like `alloc_slice_clone` but does not panic on failure.
1255+
#[inline(always)]
1256+
pub fn try_alloc_slice_clone<T>(&self, src: &[T]) -> Result<&mut [T], AllocErr>
1257+
where
1258+
T: Clone,
1259+
{
1260+
let layout = Layout::for_value(src);
1261+
let dst = self.try_alloc_layout(layout)?.cast::<T>();
1262+
1263+
unsafe {
1264+
for (i, val) in src.iter().cloned().enumerate() {
1265+
ptr::write(dst.as_ptr().add(i), val);
1266+
}
1267+
1268+
Ok(slice::from_raw_parts_mut(dst.as_ptr(), src.len()))
1269+
}
1270+
}
1271+
12251272
/// `Copy` a string slice into this `Bump` and return an exclusive reference to it.
12261273
///
12271274
/// ## Panics
@@ -1244,6 +1291,30 @@ impl Bump {
12441291
}
12451292
}
12461293

1294+
/// Same as `alloc_str` but does not panic on failure.
1295+
///
1296+
/// ## Example
1297+
///
1298+
/// ```
1299+
/// let bump = bumpalo::Bump::new();
1300+
/// let hello = bump.try_alloc_str("hello world").unwrap();
1301+
/// assert_eq!("hello world", hello);
1302+
///
1303+
///
1304+
/// let bump = bumpalo::Bump::new();
1305+
/// bump.set_allocation_limit(Some(5));
1306+
/// let hello = bump.try_alloc_str("hello world");
1307+
/// assert_eq!(Err(bumpalo::AllocErr), hello);
1308+
/// ```
1309+
#[inline(always)]
1310+
pub fn try_alloc_str(&self, src: &str) -> Result<&mut str, AllocErr> {
1311+
let buffer = self.try_alloc_slice_copy(src.as_bytes())?;
1312+
unsafe {
1313+
// This is OK, because it already came in as str, so it is guaranteed to be utf8
1314+
Ok(str::from_utf8_unchecked_mut(buffer))
1315+
}
1316+
}
1317+
12471318
/// Allocates a new slice of size `len` into this `Bump` and returns an
12481319
/// exclusive reference to the copy.
12491320
///
@@ -1280,6 +1351,48 @@ impl Bump {
12801351
}
12811352
}
12821353

1354+
/// Allocates a new slice of size `len` into this `Bump` and returns an
1355+
/// exclusive reference to the copy.
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+
/// ## Example
1361+
///
1362+
/// ```
1363+
/// let bump = bumpalo::Bump::new();
1364+
/// let x = bump.try_alloc_slice_fill_with(5, |i| 5 * (i + 1));
1365+
/// assert_eq!(x, Ok(&mut[5usize, 10, 15, 20, 25] as &mut [_]));
1366+
///
1367+
///
1368+
/// let bump = bumpalo::Bump::new();
1369+
/// bump.set_allocation_limit(Some(4));
1370+
/// let x = bump.try_alloc_slice_fill_with(10, |i| 5 * (i + 1));
1371+
/// assert_eq!(x, Err(bumpalo::AllocErr));
1372+
/// ```
1373+
#[inline(always)]
1374+
pub fn try_alloc_slice_fill_with<T, F>(
1375+
&self,
1376+
len: usize,
1377+
mut f: F,
1378+
) -> Result<&mut [T], AllocErr>
1379+
where
1380+
F: FnMut(usize) -> T,
1381+
{
1382+
let layout = Layout::array::<T>(len).map_err(|_| AllocErr)?;
1383+
let dst = self.try_alloc_layout(layout)?.cast::<T>();
1384+
1385+
unsafe {
1386+
for i in 0..len {
1387+
ptr::write(dst.as_ptr().add(i), f(i));
1388+
}
1389+
1390+
let result = slice::from_raw_parts_mut(dst.as_ptr(), len);
1391+
debug_assert_eq!(Layout::for_value(result), layout);
1392+
Ok(result)
1393+
}
1394+
}
1395+
12831396
/// Allocates a new slice of size `len` into this `Bump` and returns an
12841397
/// exclusive reference to the copy.
12851398
///
@@ -1301,6 +1414,16 @@ impl Bump {
13011414
self.alloc_slice_fill_with(len, |_| value)
13021415
}
13031416

1417+
/// Same as `alloc_slice_fill_copy` but does not panic on failure.
1418+
#[inline(always)]
1419+
pub fn try_alloc_slice_fill_copy<T: Copy>(
1420+
&self,
1421+
len: usize,
1422+
value: T,
1423+
) -> Result<&mut [T], AllocErr> {
1424+
self.try_alloc_slice_fill_with(len, |_| value)
1425+
}
1426+
13041427
/// Allocates a new slice of size `len` slice into this `Bump` and return an
13051428
/// exclusive reference to the copy.
13061429
///
@@ -1325,6 +1448,16 @@ impl Bump {
13251448
self.alloc_slice_fill_with(len, |_| value.clone())
13261449
}
13271450

1451+
/// Like `alloc_slice_fill_clone` but does not panic on failure.
1452+
#[inline(always)]
1453+
pub fn try_alloc_slice_fill_clone<T: Clone>(
1454+
&self,
1455+
len: usize,
1456+
value: &T,
1457+
) -> Result<&mut [T], AllocErr> {
1458+
self.try_alloc_slice_fill_with(len, |_| value.clone())
1459+
}
1460+
13281461
/// Allocates a new slice of size `len` slice into this `Bump` and return an
13291462
/// exclusive reference to the copy.
13301463
///
@@ -1354,6 +1487,31 @@ impl Bump {
13541487
})
13551488
}
13561489

1490+
/// Allocates a new slice of size `iter.len()` slice into this `Bump` and return an
1491+
/// exclusive reference to the copy. Does not panic on failure.
1492+
///
1493+
/// The elements are initialized using the supplied iterator.
1494+
///
1495+
/// ## Example
1496+
///
1497+
/// ```
1498+
/// let bump = bumpalo::Bump::new();
1499+
/// let x: &[i32] = bump.try_alloc_slice_fill_iter([2, 3, 5]
1500+
/// .iter().cloned().map(|i| i * i)).unwrap();
1501+
/// assert_eq!(x, [4, 9, 25]);
1502+
/// ```
1503+
#[inline(always)]
1504+
pub fn try_alloc_slice_fill_iter<T, I>(&self, iter: I) -> Result<&mut [T], AllocErr>
1505+
where
1506+
I: IntoIterator<Item = T>,
1507+
I::IntoIter: ExactSizeIterator,
1508+
{
1509+
let mut iter = iter.into_iter();
1510+
self.try_alloc_slice_fill_with(iter.len(), |_| {
1511+
iter.next().expect("Iterator supplied too few elements")
1512+
})
1513+
}
1514+
13571515
/// Allocates a new slice of size `len` slice into this `Bump` and return an
13581516
/// exclusive reference to the copy.
13591517
///
@@ -1377,6 +1535,15 @@ impl Bump {
13771535
self.alloc_slice_fill_with(len, |_| T::default())
13781536
}
13791537

1538+
/// Like `alloc_slice_fill_default` but does not panic on failure.
1539+
#[inline(always)]
1540+
pub fn try_alloc_slice_fill_default<T: Default>(
1541+
&self,
1542+
len: usize,
1543+
) -> Result<&mut [T], AllocErr> {
1544+
self.try_alloc_slice_fill_with(len, |_| T::default())
1545+
}
1546+
13801547
/// Allocate space for an object with the given `Layout`.
13811548
///
13821549
/// The returned pointer points at uninitialized memory, and should be

0 commit comments

Comments
 (0)