use core::{
alloc::Layout,
hint::assert_unchecked,
marker::PhantomData,
mem::offset_of,
ops::{Add, Sub},
ptr::NonNull,
};
use ecore::int::{CInt, PrimaryUInt};
use crate::ptr::Ptr;
use super::{Block, assert_element_type};
#[repr(transparent)]
pub struct ElementCount<StateElement, Element>(StateElement, PhantomData<Element>);
impl<StateElement: Copy, Element> Copy for ElementCount<StateElement, Element> {}
impl<StateElement: Clone, Element> Clone for ElementCount<StateElement, Element> {
fn clone(&self) -> Self {
Self(self.0.clone(), PhantomData)
}
}
impl<StateElement: Eq, Element> Eq for ElementCount<StateElement, Element> {}
impl<StateElement: PartialEq, Element> PartialEq for ElementCount<StateElement, Element> {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl<StateElement: Ord, Element> Ord for ElementCount<StateElement, Element> {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.0.cmp(&other.0)
}
}
impl<StateElement: PartialOrd, Element> PartialOrd for ElementCount<StateElement, Element> {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
self.0.partial_cmp(&other.0)
}
}
impl<StateElement: PrimaryUInt, Element> ElementCount<StateElement, Element> {
pub const IS_USIZE: bool = {
assert!(size_of::<StateElement>() <= size_of::<usize>());
size_of::<StateElement>() == size_of::<usize>()
};
pub const ZERO: Self = Self(StateElement::ZERO, PhantomData);
const MAX_UNDERLYING: usize = if Self::IS_USIZE { usize::MAX >> 1 } else { CInt::cast_as(CInt::shr(StateElement::MAX, 1u32)) };
pub const MAX: Self = {
if Self::IS_USIZE {
Self(CInt::cast_as((usize::MAX >> 1) / size_of::<Element>() * size_of::<Element>()), PhantomData)
} else {
Self(CInt::shr(StateElement::MAX, 1u32), PhantomData)
}
};
pub const fn max_for_bits<const BITS: usize>() -> Self {
assert_element_type::<Element>();
const {
assert!((BITS as u32) < StateElement::BITS);
let remain = StateElement::BITS - BITS as u32;
if Self::IS_USIZE {
Self(CInt::cast_as((usize::MAX >> 1) / size_of::<Element>() * size_of::<Element>()), PhantomData)
} else {
Self(CInt::shr(StateElement::MAX, remain), PhantomData)
}
}
}
pub const fn max_for_count(count: usize) -> Self {
assert_element_type::<Element>();
if count >= Self::MAX.to_count() {
Self::MAX
} else if Self::IS_USIZE {
Self(CInt::cast_as(count * size_of::<Element>()), PhantomData)
} else {
Self(CInt::cast_as(count), PhantomData)
}
}
pub const fn max_for_bytes(bytes: usize) -> Self {
Self::max_for_count(bytes / size_of::<Element>())
}
pub const fn from_bytes_floor(bytes: usize) -> Option<Self> {
assert_element_type::<Element>();
let max = const { Self::MAX.to_count() };
let count = bytes / size_of::<Element>();
if Self::IS_USIZE {
if count <= max { Some(Self(CInt::cast_as(count * size_of::<Element>()), PhantomData)) } else { None }
} else {
if count <= max { Some(Self(CInt::cast_as(count), PhantomData)) } else { None }
}
}
const fn from_bytes_ceil(bytes: usize) -> Option<Self> {
assert_element_type::<Element>();
let max = const { Self::MAX.to_bytes() };
if Self::IS_USIZE {
if bytes <= max { Some(Self(CInt::cast_as(bytes.next_multiple_of(size_of::<Element>())), PhantomData)) } else { None }
} else {
if bytes <= max { Some(Self(CInt::cast_as(bytes.div_ceil(size_of::<Element>())), PhantomData)) } else { None }
}
}
#[inline(always)]
pub const fn min_for<Node>() -> Self {
const {
assert!(align_of::<Node>() <= align_of::<Element>());
Self::raw_calc(Layout::new::<Node>()).unwrap()
}
}
#[inline(always)]
pub const fn for_layout<Node>(layout: Layout) -> Option<Self> {
Self::min_for::<Node>().sat_layout(layout)
}
pub const fn is_zero(self) -> bool {
CInt::is_zero(self.0)
}
pub const fn underlying(self) -> usize {
CInt::cast_as(self.0)
}
pub const fn to_bytes(self) -> usize {
if Self::IS_USIZE { self.underlying() } else { self.underlying() * size_of::<Element>() }
}
pub const fn to_count(self) -> usize {
if Self::IS_USIZE { self.underlying() / size_of::<Element>() } else { self.underlying() }
}
pub const fn usable_bytes_len(self) -> usize {
self.to_bytes() - Joint::<StateElement, Element>::SIZE
}
pub fn get_from_block(block: NonNull<u8>) -> Self {
assert_element_type::<Element>();
Ptr::<Block<StateElement, Element>>::new(block.cast()).head_state().element_count()
}
const fn raw_calc(layout: Layout) -> Option<Self> {
let size = layout.size();
let align = layout.align();
let align = if align <= Joint::<StateElement, Element>::ALIGN { Joint::<StateElement, Element>::ALIGN } else { align };
unsafe { assert_unchecked(align.is_power_of_two()) };
ElementCount::from_bytes_ceil((size + Joint::<StateElement, Element>::SIZE).next_multiple_of(align))
}
const fn sat_layout(self, layout: Layout) -> Option<Self> {
let Some(count) = Self::raw_calc(layout) else { return None };
Some(if count.underlying() <= self.underlying() { self } else { count })
}
pub const fn add(self, rhs: Self) -> Self {
debug_assert!(self.underlying() + rhs.underlying() <= Self::MAX_UNDERLYING);
Self(CInt::add(self.0, rhs.0), PhantomData)
}
}
impl<StateElement: PrimaryUInt, Element> Add for ElementCount<StateElement, Element> {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
debug_assert!(self.underlying() + rhs.underlying() <= Self::MAX_UNDERLYING);
Self(self.0 + rhs.0, PhantomData)
}
}
impl<StateElement: PrimaryUInt, Element> Sub for ElementCount<StateElement, Element> {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Self(self.0 - rhs.0, PhantomData)
}
}
#[repr(transparent)]
pub(super) struct State<StateElement, Element>(StateElement, PhantomData<Element>);
impl<StateElement: Copy, Element> Copy for State<StateElement, Element> {}
impl<StateElement: Clone, Element> Clone for State<StateElement, Element> {
fn clone(&self) -> Self {
Self(self.0.clone(), PhantomData)
}
}
impl<StateElement: Eq, Element> Eq for State<StateElement, Element> {}
impl<StateElement: PartialEq, Element> PartialEq for State<StateElement, Element> {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl<StateElement: PrimaryUInt, Element> State<StateElement, Element> {
pub(super) fn new(element_count: ElementCount<StateElement, Element>, free: bool) -> Self {
if ElementCount::<StateElement, Element>::IS_USIZE {
Self(element_count.0 | if free { StateElement::ONE } else { StateElement::ZERO }, PhantomData)
} else {
Self(element_count.0 << 1u32 | if free { StateElement::ONE } else { StateElement::ZERO }, PhantomData)
}
}
pub(super) fn element_count(self) -> ElementCount<StateElement, Element> {
if ElementCount::<StateElement, Element>::IS_USIZE {
ElementCount(self.0 & const { CInt::not(StateElement::ONE) }, PhantomData)
} else {
ElementCount(self.0 >> 1u32, PhantomData)
}
}
pub(super) fn is_free(self) -> bool {
self.0 & StateElement::ONE != StateElement::ZERO
}
}
impl<StateElement: PrimaryUInt, Element> Ptr<State<StateElement, Element>> {
#[inline(always)]
pub(super) fn element_count(self) -> ElementCount<StateElement, Element> {
self.read().element_count()
}
#[inline(always)]
pub(super) fn is_free(self) -> bool {
self.read().is_free()
}
#[inline(always)]
pub(super) fn bytes_len(self) -> usize {
self.element_count().to_bytes()
}
#[inline(always)]
pub(super) fn usable_bytes_len(self) -> usize {
if ElementCount::<StateElement, Element>::IS_USIZE {
CInt::cast_as::<_, usize>(self.read().0) - Joint::<StateElement, Element>::SIZE
} else {
CInt::cast_as::<_, usize>(self.read().0) * const { size_of::<Element>() / 2 } - Joint::<StateElement, Element>::SIZE
}
}
}
#[repr(C)]
pub(super) struct Joint<StateElement, Element> {
pub(super) low_state: State<StateElement, Element>,
pub(super) high_state: State<StateElement, Element>,
}
impl<StateElement, Element> Joint<StateElement, Element> {
pub(super) const SIZE: usize = size_of::<Self>();
pub(super) const ALIGN: usize = align_of::<Self>();
}
impl<StateElement, Element> Ptr<Joint<StateElement, Element>> {
#[inline(always)]
pub(super) fn low_state(self) -> Ptr<State<StateElement, Element>> {
const { assert!(offset_of!(Joint<StateElement, Element>, low_state) == 0) }
self.cast()
}
}