Should I allocate a Vec with bumpalo?

Viewed 191

I need arrays allocated dynamically so I need a memory pool for doing this efficiently. I found https://github.com/fitzgen/bumpalo but it looks like it does not support allocating direct arrays. Should I allocate a vector like this:


use bumpalo::{Bump, collections::Vec};
let bump = Bump::new();
let mut v = Vec::new_in(&bump);

and get its slice every time I need it?

Problem is that I can't force the vector to have the exact size I want. My arrays always have a fixed size (size determined at runtime though). I think Vec is for things that grow in size.

1 Answers

I wanted to own the data and get the slice when needed.

bumpalo currently only provides growable collections, but it should be straightforward to write a non-growable one. For example:

use std::marker::PhantomData;
use bumpalo::Bump;

#[derive(Debug)]
pub struct BumpArray<'bump, T> {
    data: &'bump mut [T],
    _marker: PhantomData<T>, // we're dropping T values
}

impl<'bump, T> BumpArray<'bump, T> {
    // Just an example - you could also provide `new_with()` or similar
    // with different bounds on `T`.
    pub fn new_default(bump: &'bump Bump, size: usize) -> Self
    where
        T: Default,
    {
        BumpArray {
            data: bump.alloc_slice_fill_default(size),
            _marker: PhantomData,
        }
    }

    pub fn as_slice(&self) -> &[T] {
        self.data
    }

    pub fn as_slice_mut(&mut self) -> &mut [T] {
        self.data
    }
}

impl<T> Drop for BumpArray<'_, T> {
    fn drop(&mut self) {
        if std::mem::needs_drop::<T>() {
            for val in self.data.iter_mut() {
                unsafe {
                    std::ptr::drop_in_place(val);
                }
            }
        }
    }
}

The manual drop is required because bumpalo doesn't call drop(). In this case it allosw us to take advantage of ownership and execute the drops on individual elements (for types that require drops in the first place) much sooner than the whole arena is deallocated. It does require a bit of unsafe, but one that is fairly easy to reason about. Feel free to omit the Drop implementation and the _marker field if you use types that don't implement Drop.

Related