use std::borrow::Borrow;
use crate::slab::{Slab, SlabIndex};
type NumType = u16;
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Hash)]
pub struct SmallIndex(NumType);
impl SmallIndex {
pub const MAX: Self = Self(NumType::MAX);
pub const ONE: Self = Self(1);
pub const ZERO: Self = Self(0);
}
impl From<SmallIndex> for NumType {
fn from(value: SmallIndex) -> Self {
value.0
}
}
impl SlabIndex for SmallIndex {
const MAX: usize = NumType::MAX as usize;
fn as_usize(&self) -> usize {
self.0 as usize
}
fn from_usize(index: usize) -> Self
where
Self: Sized,
{
Self(index as NumType)
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct SmallMap<K, V>(Slab<SmallIndex, (K, V)>);
impl<K, V> SmallMap<K, V>
where
K: PartialEq,
{
pub fn empty() -> Self {
Self(Slab::empty())
}
pub fn set(&mut self, key: K, mut value: V) -> Option<V> {
let old_value = self.get_mut(&key);
match old_value {
Some(old) => {
std::mem::swap(old, &mut value);
Some(value)
}
None => {
self.0.insert((key, value));
None
}
}
}
pub fn insert_with<F>(&mut self, key: K, f: F) -> SmallIndex
where
F: FnOnce(SmallIndex) -> V,
{
let id = self.0.next_id();
let value = f(id);
assert_eq!(self.0.insert((key, value)), id);
id
}
pub fn get<Q>(&self, key: &Q) -> Option<&V>
where
K: Borrow<Q>,
Q: PartialEq + ?Sized,
{
self.0.iter().find_map(|(_, (k, v))| match k.borrow() == key {
true => Some(v),
false => None,
})
}
pub fn get_mut<Q>(&mut self, key: &Q) -> Option<&mut V>
where
K: Borrow<Q>,
Q: PartialEq + ?Sized,
{
self.0.iter_mut().find_map(|(_, (k, v))| match (*k).borrow() == key {
true => Some(v),
false => None,
})
}
pub fn get_index<Q>(&self, key: &Q) -> Option<SmallIndex>
where
K: Borrow<Q>,
Q: PartialEq + ?Sized,
{
self.0.iter().find_map(|(i, (k, _))| match k.borrow() == key {
true => Some(i),
false => None,
})
}
pub fn remove<Q>(&mut self, key: &Q) -> Option<V>
where
K: Borrow<Q>,
Q: PartialEq + ?Sized,
{
let idx = self.get_index(key)?;
self.0.try_remove(idx).map(|(_, v)| v)
}
pub fn iter(&self) -> impl Iterator<Item = (&K, &V)> + '_ {
self.0.iter().map(|(_, (k, v))| (k, v))
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = (&mut K, &mut V)> + '_ {
self.0.iter_mut().map(|(_, (k, v))| (k, v))
}
pub fn get_with_index(&self, idx: SmallIndex) -> Option<&V> {
self.0.get(idx).map(|(_, v)| v)
}
pub fn get_mut_with_index(&mut self, idx: SmallIndex) -> Option<&mut V> {
self.0.get_mut(idx).map(|(_, v)| v)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn insert_twice() {
let mut map = SmallMap::<&str, u8>::empty();
map.set("a", 1);
map.set("b", 2);
assert_eq!(1, *map.get("a").unwrap());
}
#[test]
fn get_and_get_mut() {
let mut map = SmallMap::<&str, u8>::empty();
map.set("a", 1);
map.set("b", 2);
*map.get_mut("a").unwrap() += 1;
assert_eq!(2, *map.get("b").unwrap());
assert_eq!(2, *map.get("a").unwrap());
}
#[test]
fn double_set() {
let mut map = SmallMap::<&str, u8>::empty();
assert_eq!(None, map.set("a", 1));
assert_eq!(Some(1), map.set("a", 2));
}
#[test]
fn get_by_index() {
let mut map = SmallMap::<&str, u8>::empty();
map.set("a", 1);
let idx = map.get_index("a").unwrap();
assert_eq!(1, *map.get_with_index(idx).unwrap());
}
#[test]
fn get_by_index_mut() {
let mut map = SmallMap::<&str, u8>::empty();
map.set("a", 1);
let idx = map.get_index("a").unwrap();
assert_eq!(1, *map.get_mut_with_index(idx).unwrap());
}
}