alloc.rs |
Memory allocation APIs |
31452 |
boxed.rs |
A pointer type for bump allocation.
[`Box<'a, T>`] provides the simplest form of
bump allocation in `bumpalo`. Boxes provide ownership for this allocation, and
drop their contents when they go out of scope.
# Examples
Move a value from the stack to the heap by creating a [`Box`]:
```
use bumpalo::{Bump, boxed::Box};
let b = Bump::new();
let val: u8 = 5;
let boxed: Box<u8> = Box::new_in(val, &b);
```
Move a value from a [`Box`] back to the stack by [dereferencing]:
```
use bumpalo::{Bump, boxed::Box};
let b = Bump::new();
let boxed: Box<u8> = Box::new_in(5, &b);
let val: u8 = *boxed;
```
Running [`Drop`] implementations on bump-allocated values:
```
use bumpalo::{Bump, boxed::Box};
use std::sync::atomic::{AtomicUsize, Ordering};
static NUM_DROPPED: AtomicUsize = AtomicUsize::new(0);
struct CountDrops;
impl Drop for CountDrops {
fn drop(&mut self) {
NUM_DROPPED.fetch_add(1, Ordering::SeqCst);
}
}
// Create a new bump arena.
let bump = Bump::new();
// Create a `CountDrops` inside the bump arena.
let mut c = Box::new_in(CountDrops, &bump);
// No `CountDrops` have been dropped yet.
assert_eq!(NUM_DROPPED.load(Ordering::SeqCst), 0);
// Drop our `Box<CountDrops>`.
drop(c);
// Its `Drop` implementation was run, and so `NUM_DROPS` has been incremented.
assert_eq!(NUM_DROPPED.load(Ordering::SeqCst), 1);
```
Creating a recursive data structure:
```
use bumpalo::{Bump, boxed::Box};
let b = Bump::new();
#[derive(Debug)]
enum List<'a, T> {
Cons(T, Box<'a, List<'a, T>>),
Nil,
}
let list: List<i32> = List::Cons(1, Box::new_in(List::Cons(2, Box::new_in(List::Nil, &b)), &b));
println!("{:?}", list);
```
This will print `Cons(1, Cons(2, Nil))`.
Recursive structures must be boxed, because if the definition of `Cons`
looked like this:
```compile_fail,E0072
# enum List<T> {
Cons(T, List<T>),
# }
```
It wouldn't work. This is because the size of a `List` depends on how many
elements are in the list, and so we don't know how much memory to allocate
for a `Cons`. By introducing a [`Box<'a, T>`], which has a defined size, we know how
big `Cons` needs to be.
# Memory layout
For non-zero-sized values, a [`Box`] will use the provided [`Bump`] allocator for
its allocation. It is valid to convert both ways between a [`Box`] and a
pointer allocated with the [`Bump`] allocator, given that the
[`Layout`] used with the allocator is correct for the type. More precisely,
a `value: *mut T` that has been allocated with the [`Bump`] allocator
with `Layout::for_value(&*value)` may be converted into a box using
[`Box::<T>::from_raw(value)`]. Conversely, the memory backing a `value: *mut
T` obtained from [`Box::<T>::into_raw`] will be deallocated by the
[`Bump`] allocator with [`Layout::for_value(&*value)`].
Note that roundtrip `Box::from_raw(Box::into_raw(b))` looses the lifetime bound to the
[`Bump`] immutable borrow which guarantees that the allocator will not be reset
and memory will not be freed.
[dereferencing]: https://doc.rust-lang.org/std/ops/trait.Deref.html
[`Box`]: struct.Box.html
[`Box<'a, T>`]: struct.Box.html
[`Box::<T>::from_raw(value)`]: struct.Box.html#method.from_raw
[`Box::<T>::into_raw`]: struct.Box.html#method.into_raw
[`Bump`]: ../struct.Bump.html
[`Drop`]: https://doc.rust-lang.org/std/ops/trait.Drop.html
[`Layout`]: https://doc.rust-lang.org/std/alloc/struct.Layout.html
[`Layout::for_value(&*value)`]: https://doc.rust-lang.org/std/alloc/struct.Layout.html#method.for_value |
20560 |
collections |
|
|
lib.rs |
|
76490 |