Module bumpalo::boxed

source ·
Expand description

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:

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.

Structs

  • An owned pointer to a bump-allocated T value, that runs Drop implementations.