#![doc = include_str!("../README.md")]
#![no_std]
extern crate alloc;
use core::fmt::{Display, Formatter};
use alloc::vec::Vec;
#[derive(Debug)]
pub struct SparseMap<T> {
buffer: Vec<Option<T>>,
generations: Vec<u32>,
empty_slots: Vec<usize>,
}
impl<T> SparseMap<T> {
pub fn new() -> Self {
Self::default()
}
#[must_use = "The returned key is the only way to reference back the inserted value!"]
pub fn insert(&mut self, value: T) -> Key {
self.insert_with_key(|_, _| value)
}
pub fn insert_with_key<F>(&mut self, create: F) -> Key
where
F: FnOnce(&mut Self, Key) -> T,
{
if let Some(index) = self.empty_slots.pop() {
let mut generation = self.generations[index];
generation = generation.wrapping_add(1);
self.generations[index] = generation;
let key = Key::new(index, generation);
let item = create(self, key);
self.buffer[index] = Some(item);
key
} else {
let index = self.buffer.len();
self.generations.insert(index, 0);
let key = Key::new(index, 0);
let item = create(self, key);
self.buffer.insert(index, Some(item));
key
}
}
pub fn remove(&mut self, key: &Key) -> Option<T> {
let item = self.buffer.get_mut(key.index)?;
self.empty_slots.push(key.index);
item.take()
}
pub fn get(&self, key: &Key) -> Option<&T> {
let item = self.buffer.get(key.index)?;
let generation = self.generations.get(key.index)?;
if *generation == key.generation {
return item.as_ref();
}
None
}
pub fn get_mut(&mut self, key: &Key) -> Option<&mut T> {
let item = self.buffer.get_mut(key.index)?;
let generation = self.generations.get(key.index)?;
if *generation == key.generation {
return item.as_mut();
}
None
}
pub fn scope<F, R>(&mut self, key: &Key, f: F) -> Option<R>
where
F: FnOnce(&mut Self, &mut T) -> R,
{
if !self.contains(key) {
return None;
}
let mut value = self.buffer[key.index].take().unwrap();
let result = f(self, &mut value);
self.buffer[key.index] = Some(value);
Some(result)
}
pub fn contains(&self, key: &Key) -> bool {
self.buffer
.get(key.index)
.zip(self.generations.get(key.index))
.is_some_and(|(item, generation)| {
item.is_some() && *generation == key.generation
})
}
pub fn len(&self) -> usize {
self.buffer.len() - self.empty_slots.len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl<T> Default for SparseMap<T> {
fn default() -> Self {
Self {
buffer: Vec::new(),
generations: Vec::new(),
empty_slots: Vec::new(),
}
}
}
#[derive(
Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord,
)]
pub struct Key {
index: usize,
generation: u32,
}
impl Key {
fn new(index: usize, generation: u32) -> Self {
Self { index, generation }
}
pub fn index(&self) -> usize {
self.index
}
pub fn generation(&self) -> u32 {
self.generation
}
}
impl Display for Key {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.write_fmt(format_args!(
"#{}v{}",
self.index, self.generation
))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn insert_and_get() {
let mut map = SparseMap::new();
let key = map.insert(42);
assert_eq!(map.get(&key), Some(&42));
assert!(map.contains(&key));
assert_eq!(map.len(), 1);
}
#[test]
fn insert_and_insert_with_key_behave_equivalently() {
let mut map = SparseMap::new();
let k1 = map.insert(1);
let k2 = map.insert_with_key(|_, _| 2);
assert_eq!(k1.index, 0);
assert_eq!(k2.index, 1);
assert_eq!(map.buffer[k1.index], Some(1));
assert_eq!(map.buffer[k2.index], Some(2));
}
#[test]
fn remove_invalidates_key() {
let mut map = SparseMap::new();
let key = map.insert(10);
let removed = map.remove(&key);
assert_eq!(removed, Some(10));
assert_eq!(map.get(&key), None);
assert!(!map.contains(&key));
assert_eq!(map.len(), 0);
}
#[test]
fn insert_reuse_bumps_generation() {
let mut map = SparseMap::new();
let k1 = map.insert(1);
map.remove(&k1);
let k2 = map.insert(2);
assert_eq!(k1.index, k2.index);
assert_ne!(k1.generation, k2.generation);
assert_eq!(map.get(&k1), None);
assert_eq!(map.get(&k2), Some(&2));
}
#[test]
fn insert_with_key_reuse_bumps_generation() {
let mut map = SparseMap::new();
let k1 = map.insert_with_key(|_, _| 1);
map.remove(&k1);
let k2 = map.insert_with_key(|_, _| 2);
assert_eq!(k1.index, k2.index);
assert_ne!(k1.generation, k2.generation);
assert_eq!(map.get(&k1), None);
assert_eq!(map.get(&k2), Some(&2));
}
#[test]
fn get_mut_works() {
let mut map = SparseMap::new();
let key = map.insert(5);
*map.get_mut(&key).unwrap() = 99;
assert_eq!(map.get(&key), Some(&99));
}
#[test]
fn removing_twice_is_safe() {
let mut map = SparseMap::new();
let key = map.insert(7);
assert_eq!(map.remove(&key), Some(7));
assert_eq!(map.remove(&key), None);
}
#[test]
fn invalid_index_returns_none() {
let mut map = SparseMap::<usize>::new();
let fake_key = Key::new(999, 0);
assert_eq!(map.get(&fake_key), None);
assert_eq!(map.get_mut(&fake_key), None);
assert!(!map.contains(&fake_key));
}
}