o3 0.36.2

shared-nothing primitives
Documentation
pub mod common;

use std::{cell::Cell, mem, ptr};

use common::alloc::{
    Aligned,
    system::Tracker,
    tail::{Entry, Header},
};
use o3::alloc::{self, tail};

#[global_allocator]
static ALLOCATOR: Tracker = Tracker;

#[test]
fn initializes_exact_tail() {
    for count in [0, 3] {
        let drops = Cell::new(Some(0));
        let observed = Cell::new(None);
        let plan = tail::Plan::<Header<'_>, Entry<'_>>::try_new(count).expect("tail layout");
        let bytes = (count + 1) * mem::size_of::<Entry<'_>>();
        let freed = {
            let (memory, cold) = Tracker::measure(|| plan.try_allocate());
            assert_eq!(cold, [1, bytes, 0, 0]);
            let memory = memory.expect("header and exact tail allocation");
            let (block, init) = Tracker::measure(|| {
                memory.fill(
                    Header {
                        drops: &drops,
                        observed: &observed,
                    },
                    |_, index| Entry::new(index),
                )
            });
            assert_eq!(init, [0; 4]);
            let values = tail::View::new(&block).as_slice();
            assert_eq!(values.len(), count);
            assert_eq!(values.as_ptr().addr() % 128, 0);
            for (index, slot) in values.iter().enumerate() {
                slot.drops.set(Some(&drops));
                assert_eq!(slot.index, index);
            }
            Tracker::begin()
        };
        assert_eq!(
            freed.finish(),
            common::alloc::system::Activity {
                allocations: 0,
                allocated_bytes: 0,
                deallocations: 1,
                deallocated_bytes: bytes
            }
        );
        assert_eq!(drops.get(), Some(count + 1));
        assert_eq!(observed.get(), Some(Some(count)));
    }
}

#[test]
fn failure_is_inert() {
    let plan = tail::Plan::<Header<'_>, Entry<'_>>::fixed::<3>();
    let (memory, activity) = Tracker::measure(|| Tracker::fail_after(0, || plan.try_allocate()));
    assert!(matches!(memory, Err(alloc::Exhausted)));
    assert_eq!(activity, [0; 4]);
}

#[test]
fn recovers_aligned_owner() {
    use std::num::NonZero;

    let drops = Cell::new(Some(0));
    let observed = Cell::new(None);
    {
        let count = NonZero::new(3u32).expect("nonzero tail");
        let block = tail::Plan::<Header<'_>, Entry<'_>, _>::try_new(count)
            .expect("aligned layout")
            .try_allocate()
            .expect("tail allocation")
            .fill(
                Header {
                    drops: &drops,
                    observed: &observed,
                },
                |_, index| Entry::new(index as usize),
            );
        for index in 0..count.get() {
            // SAFETY: the loop visits each exact initialized resident once.
            let resident = unsafe { alloc::raw::Resident::new(tail::View::new(&block), index) };
            let entry = resident.get();
            entry.drops.set(Some(&drops));
            entry.value.set(index as usize + 7);
            // SAFETY: each entry stores its immutable original construction ordinal.
            let view = unsafe { resident.view(entry.index as u32) };
            assert!(std::ptr::eq(
                view.header(),
                tail::View::new(&block).header()
            ));
            assert!(std::ptr::eq(
                view.as_slice(),
                tail::View::new(&block).as_slice()
            ));
            assert_eq!(
                view.as_slice()[index as usize].value.get(),
                index as usize + 7
            );
        }
    }
    assert_eq!(drops.get(), Some(4));
    assert_eq!(observed.get(), Some(Some(3)));
}

#[test]
fn layout_is_exact() {
    const LEN: usize = 257;
    const BYTES: usize = (2 + LEN) * mem::size_of::<u64>();
    let released = {
        let (memory, cold) =
            Tracker::measure(|| tail::Plan::<u64, u64>::fixed::<LEN>().try_allocate());
        assert_eq!(cold, [1, BYTES, 0, 0]);
        let memory = memory.expect("exact tail allocation");
        let (block, hot) = Tracker::measure(|| memory.fill(7, |_, index| index as u64));
        assert_eq!(hot, [0; 4]);
        assert_eq!(*tail::View::new(&block).header(), 7);
        assert_eq!(tail::View::new(&block).as_slice().len(), LEN);
        assert_eq!(tail::View::new(&block).as_slice()[17], 17);
        Tracker::begin()
    };
    assert_eq!(
        released.finish(),
        common::alloc::system::Activity {
            allocations: 0,
            allocated_bytes: 0,
            deallocations: 1,
            deallocated_bytes: BYTES
        }
    );
}

#[test]
fn preserves_header_address() {
    let memory = tail::Plan::<u64, ptr::NonNull<u64>>::fixed::<3>()
        .try_allocate()
        .expect("header with three resident pointers");
    let block = memory.fill(23, |header, _| ptr::NonNull::from(header));
    for pointer in tail::View::new(&block).as_slice() {
        assert_eq!(
            *pointer,
            ptr::NonNull::from(tail::View::new(&block).header())
        );
    }
}

#[test]
fn preserves_alignment() {
    for count in [0, 3] {
        let memory = tail::Plan::<u8, Aligned>::try_new(count)
            .expect("small aligned layout")
            .try_allocate()
            .expect("aligned allocation");
        let block = memory.fill(11, |_, index| Aligned(index as u8));
        assert_eq!(tail::View::new(&block).as_slice().as_ptr() as usize % 64, 0);
        assert!(
            tail::View::new(&block)
                .as_slice()
                .iter()
                .map(|value| value.0)
                .eq(0..count as u8)
        );
    }
}

#[test]
fn initializes_zero_sizes() {
    for count in [0, 17] {
        let memory = tail::Plan::<u8, ()>::try_new(count)
            .expect("zero-sized layout")
            .try_allocate()
            .expect("header allocation");
        let mut written = 0;
        let block = memory.fill(4, |_, index| {
            assert_eq!(index, written);
            written += 1;
        });
        assert_eq!(written, count);
        assert_eq!(tail::View::new(&block).as_slice().len(), count);
    }
}