use std::{fmt, marker::PhantomData};
use crate::{div_ceil, safe_n_mask, Bitset, Index, MostSignificantBit};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum ValueEq {}
#[derive(Clone)]
pub struct PackedIntArray<K: Index, V: From<u32>, Eq = ()> {
indices: Bitset<Box<[u32]>>,
value_width: usize,
_tys: PhantomData<fn(K, V, Eq)>,
}
impl<K: Index, V: From<u32>, Eq> Default for PackedIntArray<K, V, Eq> {
fn default() -> Self {
PackedIntArray {
indices: Bitset(Vec::new().into_boxed_slice()),
value_width: 0,
_tys: PhantomData,
}
}
}
impl<K: Index, V: From<u32>, Eq> PackedIntArray<K, V, Eq> {
#[must_use]
pub fn with_capacity(key_len: usize, value_len: u32) -> Self {
let vwidth = value_len.most_significant_bit() as usize;
let bit_size = vwidth * key_len;
let u32_size = div_ceil(bit_size, u32::BITS as usize);
PackedIntArray {
indices: Bitset(vec![u32::MAX; u32_size].into_boxed_slice()),
value_width: vwidth,
_tys: PhantomData,
}
}
#[allow(clippy::unnecessary_lazy_evaluations)] #[must_use]
pub fn capacity(&self) -> usize {
let bit_len = self.indices.bit_len();
(bit_len != 0)
.then(|| bit_len / self.value_width)
.unwrap_or(0)
}
#[inline]
fn row_offset(&self, index: usize) -> usize {
index.get() * self.value_width
}
#[inline]
fn value_mask(&self) -> Option<u32> {
let shift = self.value_width as u32;
(shift != 0).then(|| safe_n_mask(shift))
}
fn get_index(&self, index: usize) -> Option<V> {
let offset = self.row_offset(index);
let width = self.value_width as u32;
let mask = self.value_mask()?;
let value = mask & self.indices.n_at(width, offset)?;
(value != mask && index < self.capacity()).then(|| V::from(value))
}
#[inline]
pub fn get(&self, index: &K) -> Option<V> {
self.get_index(index.get())
}
pub fn remove(&mut self, key: &K) {
let offset = self.row_offset(key.get());
self.indices.extend(offset..offset + self.value_width);
}
#[inline]
pub fn set(&mut self, key: &K, value: &V) -> Option<()>
where
V: Index,
{
let value = value.get() as u32;
let key = key.get();
let mask = self.value_mask()?;
if key >= self.capacity() || value == mask || value & mask != value {
return None;
}
let offset = self.row_offset(key);
self.indices
.disable_range(offset..offset + self.value_width);
self.indices
.extend(Bitset([value]).ones().map(|v| v + offset as u32));
Some(())
}
#[inline]
pub fn set_expanding_values(&mut self, key: &K, value: &V) -> Option<()>
where
V: Index,
{
let value_u32 = value.get() as u32;
let value_bits = value_u32.most_significant_bit();
let width = self.value_width as u32;
if value_bits > width || value_u32 == self.value_mask()? {
let additional_bits = value_bits - width;
let offset = |x: u32| x + x / width * additional_bits;
let new_indices = self.indices.ones().map(offset);
self.indices = new_indices.collect();
self.value_width += additional_bits as usize;
}
self.set(key, value)
}
#[inline]
pub fn iter(&self) -> impl Iterator<Item = (K, V)> + '_ {
(0..self.capacity()).filter_map(|k| self.get_index(k).map(|v| (K::new(k), v)))
}
#[inline]
pub fn rev_iter(&self) -> impl Iterator<Item = (K, V)> + '_ {
(0..self.capacity())
.rev()
.filter_map(|k| self.get_index(k).map(|v| (K::new(k), v)))
}
}
impl<K: Index, V: From<u32>> PartialEq for PackedIntArray<K, V> {
fn eq(&self, other: &Self) -> bool {
let min_len = self.indices.0.len().min(other.indices.0.len());
let largest = if self.indices.0.len() == min_len { other } else { self };
let common_identical = self.indices.0[..min_len] == other.indices.0[..min_len];
let no_more = largest.indices.0[min_len..].iter().all(|v| *v == u32::MAX);
common_identical && no_more
}
}
impl<K: Index, V: From<u32> + PartialEq> PartialEq for PackedIntArray<K, V, ValueEq> {
#[inline]
fn eq(&self, other: &Self) -> bool {
let max = self.capacity().max(other.capacity());
(0..max).all(|k| self.get_index(k) == other.get_index(k))
}
}
impl<K: Index, V: From<u32> + Index> FromIterator<(K, V)> for PackedIntArray<K, V> {
fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
let mut max_value = 0;
let mut max_key = 0;
let key_values = iter
.into_iter()
.map(|(k, v)| {
max_key = max_key.max(k.get() + 1);
max_value = max_value.max(v.get() + 1);
(k, v)
})
.collect::<Box<[_]>>();
let max_value = u32::try_from(max_value).unwrap();
let mut map = PackedIntArray::with_capacity(max_key, max_value);
for (key, value) in &*key_values {
map.set(key, value);
}
map
}
}
impl<K, V, Eq> fmt::Debug for PackedIntArray<K, V, Eq>
where
K: Index + fmt::Debug,
V: From<u32> + fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut list = f.debug_map();
self.iter().for_each(|(k, v)| {
list.entry(&k, &v);
});
list.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn capacity() {
let max_value = 127_u32;
let max_key = 32 * 7;
let map = PackedIntArray::<usize, u32>::with_capacity(max_key, max_value);
assert_eq!(max_key, map.capacity());
}
#[test]
fn compact_size() {
let value_len = 127_u32;
let key_len = 32 * 7;
let mut map = PackedIntArray::<usize, u32>::with_capacity(key_len, value_len);
let max_key = key_len - 1;
let max_value = value_len - 1;
assert_eq!(map.set(&max_key, &0), Some(()));
assert_eq!(map.get(&max_key), Some(0));
assert_eq!(map.set(&0, &max_value), Some(()));
assert_eq!(map.get(&0), Some(max_value));
}
#[test]
fn mini_size() {
let mut map = PackedIntArray::<usize, u32>::with_capacity(0, 0);
assert_eq!(map.indices.0.len(), 0);
assert_eq!(map.set(&32, &0), None);
assert_eq!(map.set(&0, &0), None);
assert_eq!(map.get(&32), None);
assert_eq!(map.get(&0), None);
let mut map = PackedIntArray::<usize, u32>::with_capacity(0, u32::MAX);
assert_eq!(map.indices.0.len(), 0);
assert_eq!(map.set(&32, &0), None);
assert_eq!(map.set(&0, &0), None);
assert_eq!(map.get(&32), None);
assert_eq!(map.get(&0), None);
let mut map = PackedIntArray::<usize, u32>::with_capacity(u32::MAX as usize, 0);
assert_eq!(map.indices.0.len(), 0);
assert_eq!(map.set(&32, &0), None);
assert_eq!(map.set(&0, &0), None);
assert_eq!(map.get(&32), None);
assert_eq!(map.get(&0), None);
}
#[test]
fn size() {
let len = 128;
let mut map = PackedIntArray::<usize, u32>::with_capacity(len, u32::MAX);
assert_eq!(map.indices.0.len(), len);
assert_eq!(map.set(&32, &0xffff_ff00), Some(()));
assert_eq!(map.get(&32), Some(0xffff_ff00));
assert_eq!(map.set(&(len - 1), &0xffff_0000), Some(()));
assert_eq!(map.get(&(len - 1)), Some(0xffff_0000));
}
#[test]
fn expand_size() {
let max_value = 127_u32;
let max_key = 32 * 7;
let mut map = PackedIntArray::<usize, u32>::with_capacity(max_key, max_value);
assert_eq!(max_key, map.capacity());
assert_eq!(map.set(&12, &100), Some(()));
assert_eq!(map.set(&20, &101), Some(()));
assert_eq!(map.set(&32, &102), Some(()));
assert_eq!(map.set(&300, &103), None);
assert_eq!(map.set(&32, &200), None);
assert_eq!(map.set_expanding_values(&35, &200), Some(()));
assert_eq!(map.set_expanding_values(&300, &200), None);
assert_eq!(map.set(&13, &199), Some(()));
assert_eq!(map.get(&12), Some(100));
assert_eq!(map.get(&13), Some(199));
assert_eq!(map.get(&20), Some(101));
assert_eq!(map.get(&32), Some(102));
assert_eq!(map.get(&35), Some(200));
assert_eq!(map.set_expanding_values(&36, &1845), Some(()));
assert_eq!(map.get(&12), Some(100));
assert_eq!(map.get(&13), Some(199));
assert_eq!(map.get(&20), Some(101));
assert_eq!(map.get(&32), Some(102));
assert_eq!(map.get(&35), Some(200));
assert_eq!(map.get(&36), Some(1845));
}
}