#![allow(rustdoc::private_intra_doc_links)]
use num_traits::{One, Zero};
use std::alloc;
use std::mem::MaybeUninit;
use std::ops::{Add, Range};
#[cfg_attr(feature = "bucket-array", visibility::make(pub))]
pub(crate) unsafe trait Uninit: Copy {
fn alloc() -> Box<Self> {
unsafe {
let layout = alloc::Layout::new::<Self>();
let ptr: *mut Self = std::mem::transmute(alloc::alloc(layout));
Box::from_raw(ptr)
}
}
}
#[cfg_attr(feature = "bucket-array", visibility::make(pub))]
#[derive(Copy, Clone)]
pub(crate) struct BucketArrayMemory<
const N: usize,
const M: usize,
T: Copy,
>([[MaybeUninit<T>; M]; N]);
unsafe impl<const N: usize, const M: usize, T: Copy> Uninit for BucketArrayMemory<N, M, T> {}
#[cfg_attr(feature = "bucket-array", visibility::make(pub))]
pub(crate) trait Count: Copy + Zero + One + Into<usize> + Add<Self, Output = Self> {}
impl<T: Copy + Zero + One + Into<usize> + Add<Self, Output = Self>> Count for T {}
struct BucketState<
const N: usize,
const CAP: usize,
C: Count,
> {
counts: [C; N],
}
impl<const N: usize, const CAP: usize, C: Count> BucketState<N, CAP, C> {
fn new() -> Self {
Self {
counts: [C::zero(); N],
}
}
#[inline(always)]
fn insert<F: FnMut(usize)>(&mut self, bucket: usize, mut writer: F) -> Result<(), ()> {
let item_count = self.counts[bucket];
let count_usize: usize = item_count.into();
if count_usize < CAP {
writer(count_usize);
self.counts[bucket] = item_count + C::one();
Ok(())
} else {
Err(())
}
}
#[inline(always)]
fn item_range(&self, bucket: usize) -> Range<usize> {
0..self.counts[bucket].into()
}
}
#[cfg_attr(feature = "bucket-array", visibility::make(pub))]
pub(crate) struct BucketArray<
'a,
const N: usize,
const CAP: usize,
C: Count,
A: Copy,
> {
mem: &'a mut BucketArrayMemory<N, CAP, A>,
state: BucketState<N, CAP, C>,
}
impl<'a, const N: usize, const CAP: usize, C: Count, A: Copy> BucketArray<'a, N, CAP, C, A> {
#[cfg_attr(feature = "bucket-array", visibility::make(pub))]
pub(crate) fn new(mem: &'a mut BucketArrayMemory<N, CAP, A>) -> Self {
Self {
mem,
state: BucketState::new(),
}
}
#[cfg_attr(feature = "bucket-array", visibility::make(pub))]
#[inline(always)]
pub(crate) fn item_range(&self, bucket: usize) -> Range<usize> {
self.state.item_range(bucket)
}
#[cfg_attr(feature = "bucket-array", visibility::make(pub))]
#[inline(always)]
pub(crate) fn item_value(&self, bucket: usize, item: usize) -> A {
assert!(self.state.item_range(bucket).contains(&item));
unsafe { self.mem.0[bucket][item].assume_init() }
}
#[cfg_attr(
feature = "bucket-array",
visibility::make(pub),
allow(clippy::result_unit_err)
)]
#[inline(always)]
pub(crate) fn insert(&mut self, bucket: usize, value: A) -> Result<(), ()> {
self.state.insert(bucket, |item| {
self.mem.0[bucket][item].write(value);
})
}
}
#[cfg_attr(feature = "bucket-array", visibility::make(pub))]
pub(crate) struct BucketArrayPair<
'a,
'b,
const N: usize,
const CAP: usize,
C: Count,
A: Copy,
B: Copy,
> {
mem_a: &'a mut BucketArrayMemory<N, CAP, A>,
mem_b: &'b mut BucketArrayMemory<N, CAP, B>,
state: BucketState<N, CAP, C>,
}
impl<'a, 'b, const N: usize, const CAP: usize, C: Count, A: Copy, B: Copy>
BucketArrayPair<'a, 'b, N, CAP, C, A, B>
{
#[cfg_attr(feature = "bucket-array", visibility::make(pub))]
pub(crate) fn new(
mem_a: &'a mut BucketArrayMemory<N, CAP, A>,
mem_b: &'b mut BucketArrayMemory<N, CAP, B>,
) -> Self {
Self {
mem_a,
mem_b,
state: BucketState::new(),
}
}
#[cfg_attr(feature = "bucket-array", visibility::make(pub))]
#[inline(always)]
pub(crate) fn item_range(&self, bucket: usize) -> Range<usize> {
self.state.item_range(bucket)
}
#[cfg_attr(feature = "bucket-array", visibility::make(pub))]
#[inline(always)]
pub(crate) fn item_value_first(&self, bucket: usize, item: usize) -> A {
assert!(self.state.item_range(bucket).contains(&item));
unsafe { self.mem_a.0[bucket][item].assume_init() }
}
#[cfg_attr(feature = "bucket-array", visibility::make(pub))]
#[inline(always)]
pub(crate) fn item_value_second(&self, bucket: usize, item: usize) -> B {
assert!(self.state.item_range(bucket).contains(&item));
unsafe { self.mem_b.0[bucket][item].assume_init() }
}
#[cfg_attr(
feature = "bucket-array",
visibility::make(pub),
allow(clippy::result_unit_err)
)]
#[inline(always)]
pub(crate) fn insert(&mut self, bucket: usize, first: A, second: B) -> Result<(), ()> {
self.state.insert(bucket, |item| {
self.mem_a.0[bucket][item].write(first);
self.mem_b.0[bucket][item].write(second);
})
}
#[cfg_attr(feature = "bucket-array", visibility::make(pub))]
pub(crate) fn drop_first(self) -> BucketArray<'b, N, CAP, C, B> {
BucketArray {
mem: self.mem_b,
state: self.state,
}
}
}