use crate::bucket_array::mem::{self, BucketArrayMemory};
use num_traits::{One, WrappingAdd, WrappingNeg, Zero};
use std::marker::PhantomData;
use std::ops::{BitAnd, Div, Mul, Not, Range, Rem, Shl, Shr, Sub};
pub(crate) trait Shape<K: Key> {
const NUM_BUCKETS: usize;
fn item_range(&self, bucket: usize) -> Range<usize>;
#[inline(always)]
fn divisor(&self) -> K {
K::from_bucket_index(Self::NUM_BUCKETS)
}
#[inline(always)]
fn split_wide_key(&self, key: K) -> (usize, K) {
let divisor = self.divisor();
((key % divisor).into_bucket_index(), (key / divisor))
}
#[inline(always)]
fn join_wide_key(&self, bucket: usize, remainder: K) -> K {
let divisor = self.divisor();
remainder * divisor + K::from_bucket_index(bucket)
}
}
pub(crate) trait Insert<K: Key, V: Copy> {
fn insert(&mut self, key: K, value: V) -> Result<(), ()>;
}
pub(crate) trait KeyLookup<S: KeyStorage<K>, K: Key> {
fn item_stored_key(&self, bucket: usize, item: usize) -> S;
fn item_full_key(&self, bucket: usize, item: usize) -> K;
}
pub(crate) trait ValueLookup<V: Copy> {
fn item_value(&self, bucket: usize, item: usize) -> V;
}
pub(crate) struct KeyValueBucketArray<
'k,
'v,
const N: usize,
const CAP: usize,
C: Count,
K: Key,
KS: KeyStorage<K>,
V: Copy,
>(
mem::BucketArrayPair<'k, 'v, N, CAP, C, KS, V>,
PhantomData<K>,
);
impl<'k, 'v, const N: usize, const CAP: usize, C: Count, K: Key, KS: KeyStorage<K>, V: Copy>
KeyValueBucketArray<'k, 'v, N, CAP, C, K, KS, V>
{
pub(crate) fn new(
key_mem: &'k mut BucketArrayMemory<N, CAP, KS>,
value_mem: &'v mut BucketArrayMemory<N, CAP, V>,
) -> Self {
Self(mem::BucketArrayPair::new(key_mem, value_mem), PhantomData)
}
pub(crate) fn drop_key_storage(self) -> ValueBucketArray<'v, N, CAP, C, K, V> {
ValueBucketArray(self.0.drop_first(), self.1)
}
}
pub(crate) struct ValueBucketArray<
'v,
const N: usize,
const CAP: usize,
C: Count,
K: Key,
V: Copy,
>(mem::BucketArray<'v, N, CAP, C, V>, PhantomData<K>);
impl<'v, const N: usize, const CAP: usize, C: Count, K: Key, V: Copy>
ValueBucketArray<'v, N, CAP, C, K, V>
{
pub(crate) fn new(value_mem: &'v mut BucketArrayMemory<N, CAP, V>) -> Self {
Self(mem::BucketArray::new(value_mem), PhantomData)
}
}
impl<'k, 'v, const N: usize, const CAP: usize, C: Count, K: Key, KS: KeyStorage<K>, V: Copy>
Shape<K> for KeyValueBucketArray<'k, 'v, N, CAP, C, K, KS, V>
{
const NUM_BUCKETS: usize = N;
#[inline(always)]
fn item_range(&self, bucket: usize) -> Range<usize> {
self.0.item_range(bucket)
}
}
impl<'v, const N: usize, const CAP: usize, C: Count, K: Key, V: Copy> Shape<K>
for ValueBucketArray<'v, N, CAP, C, K, V>
{
const NUM_BUCKETS: usize = N;
#[inline(always)]
fn item_range(&self, bucket: usize) -> Range<usize> {
self.0.item_range(bucket)
}
}
impl<'k, 'v, const N: usize, const CAP: usize, C: Count, K: Key, KS: KeyStorage<K>, V: Copy>
Insert<K, V> for KeyValueBucketArray<'k, 'v, N, CAP, C, K, KS, V>
{
#[inline(always)]
fn insert(&mut self, key: K, value: V) -> Result<(), ()> {
let (bucket, key_remainder) = self.split_wide_key(key);
let key_storage = KS::from_key(key_remainder);
self.0.insert(bucket, key_storage, value)
}
}
impl<'v, const N: usize, const CAP: usize, C: Count, K: Key, V: Copy> Insert<K, V>
for ValueBucketArray<'v, N, CAP, C, K, V>
{
#[inline(always)]
fn insert(&mut self, key: K, value: V) -> Result<(), ()> {
let (bucket, _) = self.split_wide_key(key);
self.0.insert(bucket, value)
}
}
impl<'k, 'v, const N: usize, const CAP: usize, C: Count, K: Key, KS: KeyStorage<K>, V: Copy>
KeyLookup<KS, K> for KeyValueBucketArray<'k, 'v, N, CAP, C, K, KS, V>
{
#[inline(always)]
fn item_stored_key(&self, bucket: usize, item: usize) -> KS {
self.0.item_value_first(bucket, item)
}
#[inline(always)]
fn item_full_key(&self, bucket: usize, item: usize) -> K {
self.join_wide_key(bucket, self.item_stored_key(bucket, item).into_key())
}
}
impl<'k, 'v, const N: usize, const CAP: usize, C: Count, K: Key, KS: KeyStorage<K>, V: Copy>
ValueLookup<V> for KeyValueBucketArray<'k, 'v, N, CAP, C, K, KS, V>
{
#[inline(always)]
fn item_value(&self, bucket: usize, item: usize) -> V {
self.0.item_value_second(bucket, item)
}
}
impl<'v, const N: usize, const CAP: usize, C: Count, K: Key, V: Copy> ValueLookup<V>
for ValueBucketArray<'v, N, CAP, C, K, V>
{
#[inline(always)]
fn item_value(&self, bucket: usize, item: usize) -> V {
self.0.item_value(bucket, item)
}
}
pub(crate) trait Count: mem::Count + TryFrom<usize> {
#[inline(always)]
fn from_item_index(i: usize) -> Self {
i.try_into()
.map_err(|_| ())
.expect("Bucket count type is always wide enough for item index")
}
}
impl<T: mem::Count + TryFrom<usize>> Count for T {}
pub(crate) trait Key:
Copy
+ Zero
+ One
+ PartialEq<Self>
+ TryFrom<usize>
+ TryInto<usize>
+ Shl<usize, Output = Self>
+ Shr<usize, Output = Self>
+ Div<Self, Output = Self>
+ Rem<Self, Output = Self>
+ Mul<Self, Output = Self>
+ Not
+ Sub<Self, Output = Self>
+ BitAnd<Self, Output = Self>
+ WrappingAdd
+ WrappingNeg
{
#[inline(always)]
fn from_bucket_index(i: usize) -> Self {
i.try_into()
.map_err(|_| ())
.expect("Key type is always wide enough for a bucket index")
}
#[inline(always)]
fn into_bucket_index(self) -> usize {
self.try_into()
.map_err(|_| ())
.expect("Key is a bucket index which always fits in a usize")
}
#[inline(always)]
fn low_bits_are_zero(self, num_bits: usize) -> bool {
(self & ((Self::one() << num_bits) - Self::one())) == Self::zero()
}
}
impl<
T: Copy
+ Zero
+ One
+ PartialEq<Self>
+ TryFrom<usize>
+ TryInto<usize>
+ Shl<usize, Output = Self>
+ Shr<usize, Output = Self>
+ Div<Self, Output = Self>
+ Rem<Self, Output = Self>
+ Mul<Self, Output = Self>
+ Not
+ Sub<Self, Output = Self>
+ BitAnd<Self, Output = Self>
+ WrappingAdd
+ WrappingNeg,
> Key for T
{
}
pub(crate) trait KeyStorage<K>:
Copy + Zero + Not<Output = Self> + TryFrom<K> + TryInto<K>
where
K: Key,
{
#[inline(always)]
fn from_key(k: K) -> Self {
let key_mask = (!Self::zero()).into_key();
<K as TryInto<Self>>::try_into(k & key_mask)
.map_err(|_| ())
.expect("masked Key type always fits in KeyStorage")
}
#[inline(always)]
fn into_key(self) -> K {
self.try_into()
.map_err(|_| ())
.expect("Key type is always wider than KeyStorage")
}
}
impl<T: Copy + Zero + Not<Output = Self> + TryFrom<K> + TryInto<K>, K: Key> KeyStorage<K> for T {}