#![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 generation = self.generations.get(key.index)?;
if *generation != key.generation {
return None;
}
let item = self.buffer.get_mut(key.index)?;
if item.is_none() {
return None;
}
self.empty_slots.push(key.index);
item.take()
}
pub fn take(&mut self, key: &Key) -> Option<T> {
let generation = self.generations.get(key.index)?;
if *generation != key.generation {
return None;
}
self.buffer.get_mut(key.index)?.take()
}
pub fn restore(&mut self, key: &Key, value: T) -> bool {
let Some(&generation) = self.generations.get(key.index)
else {
return false;
};
if generation != key.generation {
return false;
}
let Some(slot) = self.buffer.get_mut(key.index) else {
return false;
};
if slot.is_some() {
return false;
}
*slot = Some(value);
true
}
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,
{
let generation = self.generations.get(key.index)?;
if *generation != key.generation {
return None;
}
let mut value = self.buffer[key.index].take()?;
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
}
pub fn iter(&self) -> impl Iterator<Item = &T> {
self.buffer.iter().flatten()
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {
self.buffer.iter_mut().flatten()
}
pub fn drain(&mut self) -> Drain<'_, T> {
Drain {
map: self,
index: 0,
}
}
pub fn clear(&mut self) {
for (index, slot) in self.buffer.iter_mut().enumerate() {
if slot.take().is_some() {
self.generations[index] =
self.generations[index].wrapping_add(1);
self.empty_slots.push(index);
}
}
}
}
pub struct Drain<'a, T> {
map: &'a mut SparseMap<T>,
index: usize,
}
impl<T> Iterator for Drain<'_, T> {
type Item = T;
fn next(&mut self) -> Option<T> {
while self.index < self.map.buffer.len() {
let index = self.index;
self.index += 1;
if self.map.buffer[index].is_some() {
let generation =
self.map.generations[index].wrapping_add(1);
self.map.generations[index] = generation;
self.map.empty_slots.push(index);
return self.map.buffer[index].take();
}
}
None
}
}
impl<T> Drop for Drain<'_, T> {
fn drop(&mut self) {
for _ in self.by_ref() {}
}
}
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 {
pub const PLACEHOLDER: Self = Self {
index: usize::MAX,
generation: u32::MAX,
};
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));
}
#[test]
fn take_returns_value() {
let mut map = SparseMap::new();
let key = map.insert(42);
assert_eq!(map.take(&key), Some(42));
}
#[test]
fn take_makes_slot_empty_but_key_generation_preserved() {
let mut map = SparseMap::new();
let key = map.insert(42);
map.take(&key);
assert_eq!(map.get(&key), None);
assert!(!map.contains(&key));
assert_eq!(map.generations[key.index], key.generation);
}
#[test]
fn take_does_not_free_slot_for_reuse() {
let mut map = SparseMap::new();
let key = map.insert(1);
map.take(&key);
let key2 = map.insert(2);
assert_ne!(key.index, key2.index);
}
#[test]
fn take_invalid_key_returns_none() {
let mut map = SparseMap::<i32>::new();
let fake_key = Key::new(999, 0);
assert_eq!(map.take(&fake_key), None);
}
#[test]
fn take_already_taken_returns_none() {
let mut map = SparseMap::new();
let key = map.insert(7);
assert_eq!(map.take(&key), Some(7));
assert_eq!(map.take(&key), None);
}
#[test]
fn restore_puts_value_back() {
let mut map = SparseMap::new();
let key = map.insert(10);
map.take(&key);
assert!(map.restore(&key, 10));
assert_eq!(map.get(&key), Some(&10));
assert!(map.contains(&key));
}
#[test]
fn restore_fails_if_slot_occupied() {
let mut map = SparseMap::new();
let key = map.insert(5);
assert!(!map.restore(&key, 99));
assert_eq!(map.get(&key), Some(&5));
}
#[test]
fn restore_fails_on_stale_key() {
let mut map = SparseMap::new();
let k1 = map.insert(1);
map.remove(&k1);
let _k2 = map.insert(2);
assert!(!map.restore(&k1, 99));
}
#[test]
fn restore_fails_on_invalid_index() {
let mut map = SparseMap::<i32>::new();
let fake_key = Key::new(999, 0);
assert!(!map.restore(&fake_key, 42));
}
#[test]
fn take_restore_roundtrip_key_stays_valid() {
let mut map = SparseMap::new();
let key = map.insert(100);
map.take(&key);
assert!(map.restore(&key, 200));
assert_eq!(map.get(&key), Some(&200));
}
#[test]
fn take_restore_allows_map_mutation_in_between() {
let mut map = SparseMap::new();
let key = map.insert(1);
let value = map.take(&key).unwrap();
let other = map.insert(99);
map.remove(&other);
assert!(map.restore(&key, value));
assert_eq!(map.get(&key), Some(&1));
}
#[test]
fn iter_yields_only_live_values() {
let mut map = SparseMap::new();
let _ = map.insert(1);
let key = map.insert(2);
let _ = map.insert(3);
map.remove(&key);
let mut values = map.iter().copied().collect::<Vec<_>>();
values.sort();
assert_eq!(values, [1, 3]);
}
#[test]
fn iter_mut_allows_mutation() {
let mut map = SparseMap::new();
let _ = map.insert(1);
let _ = map.insert(2);
for value in map.iter_mut() {
*value *= 10;
}
let mut values = map.iter().copied().collect::<Vec<_>>();
values.sort();
assert_eq!(values, [10, 20]);
}
#[test]
fn drain_yields_all_and_empties() {
let mut map = SparseMap::new();
let _ = map.insert(1);
let _ = map.insert(2);
let mut drained = map.drain().collect::<Vec<_>>();
drained.sort();
assert_eq!(drained, [1, 2]);
assert!(map.is_empty());
}
#[test]
fn drain_invalidates_keys_and_reuses_slots() {
let mut map = SparseMap::new();
let k1 = map.insert(1);
map.drain().count();
assert_eq!(map.get(&k1), None);
let k2 = map.insert(2);
assert_eq!(k1.index(), k2.index());
assert_ne!(k1.generation(), k2.generation());
}
#[test]
fn drain_dropped_early_still_empties() {
let mut map = SparseMap::new();
let _ = map.insert(1);
let _ = map.insert(2);
let _ = map.insert(3);
{
let mut drain = map.drain();
let _ = drain.next();
}
assert!(map.is_empty());
}
#[test]
fn clear_empties_and_invalidates_keys() {
let mut map = SparseMap::new();
let key = map.insert(1);
map.clear();
assert!(map.is_empty());
assert_eq!(map.get(&key), None);
let reused = map.insert(4);
assert_eq!(key.index(), reused.index());
assert_ne!(key.generation(), reused.generation());
assert_eq!(map.get(&key), None);
}
#[test]
fn clear_leaves_reserved_slot_restorable() {
let mut map = SparseMap::new();
let key = map.insert(1);
let value = map.take(&key).unwrap();
map.clear();
assert!(map.restore(&key, value));
assert_eq!(map.get(&key), Some(&1));
}
#[test]
fn clear_inside_scope_preserves_scoped_value() {
let mut map = SparseMap::new();
let key = map.insert(1);
let other = map.insert(2);
map.scope(&key, |map, _| map.clear());
assert_eq!(map.get(&key), Some(&1));
assert_eq!(map.get(&other), None);
}
}