use std::{
collections::BTreeMap,
simd::{Simd, SimdPartialEq, ToBitMask},
};
const LANES: usize = 16;
#[derive(Debug, Default)]
struct InlineMap<V>
where
V: Default,
{
keys: [u8; LANES],
values: [V; LANES],
}
#[derive(Debug)]
pub enum TinyMap<V>
where
V: Default,
{
Inline(InlineMap<V>),
Heap(BTreeMap<u8, V>),
}
impl<V> Default for TinyMap<V>
where
V: Default,
{
fn default() -> Self {
TinyMap::Inline(Default::default())
}
}
impl<V> TinyMap<V>
where
V: Default,
{
pub fn new() -> TinyMap<V> {
Default::default()
}
pub fn get(&self, key: u8) -> Option<&V> {
match self {
TinyMap::Inline(map) => map.get(key),
TinyMap::Heap(map) => map.get(&key),
}
}
}
impl<V> InlineMap<V>
where
V: Default,
{
fn len(&self) -> usize {
self.keys[LANES - 1] as usize
}
fn index(&self, key: u8) -> Option<usize> {
let keys = Simd::from_array(self.keys);
let q = Simd::splat(key);
let mask: u32 = q.simd_eq(keys).to_bitmask().into();
if mask != 0u32 {
let i = mask.trailing_zeros() as usize;
if i < self.len() as usize {
return Some(i);
}
}
None
}
pub fn get(&self, key: u8) -> Option<&V> {
self.index(key).and_then(|i| self.values.get(i))
}
}
#[cfg(test)]
mod test {
use std::simd::u8x8;
use super::*;
#[test]
fn test_mask_u8() {
for i in 0..7 {
let x: u8x8 = Simd::from_array([0, 1, 2, 3, 4, 5, 6, 7]);
let x_eq_i = x.simd_eq(Simd::splat(i));
assert_eq!(i as usize, x_eq_i.to_bitmask().trailing_zeros() as usize);
}
let x: u8x8 = Simd::from_array([0, 1, 2, 3, 4, 5, 6, 7]);
let x_eq_i = x.simd_eq(Simd::splat(10));
assert_eq!(0, x_eq_i.to_bitmask());
assert_eq!(8, x_eq_i.to_bitmask().trailing_zeros() as usize);
}
}