rarena-allocator 0.6.0

Lock-free ARENA allocator which can be used in both memory and on-disk.
Documentation
use core::{mem, ptr};

#[cfg(not(feature = "loom"))]
pub(crate) use core::cell::UnsafeCell;
#[cfg(not(feature = "loom"))]
pub(crate) use std::alloc::{Layout, alloc_zeroed, dealloc};

#[cfg(feature = "loom")]
pub(crate) use loom::{
  alloc::{Layout, alloc_zeroed, dealloc},
  cell::UnsafeCell,
};

#[cfg(not(feature = "loom"))]
pub(crate) use core::sync::atomic::*;

#[cfg(feature = "loom")]
pub(crate) use loom::sync::atomic::*;

pub(crate) trait UnsafeCellExt<T> {
  fn as_inner_ptr(&self) -> *const T;
  fn as_inner_mut(&self) -> *mut T;
  #[inline]
  fn as_inner_ref(&self) -> &T {
    unsafe { &*self.as_inner_ptr() }
  }
  #[inline]
  #[allow(clippy::mut_from_ref)]
  fn as_inner_ref_mut(&self) -> &mut T {
    unsafe { &mut *self.as_inner_mut() }
  }
}

impl<T> UnsafeCellExt<T> for core::cell::UnsafeCell<T> {
  #[inline]
  fn as_inner_ptr(&self) -> *const T {
    self.get()
  }

  #[inline]
  fn as_inner_mut(&self) -> *mut T {
    self.get()
  }
}

#[cfg(feature = "loom")]
impl<T> UnsafeCellExt<T> for loom::cell::UnsafeCell<T> {
  #[inline]
  fn as_inner_ptr(&self) -> *const T {
    unsafe { self.get().deref() }
  }

  #[inline]
  fn as_inner_mut(&self) -> *mut T {
    unsafe { self.get_mut().deref() }
  }
}

#[derive(Debug)]
pub(super) struct AlignedVec {
  pub(super) ptr: ptr::NonNull<u8>,
  pub(super) cap: usize,
  pub(super) align: usize,
}

impl Drop for AlignedVec {
  #[inline]
  fn drop(&mut self) {
    if self.cap != 0 {
      unsafe {
        dealloc(self.ptr.as_ptr(), self.layout());
      }
    }
  }
}

impl AlignedVec {
  #[inline]
  pub(super) fn new<H>(capacity: usize, align: usize) -> Self {
    let align = align.max(mem::align_of::<H>());
    assert!(
      capacity <= Self::max_capacity(align),
      "`capacity` cannot exceed isize::MAX - {}",
      align - 1
    );

    let ptr = unsafe {
      let layout = Layout::from_size_align_unchecked(capacity, align);
      let ptr = alloc_zeroed(layout);
      if ptr.is_null() {
        std::alloc::handle_alloc_error(layout);
      }
      ptr::NonNull::new_unchecked(ptr)
    };

    Self {
      ptr,
      cap: capacity,
      align,
    }
  }

  #[inline]
  pub(super) const fn max_capacity(align: usize) -> usize {
    isize::MAX as usize - (align - 1)
  }

  #[inline]
  pub(super) const fn layout(&self) -> std::alloc::Layout {
    unsafe { std::alloc::Layout::from_size_align_unchecked(self.cap, self.align) }
  }

  #[inline]
  pub(super) fn as_mut_ptr(&mut self) -> *mut u8 {
    self.ptr.as_ptr()
  }
}