use std::fmt;
use std::marker::PhantomData;
#[allow(dead_code)]
const CACHE_LINE_SIZE: usize = 64;
#[derive(Clone, Debug)]
pub struct Slot<T> {
pub data: Option<T>,
pub generation: u32,
}
impl<T> Slot<T> {
pub fn new(data: T, generation: u32) -> Self {
Self {
data: Some(data),
generation,
}
}
#[inline]
pub fn is_occupied(&self) -> bool {
self.data.is_some()
}
#[inline]
pub fn data(&self) -> Option<&T> {
self.data.as_ref()
}
#[inline]
pub fn data_mut(&mut self) -> Option<&mut T> {
self.data.as_mut()
}
#[inline]
pub fn replace(&mut self, new_data: T) -> Option<T> {
self.data.replace(new_data)
}
#[inline]
pub fn clear(&mut self) -> Option<T> {
self.data.take()
}
}
pub struct Arena<T> {
slots: Vec<Slot<T>>,
free_list: Vec<usize>,
_marker: PhantomData<T>,
}
impl<T> fmt::Debug for Arena<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Arena")
.field("len", &self.len())
.field("capacity", &self.capacity())
.field("free_list_len", &self.free_list.len())
.finish()
}
}
impl<T> Arena<T> {
pub fn new() -> Self {
Self {
slots: Vec::new(),
free_list: Vec::new(),
_marker: PhantomData,
}
}
pub fn with_capacity(capacity: usize) -> Self {
Self {
slots: Vec::with_capacity(capacity),
free_list: Vec::with_capacity(capacity),
_marker: PhantomData,
}
}
#[inline]
pub fn allocate(&mut self, value: T) -> (usize, u32) {
if let Some(index) = self.free_list.pop() {
let slot = &mut self.slots[index];
let new_generation = slot.generation.wrapping_add(1);
*slot = Slot::new(value, new_generation);
(index, new_generation)
} else {
let index = self.slots.len();
let generation = 1u32;
self.slots.push(Slot::new(value, generation));
(index, generation)
}
}
#[inline]
pub fn deallocate(&mut self, index: usize, generation: u32) -> Option<T> {
if index >= self.slots.len() {
return None;
}
let slot = &mut self.slots[index];
if slot.generation != generation {
return None; }
let value = slot.data.take()?;
self.free_list.push(index);
Some(value)
}
#[inline]
pub fn get(&self, index: usize, generation: u32) -> Option<&T> {
self.slots
.get(index)
.filter(|slot| slot.generation == generation && slot.is_occupied())
.and_then(|slot| slot.data())
}
#[inline]
pub fn get_mut(&mut self, index: usize, generation: u32) -> Option<&mut T> {
self.slots
.get_mut(index)
.filter(|slot| slot.generation == generation && slot.is_occupied())
.and_then(|slot| slot.data_mut())
}
#[inline]
pub fn is_valid(&self, index: usize, generation: u32) -> bool {
self.slots
.get(index)
.is_some_and(|slot| slot.generation == generation && slot.is_occupied())
}
#[inline]
pub fn get_slot(&self, index: usize) -> Option<&Slot<T>> {
self.slots.get(index)
}
#[inline]
pub fn get_slot_mut(&mut self, index: usize) -> Option<&mut Slot<T>> {
self.slots.get_mut(index)
}
#[inline]
pub fn clear(&mut self) {
for slot in &mut self.slots {
slot.data = None;
}
self.free_list.clear();
for i in 0..self.slots.len() {
self.free_list.push(i);
}
}
#[inline]
pub fn drain(&mut self) {
self.slots.clear();
self.free_list.clear();
}
#[inline]
pub fn len(&self) -> usize {
self.slots.len() - self.free_list.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline]
pub fn capacity(&self) -> usize {
self.slots.capacity()
}
#[inline]
pub fn num_slots(&self) -> usize {
self.slots.len()
}
#[inline]
pub fn num_free(&self) -> usize {
self.free_list.len()
}
#[inline]
pub fn reserve(&mut self, additional: usize) {
self.slots.reserve(additional);
self.free_list.reserve(additional);
}
pub fn shrink_to_fit(&mut self) {
self.free_list.shrink_to_fit();
self.slots.shrink_to_fit();
}
pub fn iter(&self) -> impl Iterator<Item = (usize, u32, &T)> {
self.slots.iter().enumerate().filter_map(|(idx, slot)| {
if slot.is_occupied() {
Some((idx, slot.generation, slot.data.as_ref().unwrap()))
} else {
None
}
})
}
pub fn iter_all(&self) -> impl Iterator<Item = (usize, &Slot<T>)> {
self.slots.iter().enumerate()
}
}
impl<T> Default for Arena<T> {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_arena_allocate() {
let mut arena = Arena::new();
let (idx, generation) = arena.allocate(42);
assert_eq!(arena.get(idx, generation), Some(&42));
assert_eq!(generation, 1);
}
#[test]
fn test_arena_deallocate() {
let mut arena = Arena::new();
let (idx, generation) = arena.allocate(42);
let value = arena.deallocate(idx, generation);
assert_eq!(value, Some(42));
assert_eq!(arena.get(idx, generation), None);
}
#[test]
fn test_arena_reuse() {
let mut arena = Arena::new();
let (idx1, gen1) = arena.allocate(1);
let _ = arena.deallocate(idx1, gen1);
let (idx2, gen2) = arena.allocate(2);
assert_eq!(idx2, idx1);
assert_eq!(gen2, gen1 + 1);
assert!(arena.get(idx2, gen2).is_some());
assert!(arena.get(idx2, gen1).is_none());
}
#[test]
fn test_arena_is_valid() {
let mut arena = Arena::new();
let (idx, generation) = arena.allocate(42);
assert!(arena.is_valid(idx, generation));
assert!(!arena.is_valid(idx, generation + 1)); assert!(!arena.is_valid(idx + 1, generation));
arena.deallocate(idx, generation);
assert!(!arena.is_valid(idx, generation)); }
#[test]
fn test_arena_len_and_capacity() {
let mut arena = Arena::with_capacity(10);
assert_eq!(arena.len(), 0);
assert!(arena.is_empty());
assert!(arena.capacity() >= 10);
let (idx, generation) = arena.allocate(1);
assert_eq!(arena.len(), 1);
assert!(!arena.is_empty());
arena.deallocate(idx, generation);
assert_eq!(arena.len(), 0);
}
#[test]
fn test_arena_clear() {
let mut arena = Arena::new();
let (idx1, _) = arena.allocate(1);
let (idx2, _) = arena.allocate(2);
arena.clear();
assert!(arena.is_empty());
assert!(!arena.is_valid(idx1, 1));
assert!(!arena.is_valid(idx2, 1));
}
#[test]
fn test_arena_iter() {
let mut arena = Arena::new();
let (idx1, gen1) = arena.allocate(1);
let (idx2, gen2) = arena.allocate(2);
let (idx3, gen3) = arena.allocate(3);
arena.deallocate(idx2, gen2);
let items: Vec<_> = arena.iter().collect();
assert_eq!(items.len(), 2);
assert!(items
.iter()
.any(|(i, g, v)| *i == idx1 && *g == gen1 && **v == 1));
assert!(items
.iter()
.any(|(i, g, v)| *i == idx3 && *g == gen3 && **v == 3));
}
#[test]
fn test_arena_generation_wrap() {
let mut arena = Arena::new();
let (idx, mut generation) = arena.allocate(42);
for _ in 0..10 {
arena.deallocate(idx, generation);
let (_, new_generation) = arena.allocate(100);
generation = new_generation;
}
assert!(arena.is_valid(idx, generation));
}
#[test]
fn test_arena_get_mut() {
let mut arena = Arena::new();
let (idx, generation) = arena.allocate(42);
if let Some(val) = arena.get_mut(idx, generation) {
*val = 100;
}
assert_eq!(arena.get(idx, generation), Some(&100));
}
#[test]
fn test_arena_with_capacity() {
let mut arena = Arena::<i32>::with_capacity(100);
assert!(arena.is_empty());
assert!(arena.capacity() >= 100);
for i in 0..100 {
arena.allocate(i);
}
assert_eq!(arena.len(), 100);
}
}