use core::marker::PhantomData;
use core::ops;
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
use crate::Key;
use crate::entry::{EmptyEntry, Entry, OccupiedEntry};
use crate::free_pointer::FreePointer;
use crate::generation::Generation;
use crate::iter::{Drain, IntoIter, Iter, IterMut};
#[derive(Debug, Default, Clone)]
pub struct Arena<K: Copy, V> {
storage: Vec<Entry<V>>,
len: u32,
first_free: Option<FreePointer>,
_key_type: PhantomData<K>,
}
impl<K: Copy, V> Arena<K, V> {
pub const fn new() -> Self {
Self {
storage: Vec::new(),
len: 0,
first_free: None,
_key_type: PhantomData,
}
}
pub fn with_capacity(capacity: usize) -> Self {
Self {
storage: Vec::with_capacity(capacity),
len: 0,
first_free: None,
_key_type: PhantomData,
}
}
pub const fn len(&self) -> usize {
self.len as usize
}
pub fn capacity(&self) -> usize {
self.storage.capacity()
}
pub fn reserve(&mut self, additional: usize) {
let currently_free = self.storage.len().saturating_sub(self.len as usize);
let to_reserve = additional.saturating_sub(currently_free);
self.storage.reserve(to_reserve);
}
pub fn reserve_exact(&mut self, additional: usize) {
let currently_free = self.storage.len().saturating_sub(self.len as usize);
let to_reserve = additional.saturating_sub(currently_free);
self.storage.reserve_exact(to_reserve);
}
pub fn shrink_to_fit_all_slots(&mut self) {
self.storage.shrink_to_fit();
}
pub fn shrink_to_fit(&mut self) {
let max_occupied_slot = self.iter().map(|(k, _)| k.slot).max();
if let Some(max_occupied_slot) = max_occupied_slot {
self.storage.resize_with(
max_occupied_slot.saturating_add(1) as usize,
|| unreachable!(),
);
} else {
self.storage.clear();
}
self.storage.shrink_to_fit();
}
pub const fn is_empty(&self) -> bool {
self.len == 0
}
pub const fn num_free_slots(&self) -> usize {
self.storage.capacity().saturating_sub(self.len as usize)
}
pub fn insert(&mut self, value: V) -> Key<K> {
self.len = self
.len
.checked_add(1)
.unwrap_or_else(|| panic!("Cannot insert more than u32::MAX elements into Arena"));
if let Some(free_pointer) = self.first_free {
let slot = free_pointer.slot();
let entry = self.storage.get_mut(slot as usize).unwrap_or_else(|| {
unreachable!("first_free pointed past the end of the arena's storage")
});
let empty = entry
.as_empty()
.unwrap_or_else(|| unreachable!("first_free pointed to an occupied entry"));
self.first_free = empty.next_free;
let generation = empty.generation.next();
*entry = Entry::Occupied(OccupiedEntry { generation, value });
Key::new(slot, generation)
} else {
let generation = Generation::first();
let slot: u32 = self.storage.len().try_into().unwrap_or_else(|_| {
unreachable!("Arena storage exceeded what can be represented by a u32")
});
self.storage
.push(Entry::Occupied(OccupiedEntry { generation, value }));
Key::new(slot, generation)
}
}
fn remove_slot_from_free_list(&mut self, slot: u32, new_next_free: Option<FreePointer>) {
let mut next_fp = self
.first_free
.expect("Free entry exists but first_free is None");
let mut current_slot = None;
while next_fp.slot() != slot {
current_slot = Some(next_fp.slot());
next_fp = self
.storage
.get(next_fp.slot() as usize)
.expect("Empty entry not in storage!")
.as_empty()
.expect("Entry in free list not actually empty!")
.next_free
.expect("Hit the end of the free list without finding the target slot!");
}
match current_slot {
Some(slot_to_fix) => {
self.storage[slot_to_fix as usize]
.as_empty_mut()
.unwrap()
.next_free = new_next_free
}
None => self.first_free = new_next_free,
}
}
#[inline]
fn insert_at_inner(
&mut self,
slot: u32,
generation: Option<Generation>,
value: V,
) -> (Key<K>, Option<V>) {
let (key, old_value) = match self.storage.get_mut(slot as usize) {
Some(Entry::Empty(empty)) => {
let generation = generation.unwrap_or_else(|| empty.generation.next());
let new_next_free = empty.next_free;
self.remove_slot_from_free_list(slot, new_next_free);
self.storage[slot as usize] = Entry::Occupied(OccupiedEntry { generation, value });
(Key::new(slot, generation), None)
}
Some(Entry::Occupied(occupied)) => {
occupied.generation = generation.unwrap_or_else(|| occupied.generation.next());
let generation = occupied.generation;
let old_value = core::mem::replace(&mut occupied.value, value);
(Key::new(slot, generation), Some(old_value))
}
None => {
let mut first_free = self.first_free;
while self.storage.len() < slot as usize {
let new_slot: u32 = self.storage.len().try_into().unwrap_or_else(|_| {
unreachable!("Arena storage exceeded what can be represented by a u32")
});
self.storage.push(Entry::Empty(EmptyEntry {
generation: Generation::first(),
next_free: first_free,
}));
first_free = Some(FreePointer::from_slot(new_slot));
}
self.first_free = first_free;
let generation = generation.unwrap_or_else(Generation::first);
self.storage
.push(Entry::Occupied(OccupiedEntry { generation, value }));
(Key::new(slot, generation), None)
}
};
if old_value.is_none() {
self.len = self
.len
.checked_add(1)
.unwrap_or_else(|| panic!("Cannot insert more than u32::MAX elements into Arena"));
}
(key, old_value)
}
pub fn insert_at(&mut self, key: Key<K>, value: V) -> Option<V> {
self.insert_at_inner(key.slot, Some(key.generation), value)
.1
}
pub fn insert_at_slot(&mut self, slot: u32, value: V) -> (Key<K>, Option<V>) {
self.insert_at_inner(slot, None, value)
}
pub fn contains(&self, key: Key<K>) -> bool {
matches!(
self.storage.get(key.slot as usize),
Some(Entry::Occupied(occupied)) if occupied.generation == key.generation
)
}
pub fn contains_slot(&self, slot: u32) -> Option<Key<K>> {
match self.storage.get(slot as usize) {
Some(Entry::Occupied(occupied)) => Some(Key::new(slot, occupied.generation)),
_ => None,
}
}
#[inline]
pub fn get(&self, key: Key<K>) -> Option<&V> {
match self.storage.get(key.slot as usize) {
Some(Entry::Occupied(occupied)) if occupied.generation == key.generation => {
Some(&occupied.value)
}
_ => None,
}
}
#[inline]
pub fn get_mut(&mut self, key: Key<K>) -> Option<&mut V> {
match self.storage.get_mut(key.slot as usize) {
Some(entry) => entry.get_value_mut(key.generation),
_ => None,
}
}
pub fn get_disjoint_mut<const N: usize>(&mut self, keys: [Key<K>; N]) -> Option<[&mut V; N]> {
let indices: [usize; N] = keys.map(|k| k.slot as usize);
if let Ok(entries) = self.storage.get_disjoint_mut(indices) {
for (entry, &key) in entries.iter().zip(keys.iter()) {
if !matches!(
entry,
Entry::Occupied(occupied) if occupied.generation == key.generation
) {
return None;
}
}
Some(entries.map(|entry| {
let Entry::Occupied(OccupiedEntry { value, .. }) = entry else {
unreachable!()
};
value
}))
} else {
None
}
}
pub fn get_disjoint_by_slot_mut<const N: usize>(
&mut self,
slots: [u32; N],
) -> Option<[(Key<K>, &mut V); N]> {
let indices: [usize; N] = slots.map(|s| s as usize);
if let Ok(entries) = self.storage.get_disjoint_mut(indices) {
for entry in entries.iter() {
if !matches!(entry, Entry::Occupied(_)) {
return None;
}
}
let mut i = 0;
let values = entries.map(|entry| {
let Entry::Occupied(OccupiedEntry { value, generation }) = entry else {
unreachable!()
};
let key = Key::new(slots[i], *generation);
i = i.wrapping_add(1);
(key, value)
});
Some(values)
} else {
None
}
}
pub fn remove(&mut self, key: Key<K>) -> Option<V> {
let entry = self.storage.get_mut(key.slot as usize)?;
match entry {
Entry::Occupied(occupied) if occupied.generation == key.generation => {
let new_entry = Entry::Empty(EmptyEntry {
generation: occupied.generation,
next_free: self.first_free,
});
let old_entry = core::mem::replace(entry, new_entry);
let value = old_entry.into_value().unwrap_or_else(|| unreachable!());
self.first_free = Some(FreePointer::from_slot(key.slot));
self.len = self.len.checked_sub(1).unwrap_or_else(|| unreachable!());
Some(value)
}
_ => None,
}
}
pub fn invalidate(&mut self, key: Key<K>) -> Option<Key<K>> {
let entry = self.storage.get_mut(key.slot as usize)?;
match entry {
Entry::Occupied(occupied) if occupied.generation == key.generation => {
occupied.generation = occupied.generation.next();
Some(Key::new(key.slot, occupied.generation))
}
_ => None,
}
}
pub fn get_by_slot(&self, slot: u32) -> Option<(Key<K>, &V)> {
match self.storage.get(slot as usize) {
Some(Entry::Occupied(occupied)) => {
Some((Key::new(slot, occupied.generation), &occupied.value))
}
_ => None,
}
}
pub fn get_by_slot_mut(&mut self, slot: u32) -> Option<(Key<K>, &mut V)> {
match self.storage.get_mut(slot as usize) {
Some(Entry::Occupied(occupied)) => {
Some((Key::new(slot, occupied.generation), &mut occupied.value))
}
_ => None,
}
}
pub fn remove_by_slot(&mut self, slot: u32) -> Option<(Key<K>, V)> {
let entry = self.storage.get_mut(slot as usize)?;
match entry {
Entry::Occupied(occupied) => {
let key = Key::new(slot, occupied.generation);
let next_entry = Entry::Empty(EmptyEntry {
generation: occupied.generation,
next_free: self.first_free,
});
let old_entry = core::mem::replace(entry, next_entry);
let value = old_entry.into_value().unwrap_or_else(|| unreachable!());
self.first_free = Some(FreePointer::from_slot(slot));
self.len = self.len.checked_sub(1).unwrap_or_else(|| unreachable!());
Some((key, value))
}
_ => None,
}
}
pub fn clear(&mut self) {
self.drain().for_each(drop);
}
pub fn iter(&self) -> Iter<'_, K, V> {
Iter {
inner: self.storage.iter(),
slot: 0,
len: self.len,
_key_type: PhantomData,
}
}
pub fn iter_mut(&mut self) -> IterMut<'_, K, V> {
IterMut {
inner: self.storage.iter_mut(),
slot: 0,
len: self.len,
_key_type: PhantomData,
}
}
pub fn drain(&mut self) -> Drain<'_, K, V> {
Drain {
arena: self,
slot: 0,
}
}
pub fn retain<F: FnMut(Key<K>, &mut V) -> bool>(&mut self, mut f: F) {
for (i, entry) in self.storage.iter_mut().enumerate() {
if let Entry::Occupied(occupied) = entry {
let key = Key::new(i as u32, occupied.generation);
if !f(key, &mut occupied.value) {
*entry = Entry::Empty(EmptyEntry {
generation: occupied.generation,
next_free: self.first_free,
});
self.first_free = Some(FreePointer::from_slot(key.slot));
self.len = self.len.checked_sub(1).unwrap_or_else(|| unreachable!());
}
}
}
}
}
impl<K: Copy, V> IntoIterator for Arena<K, V> {
type Item = (Key<K>, V);
type IntoIter = IntoIter<K, V>;
fn into_iter(self) -> Self::IntoIter {
IntoIter {
arena: self,
slot: 0,
}
}
}
impl<'a, K: Copy, V> IntoIterator for &'a Arena<K, V> {
type Item = (Key<K>, &'a V);
type IntoIter = Iter<'a, K, V>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a, K: Copy, V> IntoIterator for &'a mut Arena<K, V> {
type Item = (Key<K>, &'a mut V);
type IntoIter = IterMut<'a, K, V>;
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
impl<K: Copy, V> ops::Index<Key<K>> for Arena<K, V> {
type Output = V;
fn index(&self, key: Key<K>) -> &Self::Output {
self.get(key)
.unwrap_or_else(|| panic!("No entry at key {:?}", key))
}
}
impl<K: Copy, V> ops::IndexMut<Key<K>> for Arena<K, V> {
fn index_mut(&mut self, key: Key<K>) -> &mut Self::Output {
self.get_mut(key)
.unwrap_or_else(|| panic!("No entry at key {:?}", key))
}
}
#[cfg(test)]
mod test {
use core::num::NonZeroU32;
use crate::{Key, free_pointer::FreePointer};
use super::Arena;
#[test]
fn new() {
let arena: Arena<(), u32> = Arena::new();
assert_eq!(arena.len(), 0);
assert_eq!(arena.capacity(), 0);
}
#[test]
fn with_capacity() {
let arena: Arena<(), u32> = Arena::with_capacity(8);
assert_eq!(arena.len(), 0);
assert_eq!(arena.capacity(), 8);
}
#[test]
fn insert_and_get() {
let mut arena = Arena::<(), u32>::new();
let one = arena.insert(1);
assert_eq!(arena.len(), 1);
assert_eq!(arena.get(one), Some(&1));
let two = arena.insert(2);
assert_eq!(arena.len(), 2);
assert_eq!(arena.get(one), Some(&1));
assert_eq!(arena.get(two), Some(&2));
}
#[test]
fn insert_remove_get() {
let mut arena = Arena::<(), u32>::new();
let one = arena.insert(1);
let two = arena.insert(2);
assert_eq!(arena.len(), 2);
assert!(arena.contains(two));
assert_eq!(arena.remove(two), Some(2));
assert!(!arena.contains(two));
let three = arena.insert(3);
assert_eq!(arena.len(), 2);
assert_eq!(arena.get(one), Some(&1));
assert_eq!(arena.get(three), Some(&3));
assert_eq!(arena.get(two), None);
}
#[test]
fn insert_remove_get_by_slot() {
let mut arena = Arena::<(), u32>::new();
let one = arena.insert(1);
let two = arena.insert(2);
assert_eq!(arena.len(), 2);
assert!(arena.contains(two));
assert_eq!(arena.remove_by_slot(two.slot()), Some((two, 2)));
assert!(!arena.contains(two));
assert_eq!(arena.get_by_slot(two.slot()), None);
let three = arena.insert(3);
assert_eq!(arena.len(), 2);
assert_eq!(arena.get(one), Some(&1));
assert_eq!(arena.get(three), Some(&3));
assert_eq!(arena.get(two), None);
assert_eq!(arena.get_by_slot(two.slot()), Some((three, &3)));
}
#[test]
fn insert_at() {
let mut arena = Arena::<(), u32>::new();
let key = Key::from_slot_and_generation(42, NonZeroU32::new(78).unwrap());
arena.insert_at(key, 5);
assert_eq!(arena.len(), 1);
assert_eq!(arena.get(key), Some(&5));
assert_eq!(arena.get_by_slot(42), Some((key, &5)));
}
#[test]
fn insert_at_first_slot() {
let mut arena = Arena::<(), u32>::new();
let key = Key::from_slot_and_generation(0, NonZeroU32::new(3).unwrap());
arena.insert_at(key, 5);
assert_eq!(arena.len(), 1);
assert_eq!(arena.get(key), Some(&5));
assert_eq!(arena.get_by_slot(0), Some((key, &5)));
}
#[test]
fn insert_at_slot() {
let mut arena = Arena::<(), u32>::new();
let (key, _) = arena.insert_at_slot(42, 5);
assert_eq!(arena.len(), 1);
assert_eq!(arena.get(key), Some(&5));
assert_eq!(arena.get_by_slot(42), Some((key, &5)));
}
#[test]
fn insert_at_middle() {
let mut arena = Arena::<(), u32>::new();
arena.insert_at_slot(4, 50);
arena.insert_at_slot(2, 40);
let empty = arena.storage.get(3).unwrap().as_empty().unwrap();
if empty.next_free != Some(FreePointer::from_slot(1)) {
panic!("Invalid free list: {:#?}", arena);
}
}
#[test]
fn get_mut() {
let mut arena = Arena::<(), u32>::new();
let foo = arena.insert(5);
let handle = arena.get_mut(foo).unwrap();
*handle = 6;
assert_eq!(arena.get(foo), Some(&6));
}
#[test]
fn get_disjoint_mut() {
let mut arena = Arena::<(), u32>::new();
let foo = arena.insert(100);
let bar = arena.insert(500);
let zip = arena.insert(700);
let [foo_handle, bar_handle, zip_handle] = arena.get_disjoint_mut([foo, bar, zip]).unwrap();
*foo_handle = 105;
*bar_handle = 505;
*zip_handle = 705;
assert_eq!(arena.get(foo), Some(&105));
assert_eq!(arena.get(bar), Some(&505));
assert_eq!(arena.get(zip), Some(&705));
}
#[test]
fn get_disjoint_mut_non_existant_handle() {
let mut arena = Arena::<(), u32>::new();
let foo = arena.insert(100);
let bar = arena.insert(500);
arena.remove(bar);
assert_eq!(arena.get_disjoint_mut([bar, foo]), None);
}
#[test]
fn get_disjoint_mut_same_slot_different_generation() {
let mut arena = Arena::<(), u32>::new();
let foo = arena.insert(100);
let bar = arena.insert(500);
let foo1 = Key::new(foo.slot, foo.generation.next());
assert_eq!(arena.get_disjoint_mut([foo1, bar]), None);
assert_eq!(arena.get_disjoint_mut([foo, foo1]), None);
}
#[test]
fn get_disjoint_by_slot_mut() {
let mut arena = Arena::<(), u32>::new();
let foo = arena.insert(100);
let bar = arena.insert(500);
let zip = arena.insert(700);
let [foo_handle, bar_handle, zip_handle] = arena
.get_disjoint_by_slot_mut([foo.slot, bar.slot, zip.slot])
.unwrap();
assert_eq!(foo, foo_handle.0);
assert_eq!(bar, bar_handle.0);
assert_eq!(zip, zip_handle.0);
*foo_handle.1 = 105;
*bar_handle.1 = 505;
*zip_handle.1 = 705;
assert_eq!(arena.get(foo), Some(&105));
assert_eq!(arena.get(bar), Some(&505));
assert_eq!(arena.get(zip), Some(&705));
}
#[test]
fn get_disjoint_by_slot_mut_non_existant_handle() {
let mut arena = Arena::<(), u32>::new();
let foo = arena.insert(100);
let bar = arena.insert(500);
arena.remove(bar);
assert_eq!(arena.get_disjoint_by_slot_mut([bar.slot, foo.slot]), None);
}
#[test]
fn insert_remove_insert_capacity() {
let mut arena = Arena::<(), &'static str>::with_capacity(2);
assert_eq!(arena.capacity(), 2);
let a = arena.insert("a");
let b = arena.insert("b");
assert_eq!(arena.len(), 2);
assert_eq!(arena.capacity(), 2);
arena.remove(a);
arena.remove(b);
assert_eq!(arena.len(), 0);
assert_eq!(arena.capacity(), 2);
let _a2 = arena.insert("a2");
let _b2 = arena.insert("b2");
assert_eq!(arena.len(), 2);
assert_eq!(arena.capacity(), 2);
}
#[test]
fn invalidate() {
let mut arena = Arena::<(), &'static str>::new();
let a = arena.insert("a");
assert_eq!(arena.get(a), Some(&"a"));
let new_a = arena.invalidate(a).unwrap();
assert_eq!(arena.get(a), None);
assert_eq!(arena.get(new_a), Some(&"a"));
}
#[test]
fn retain() {
let mut arena = Arena::<(), u32>::new();
for i in 0..100 {
arena.insert(i);
}
arena.retain(|_, &mut i| i % 2 == 1);
for (_, i) in arena.iter() {
assert_eq!(i % 2, 1);
}
assert_eq!(arena.len(), 50);
}
}