use std::{num::NonZero, ptr};
use crate::runtime::{heap, raw::Memory};
pub(super) struct Segment<'a> {
pub(super) arena: &'a heap::raw::Arena,
pub(super) index: heap::raw::Index,
pub(super) order: heap::raw::Level,
}
pub(super) struct Vacant<'a> {
source: &'a mut heap::raw::State,
block: Block<'a>,
}
pub(super) struct Occupied<'a> {
pub(super) source: &'a mut heap::raw::State,
pub(super) block: Block<'a>,
}
pub(super) struct Block<'a> {
pub(super) arena: &'a heap::raw::Arena,
pub(super) index: heap::raw::Index,
pub(super) order: heap::raw::Order,
}
impl<'a> Segment<'a> {
pub(super) fn reserve(
mut self,
source: &'a mut heap::raw::State,
order: heap::raw::Order,
) -> Vacant<'a> {
for position in (order.index()..self.order.index()).rev() {
let level = heap::raw::Level::mask(position as u8);
self.order = level;
let width = 1usize.wrapping_shl(level.index() as u32);
let index = unsafe { NonZero::new_unchecked(self.index.0.get() + width) };
source.link(Self {
arena: self.arena,
index: heap::raw::Index(index),
order: self.order,
});
}
Vacant {
source,
block: Block {
arena: self.arena,
index: self.index,
order,
},
}
}
}
impl Vacant<'_> {
pub(super) fn publish(self) -> *mut u8 {
let pointer = self.block.write();
self.source.allocations += 1;
pointer
}
fn replace(self, old: Block<'_>) -> *mut u8 {
let pointer = self.block.write();
unsafe {
ptr::copy_nonoverlapping(old.pointer(), pointer, heap::raw::payload_bytes(old.order))
};
self.source.recycle(old.into_segment());
pointer
}
}
impl Occupied<'_> {
pub(super) fn release(self) -> Option<Memory> {
self.source.allocations -= 1;
self.source.recycle(self.block.into_segment());
if self.source.is_empty() {
self.source.release.take()
} else {
None
}
}
pub(super) fn grow(self, order: heap::raw::Order) -> *mut u8 {
let Self { source, block } = self;
source.reserve(block.arena, order, |next| next.replace(block))
}
}
impl<'a> Block<'a> {
fn pointer(&self) -> *mut u8 {
unsafe { self.arena.block(self.index).add(heap::raw::Header::BYTES) }
}
fn write(&self) -> *mut u8 {
self.arena.set_control(self.index, self.order.index() as u8);
unsafe {
self.arena
.block(self.index)
.cast::<heap::raw::Header>()
.write(heap::raw::Header::new(
heap::raw::Owner::new(self.arena),
self.order,
))
};
self.pointer()
}
fn into_segment(self) -> Segment<'a> {
Segment {
arena: self.arena,
index: self.index,
order: self.order.widen(),
}
}
}
pub(super) struct Partition<'a> {
arena: &'a heap::raw::Arena,
offset: usize,
left: usize,
}
impl<'a> Partition<'a> {
pub(super) fn new(arena: &'a heap::raw::Arena) -> Self {
Self {
arena,
offset: 0,
left: arena.units(),
}
}
}
impl<'a> Iterator for Partition<'a> {
type Item = Segment<'a>;
fn next(&mut self) -> Option<Self::Item> {
let left = NonZero::new(self.left)?;
let order = heap::raw::Level::mask(left.ilog2() as u8);
let index = heap::raw::Index(unsafe { NonZero::new_unchecked(self.offset + 1) });
let width = 1usize.wrapping_shl(order.index() as u32);
self.offset += width;
self.left -= width;
Some(Segment {
arena: self.arena,
index,
order,
})
}
}