bumpish 0.4.0

A set of collections using bump allocations
Documentation
use super::*;
use pretty_assertions::assert_eq;

fn push<T, const N: usize>(bump: &mut RawBump<T, N>, value: T) -> &mut T {
    unsafe {
        let mut ptr = bump.allocate();
        ptr.write(value);
        ptr.as_mut()
    }
}

fn pop<T, const N: usize>(bump: &mut RawBump<T, N>) -> Option<T> {
    bump.deallocate().map(|ptr| unsafe { ptr.read() })
}

#[test]
fn bump_with_capacity() {
    unsafe {
        let bump = RawBump::<i32, 0>::with_capacity(0);
        assert_eq!(bump.capacity(), 0);

        let mut bump = RawBump::<i32, 0>::with_capacity(3);
        assert!(bump.capacity() >= 3);
        let inlined_chunk = bump.inlined.get_mut().get();
        let next_chunk = inlined_chunk.next();
        assert_eq!(0, inlined_chunk.capacity());
        assert!(next_chunk.capacity() >= 3 * i32::SIZE);
        assert_eq!(bump.capacity() * i32::SIZE, next_chunk.capacity());

        assert!(!inlined_chunk.prev().is_dead());
        assert!(!inlined_chunk.next().is_dead());

        assert!(next_chunk.prev().is_dead());
        assert!(next_chunk.next().is_dead());

        let mut bump = RawBump::<i32, 5>::with_capacity(5);
        assert_eq!(bump.capacity(), 5);
        let chunk = bump.inlined.get_mut().get();
        assert_eq!(chunk.capacity(), 5 * i32::SIZE);
    }
}

#[test]
fn bump_push_pop_zst() {
    let mut bump = RawBump::<(), 0>::new();
    unsafe {
        bump.allocate();
        assert!(bump.inlined.get_mut().current_chunk().is_dead());
        assert!(bump.inlined.get_mut().next_chunk().is_dead());
        assert_eq!(pop(&mut bump), Some(()));

        bump.deallocate();
        assert!(bump.inlined.get_mut().current_chunk().is_dead());
        assert!(bump.inlined.get_mut().next_chunk().is_dead());
    }
    assert_eq!(pop(&mut bump), None);
}

#[test]
fn bump_push_pop_0() {
    let mut bump = RawBump::<usize, 0>::new();
    let cap_0 = bump.capacity();
    assert_eq!(bump.capacity(), 0);
    assert_eq!(pop(&mut bump), None);
    unsafe {
        assert!(bump.inlined.get_mut().current_chunk().is_dead());
        assert!(bump.inlined.get_mut().next_chunk().is_dead());
    }

    push(&mut bump, cap_0);
    let cap_01 = bump.capacity();
    let cap_1 = cap_01 - cap_0;
    assert_eq!(bump.capacity(), cap_01);
    assert_eq!(pop(&mut bump), Some(cap_0));
    assert!(bump.capacity() > cap_0);
    unsafe {
        let current_chunk = bump.inlined.get_mut().current_chunk();
        let first_chunk = bump.inlined.get_mut().next_chunk();
        assert!(!current_chunk.is_dead());
        assert!(!first_chunk.is_dead());
        assert!(current_chunk.is(first_chunk));
        assert!(current_chunk.next().is_dead());
        assert!(current_chunk.prev().is_dead());
        assert!(first_chunk.next().is_dead());
        assert!(first_chunk.prev().is_dead());
    }

    for i in cap_0..cap_01 {
        push(&mut bump, i);
    }

    push(&mut bump, cap_01);
    assert!(bump.capacity() > cap_01);
    assert_eq!(pop(&mut bump), Some(cap_01));
    assert!(bump.capacity() > cap_01);
    unsafe {
        let current_chunk = bump.inlined.get_mut().current_chunk();
        let first_chunk = bump.inlined.get_mut().next_chunk();
        assert!(!current_chunk.is_dead());
        assert!(!first_chunk.is_dead());
        assert!(!current_chunk.is(first_chunk));
        assert!(current_chunk.next().is_dead());
        assert!(!current_chunk.prev().is_dead());
        assert!(!first_chunk.next().is_dead());
        assert!(first_chunk.prev().is_dead());
    }

    assert_eq!(pop(&mut bump), Some(cap_01 - 1));
    assert!(bump.capacity() > cap_01);
    unsafe {
        let current_chunk = bump.inlined.get_mut().current_chunk();
        let first_chunk = bump.inlined.get_mut().next_chunk();
        assert!(!current_chunk.is_dead());
        assert!(!first_chunk.is_dead());
        assert!(current_chunk.is(first_chunk));
        assert!(!current_chunk.next().is_dead());
        assert!(current_chunk.prev().is_dead());
        assert!(!first_chunk.next().is_dead());
        assert!(first_chunk.prev().is_dead());
    }
    push(&mut bump, cap_01 - 1);

    let cap_012 = bump.capacity();
    let cap_02 = cap_012 - cap_1;
    for i in cap_01..cap_012 {
        push(&mut bump, i);
    }
    for i in (cap_01..cap_012).rev() {
        assert_eq!(pop(&mut bump), Some(i));
    }
    unsafe {
        let current_chunk = bump.inlined.get_mut().current_chunk();
        let first_chunk = bump.inlined.get_mut().next_chunk();
        assert!(!current_chunk.is_dead());
        assert!(!first_chunk.is_dead());
        assert!(!current_chunk.is(first_chunk));
        assert!(current_chunk.next().is_dead());
        assert!(!current_chunk.prev().is_dead());
        assert!(!first_chunk.next().is_dead());
        assert!(first_chunk.prev().is_dead());
    }

    assert_eq!(pop(&mut bump), Some(cap_01 - 1));
    unsafe {
        let current_chunk = bump.inlined.get_mut().current_chunk();
        let first_chunk = bump.inlined.get_mut().next_chunk();
        assert!(!current_chunk.is_dead());
        assert!(!first_chunk.is_dead());
        assert!(current_chunk.is(first_chunk));
        assert!(!current_chunk.next().is_dead());
        assert!(current_chunk.prev().is_dead());
        assert!(!first_chunk.next().is_dead());
        assert!(first_chunk.prev().is_dead());
    }

    for i in (cap_0..cap_01 - 1).rev() {
        assert_eq!(pop(&mut bump), Some(i));
    }
    assert_eq!(bump.capacity(), cap_012);
    unsafe {
        let current_chunk = bump.inlined.get_mut().current_chunk();
        let first_chunk = bump.inlined.get_mut().next_chunk();
        assert!(!current_chunk.is_dead());
        assert!(!first_chunk.is_dead());
        assert!(current_chunk.is(first_chunk));
        assert!(!current_chunk.next().is_dead());
        assert!(current_chunk.prev().is_dead());
        assert!(!first_chunk.next().is_dead());
        assert!(first_chunk.prev().is_dead());
    }

    assert_eq!(pop(&mut bump), None);
    assert_eq!(bump.capacity(), cap_02);
}

#[test]
fn bump_push_pop_n() {
    let mut bump = RawBump::<usize, 5>::new();
    assert_eq!(bump.capacity(), 5);
    assert_eq!(pop(&mut bump), None);

    let cap_0 = bump.capacity();
    for i in 0..cap_0 {
        push(&mut bump, i);
    }

    assert_eq!(bump.capacity(), cap_0);
    unsafe {
        assert!(bump.inlined.get_mut().current_chunk().is_dead());
        assert!(bump.inlined.get_mut().next_chunk().is_dead());
    }

    push(&mut bump, cap_0);
    let cap_01 = bump.capacity();
    let cap_1 = cap_01 - cap_0;
    assert_eq!(bump.capacity(), cap_01);
    assert_eq!(pop(&mut bump), Some(cap_0));
    assert!(bump.capacity() > cap_0);
    unsafe {
        let current_chunk = bump.inlined.get_mut().current_chunk();
        let first_chunk = bump.inlined.get_mut().next_chunk();
        assert!(!current_chunk.is_dead());
        assert!(!first_chunk.is_dead());
        assert!(current_chunk.is(first_chunk));
        assert!(current_chunk.next().is_dead());
        assert!(current_chunk.prev().is_dead());
        assert!(first_chunk.next().is_dead());
        assert!(first_chunk.prev().is_dead());
    }

    for i in cap_0..cap_01 {
        push(&mut bump, i);
    }

    push(&mut bump, cap_01);
    assert!(bump.capacity() > cap_01);
    assert_eq!(pop(&mut bump), Some(cap_01));
    assert!(bump.capacity() > cap_01);
    unsafe {
        let current_chunk = bump.inlined.get_mut().current_chunk();
        let first_chunk = bump.inlined.get_mut().next_chunk();
        assert!(!current_chunk.is_dead());
        assert!(!first_chunk.is_dead());
        assert!(!current_chunk.is(first_chunk));
        assert!(current_chunk.next().is_dead());
        assert!(!current_chunk.prev().is_dead());
        assert!(!first_chunk.next().is_dead());
        assert!(first_chunk.prev().is_dead());
    }

    assert_eq!(pop(&mut bump), Some(cap_01 - 1));
    assert!(bump.capacity() > cap_01);
    unsafe {
        let current_chunk = bump.inlined.get_mut().current_chunk();
        let first_chunk = bump.inlined.get_mut().next_chunk();
        assert!(!current_chunk.is_dead());
        assert!(!first_chunk.is_dead());
        assert!(current_chunk.is(first_chunk));
        assert!(!current_chunk.next().is_dead());
        assert!(current_chunk.prev().is_dead());
        assert!(!first_chunk.next().is_dead());
        assert!(first_chunk.prev().is_dead());
    }
    push(&mut bump, cap_01 - 1);

    let cap_012 = bump.capacity();
    let cap_02 = cap_012 - cap_1;
    for i in cap_01..cap_012 {
        push(&mut bump, i);
    }
    for i in (cap_01..cap_012).rev() {
        assert_eq!(pop(&mut bump), Some(i));
    }
    unsafe {
        let current_chunk = bump.inlined.get_mut().current_chunk();
        let first_chunk = bump.inlined.get_mut().next_chunk();
        assert!(!current_chunk.is_dead());
        assert!(!first_chunk.is_dead());
        assert!(!current_chunk.is(first_chunk));
        assert!(current_chunk.next().is_dead());
        assert!(!current_chunk.prev().is_dead());
        assert!(!first_chunk.next().is_dead());
        assert!(first_chunk.prev().is_dead());
    }

    assert_eq!(pop(&mut bump), Some(cap_01 - 1));
    unsafe {
        let current_chunk = bump.inlined.get_mut().current_chunk();
        let first_chunk = bump.inlined.get_mut().next_chunk();
        assert!(!current_chunk.is_dead());
        assert!(!first_chunk.is_dead());
        assert!(current_chunk.is(first_chunk));
        assert!(!current_chunk.next().is_dead());
        assert!(current_chunk.prev().is_dead());
        assert!(!first_chunk.next().is_dead());
        assert!(first_chunk.prev().is_dead());
    }

    for i in (cap_0..cap_01 - 1).rev() {
        assert_eq!(pop(&mut bump), Some(i));
    }
    assert_eq!(bump.capacity(), cap_012);
    unsafe {
        let current_chunk = bump.inlined.get_mut().current_chunk();
        let first_chunk = bump.inlined.get_mut().next_chunk();
        assert!(!current_chunk.is_dead());
        assert!(!first_chunk.is_dead());
        assert!(current_chunk.is(first_chunk));
        assert!(!current_chunk.next().is_dead());
        assert!(current_chunk.prev().is_dead());
        assert!(!first_chunk.next().is_dead());
        assert!(first_chunk.prev().is_dead());
    }

    assert_eq!(pop(&mut bump), Some(cap_0 - 1));
    assert_eq!(bump.capacity(), cap_02);

    for i in (0..cap_0 - 1).rev() {
        assert_eq!(pop(&mut bump), Some(i));
    }
    assert_eq!(pop(&mut bump), None);
    assert_eq!(bump.capacity(), cap_02);
}

#[test]
fn bump_index() {
    let mut bump = RawBump::<_, 0>::new();
    push(&mut bump, 1);
    push(&mut bump, 2);
    push(&mut bump, 3);
    push(&mut bump, 4);
    push(&mut bump, 5);
    unsafe {
        assert_eq!(bump.index(0).read(), 1);
        assert_eq!(bump.index(1).read(), 2);
        assert_eq!(bump.index(2).read(), 3);
        assert_eq!(bump.index(3).read(), 4);
        assert_eq!(bump.index(4).read(), 5);
    }

    let mut bump = RawBump::<_, 2>::new();

    push(&mut bump, 1);
    push(&mut bump, 2);
    push(&mut bump, 3);
    push(&mut bump, 4);
    push(&mut bump, 5);
    unsafe {
        assert_eq!(bump.index(0).read(), 1);
        assert_eq!(bump.index(1).read(), 2);
        assert_eq!(bump.index(2).read(), 3);
        assert_eq!(bump.index(3).read(), 4);
        assert_eq!(bump.index(4).read(), 5);
    }

    let mut bump = RawBump::<_, 0>::new();
    push(&mut bump, ());
    push(&mut bump, ());
    push(&mut bump, ());
    push(&mut bump, ());
    push(&mut bump, ());
    unsafe {
        assert_eq!(bump.index(0).read(), ());
        assert_eq!(bump.index(1).read(), ());
        assert_eq!(bump.index(2).read(), ());
        assert_eq!(bump.index(3).read(), ());
        assert_eq!(bump.index(4).read(), ());
    }
}