use core::fmt;
use core::ops::Range;
use core::ptr::NonNull;
use static_assertions::const_assert;
#[repr(C, align(16))]
pub struct FreeHeader {
next: Option<FreeBlock>,
size: usize,
}
const HEADER_SIZE: usize = 16;
const_assert!(HEADER_SIZE >= core::mem::size_of::<FreeHeader>());
pub enum Relation {
Before,
AdjacentBefore,
Overlapping,
AdjacentAfter,
After,
}
impl FreeHeader {
#[allow(clippy::cast_ptr_alignment)]
pub unsafe fn from_raw(
ptr: NonNull<u8>,
next: Option<FreeBlock>,
size: usize,
) -> NonNull<FreeHeader> {
let header = FreeHeader { next, size };
let raw_ptr: NonNull<FreeHeader> = ptr.cast();
core::ptr::write(ptr.as_ptr() as *mut FreeHeader, header);
raw_ptr
}
}
pub struct FreeBlock {
header: NonNull<FreeHeader>,
}
impl Drop for FreeBlock {
fn drop(&mut self) {
debug_assert!(false, "Leaking memory!!");
}
}
impl FreeBlock {
#[must_use]
pub unsafe fn from_raw(ptr: NonNull<u8>, next: Option<FreeBlock>, size: usize) -> FreeBlock {
debug_assert!(
size >= HEADER_SIZE,
"Can't recapture a block smaller than HEADER_SIZE"
);
let header = FreeHeader::from_raw(ptr, next, size);
FreeBlock { header }
}
pub fn as_slice(&self) -> &[u8] {
unsafe {
let size = self.header_view().size;
core::slice::from_raw_parts(self.header.as_ptr() as *const u8, size)
}
}
pub fn as_range(&self) -> Range<*const u8> {
unsafe {
let size = self.header_view().size;
let start = self.header.as_ptr() as *const u8;
start..(start.add(size))
}
}
#[must_use]
pub fn decompose(mut self) -> (Range<NonNull<u8>>, Option<FreeBlock>) {
let next = self.take_next();
let range = unsafe {
let size = self.header_view().size;
let start: NonNull<u8> = self.header.cast();
let end: NonNull<u8> =
NonNull::new_unchecked(self.header.as_ptr().add(size) as *mut u8);
start..end
};
core::mem::forget(self);
(range, next)
}
fn relation(&self, other: &Self) -> Relation {
let self_range = self.as_range();
let other_range = other.as_range();
if self_range.end < other_range.start {
Relation::Before
} else if self_range.end == other_range.start {
Relation::AdjacentBefore
} else if self_range.start < other_range.end {
Relation::Overlapping
} else if self_range.start == other_range.end {
Relation::AdjacentAfter
} else {
Relation::After
}
}
fn next(&self) -> Option<&Self> {
(&self.header_view().next).into()
}
fn next_mut(&mut self) -> Option<&mut Self> {
unsafe { (&mut self.header_mut().next).into() }
}
#[must_use]
fn take_next(&mut self) -> Option<Self> {
unsafe { (&mut self.header_mut().next).take() }
}
#[must_use]
fn replace_next(&mut self, new_next: FreeBlock) -> Option<Self> {
unsafe { (&mut self.header_mut().next).replace(new_next) }
}
pub fn size(&self) -> usize {
self.header_view().size
}
pub fn header_view(&self) -> &FreeHeader {
unsafe { self.header.as_ref() }
}
pub unsafe fn header_mut(&mut self) -> &mut FreeHeader {
self.header.as_mut()
}
#[must_use]
pub fn pop_next(&mut self) -> Option<FreeBlock> {
let mut next = match self.take_next() {
None => {
return None;
}
Some(n) => n,
};
if let Some(next_next) = next.take_next() {
assert!(self.replace_next(next_next).is_none());
}
Some(next)
}
pub fn insert(&mut self, block: FreeBlock) {
let next_next = self.replace_next(block);
let inserting_next = match next_next {
None => self.next_mut().unwrap().take_next(),
Some(next_next_block) => self.next_mut().unwrap().replace_next(next_next_block),
};
assert!(inserting_next.is_none());
}
pub fn insert_merge(&mut self, block: FreeBlock) -> usize {
let this_end = self.as_range().end;
let other_start = block.as_range().start;
assert!(block.next().is_none());
let (merges, try_next) = if this_end == other_start {
let new_size = block.size();
unsafe {
self.header_mut().size += new_size;
core::mem::forget(block);
}
(1, self)
} else {
self.insert(block);
(0, self.next_mut().unwrap())
};
merges + if try_next.try_merge_next() { 1 } else { 0 }
}
pub fn split(&mut self, size: usize) -> Range<NonNull<u8>> {
debug_assert!(
size + HEADER_SIZE <= self.header_view().size,
"Can't split a block of size {} off of a block of size {} - need {} for header",
size,
self.header_view().size,
HEADER_SIZE
);
unsafe {
let self_size = self.size();
let header = self.header_mut();
header.size -= size;
let start =
NonNull::new_unchecked((header as *mut FreeHeader as *mut u8).add(header.size));
let end = NonNull::new_unchecked((header as *mut FreeHeader as *mut u8).add(self_size));
start..end
}
}
pub fn try_merge_next(&mut self) -> bool {
let (next_start, next_size) = match self.next() {
None => return false,
Some(block) => (block.as_range().start, block.size()),
};
if self.as_range().end != next_start {
return false;
};
unsafe {
let header = self.header_mut();
header.size += next_size;
let mut next = header.next.take().unwrap();
header.next = next.take_next();
core::mem::forget(next);
}
true
}
}
pub struct BlockList {
first: Option<FreeBlock>,
}
pub struct BlockIter<'list> {
next: Option<&'list FreeBlock>,
}
impl<'list> Iterator for BlockIter<'list> {
type Item = &'list FreeBlock;
fn next(&mut self) -> Option<Self::Item> {
let next = self.next.take()?;
self.next = next.next();
Some(next)
}
}
unsafe impl Send for FreeBlock {}
impl Default for BlockList {
fn default() -> Self {
BlockList { first: None }
}
}
impl<'list> IntoIterator for &'list BlockList {
type Item = &'list FreeBlock;
type IntoIter = BlockIter<'list>;
fn into_iter(self) -> Self::IntoIter {
BlockIter {
next: self.first.as_ref(),
}
}
}
impl fmt::Display for BlockList {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "BlockList(")?;
let mut start = true;
for block in self {
if !start {
write!(f, ", ")?;
} else {
start = false;
}
write!(f, "FreeBlock({:?}, {})", block.header, block.size())?;
}
write!(f, ")")
}
}
#[derive(Default, Debug)]
pub struct Validity {
pub overlaps: usize,
pub adjacents: usize,
pub out_of_orders: usize,
}
impl Validity {
pub fn is_valid(&self) -> bool {
self.overlaps == 0 && self.adjacents == 0 && self.out_of_orders == 0
}
}
impl From<Validity> for bool {
fn from(v: Validity) -> bool {
v.is_valid()
}
}
#[derive(Default, Debug)]
pub struct Stats {
pub length: usize,
pub size: usize,
}
pub enum ApplyState<C, R> {
Continue(C),
Finished(R),
Fail(C),
}
impl BlockList {
pub const fn header_size() -> usize {
HEADER_SIZE
}
pub fn iter(&self) -> BlockIter {
BlockIter {
next: self.first.as_ref(),
}
}
pub fn apply<C, R, F: FnMut(&mut FreeBlock, C) -> ApplyState<C, R>>(
&mut self,
start: C,
mut pred: F,
) -> ApplyState<C, R> {
let mut next = self.first.as_mut();
let mut state = start;
while let Some(block) = next.take() {
state = match pred(block, state) {
ApplyState::Continue(c) => c,
ApplyState::Finished(r) => return ApplyState::Finished(r),
ApplyState::Fail(c) => return ApplyState::Fail(c),
};
next = block.next_mut()
}
ApplyState::Continue(state)
}
pub fn stats(&self) -> (Validity, Stats) {
let mut validity: Validity = Default::default();
let mut stats: Stats = Default::default();
let mut previous: Option<&FreeBlock> = None;
for next in self.iter() {
match previous.map(|p| p.relation(&next)) {
Some(Relation::Before) => {
}
Some(Relation::AdjacentBefore) => {
validity.adjacents += 1;
}
Some(Relation::Overlapping) => {
validity.overlaps += 1;
}
Some(Relation::AdjacentAfter) => {
validity.out_of_orders += 1;
validity.adjacents += 1;
}
Some(Relation::After) => {
validity.out_of_orders += 1;
}
None => {
}
}
stats.length += 1;
stats.size += next.size();
previous = Some(next);
}
(validity, stats)
}
pub fn pop_size(&mut self, size: usize) -> Option<Range<NonNull<u8>>> {
let first_size = self.first.as_ref()?.size();
if first_size == size {
let (range, next) = self.first.take()?.decompose();
self.first = next;
return Some(range);
} else if first_size >= size + HEADER_SIZE {
let split = self.first.as_mut()?.split(size);
return Some(split);
}
let applied = self.apply((), |previous, ()| {
let next_size: usize = match previous.next() {
None => return ApplyState::Fail(()),
Some(next) => next.size(),
};
if next_size == size {
let block = previous.pop_next().unwrap();
let (range, next) = block.decompose();
assert!(next.is_none());
return ApplyState::Finished(range);
}
if next_size < size + HEADER_SIZE {
return ApplyState::Continue(());
}
let ptr = previous.next_mut().unwrap().split(size);
ApplyState::Finished(ptr)
});
match applied {
ApplyState::Continue(()) => None,
ApplyState::Fail(()) => None,
ApplyState::Finished(ptr) => Some(ptr),
}
}
pub unsafe fn add_block(&mut self, ptr: NonNull<u8>, size: usize) {
let mut new_block = FreeBlock::from_raw(ptr, None, size);
let first: &FreeBlock = match self.first {
None => {
self.first = Some(new_block);
return;
}
Some(ref p) => p,
};
match new_block.relation(first) {
Relation::Before => {
match self.first.take() {
None => {}
Some(b) => assert!(new_block.replace_next(b).is_none()),
};
self.first = Some(new_block);
return;
}
Relation::AdjacentBefore => {
match self.first.take() {
None => {}
Some(b) => assert!(new_block.replace_next(b).is_none()),
};
let merged = new_block.try_merge_next();
self.first = Some(new_block);
assert!(merged, "They were adjacent, they should merge");
return;
}
Relation::Overlapping => {
debug_assert!(false, "Overlapping memory blocks OH NO");
}
Relation::AdjacentAfter => {
let first = self.first.as_mut().unwrap();
first.header_mut().size += size;
core::mem::forget(new_block);
first.try_merge_next();
return;
}
_ => {}
}
let applied = self.apply(new_block, |previous, new_block| {
let next = match previous.next() {
Some(n) => n,
None => {
previous.insert_merge(new_block);
return ApplyState::Finished(());
}
};
if next.header.cast() < ptr {
return ApplyState::Continue(new_block);
}
previous.insert_merge(new_block);
ApplyState::Finished(())
});
match applied {
ApplyState::Finished(()) => (),
ApplyState::Fail(_) => unreachable!(),
ApplyState::Continue(_) => unreachable!(),
};
}
pub fn len(&self) -> usize {
self.iter().count()
}
pub fn is_empty(&self) -> bool {
self.first.is_none()
}
}