#![warn(missing_docs)]
mod controller;
pub mod error;
pub mod iter;
mod slot;
#[cfg(test)]
mod test;
pub use controller::Controller;
use error::{ArenaFull, InsertWithKeyError};
use iter::{DrainFilter, Iter, IterMut};
use slot::{ArenaSlot, ArenaSlotState};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Key {
index: usize,
generation: usize,
}
#[derive(Debug)]
pub struct Arena<T> {
controller: Controller,
slots: Vec<ArenaSlot<T>>,
first_occupied_slot_index: Option<usize>,
}
impl<T> Arena<T> {
pub fn new(capacity: usize) -> Self {
Self {
controller: Controller::new(capacity),
slots: (0..capacity).map(|_| ArenaSlot::new()).collect(),
first_occupied_slot_index: None,
}
}
pub fn controller(&self) -> Controller {
self.controller.clone()
}
pub fn capacity(&self) -> usize {
self.slots.len()
}
pub fn len(&self) -> usize {
self.slots
.iter()
.filter(|slot| matches!(&slot.state, ArenaSlotState::Occupied { .. }))
.count()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn insert_with_key(&mut self, key: Key, data: T) -> Result<(), InsertWithKeyError> {
if let Some(slot) = self.slots.get(key.index) {
if slot.generation != key.generation {
return Err(InsertWithKeyError::InvalidKey);
}
if let ArenaSlotState::Occupied { .. } = &slot.state {
return Err(InsertWithKeyError::KeyNotReserved);
}
} else {
return Err(InsertWithKeyError::InvalidKey);
}
if let Some(head_index) = self.first_occupied_slot_index {
self.slots[head_index].set_previous_occupied_slot_index(Some(key.index));
}
self.slots[key.index].state = ArenaSlotState::Occupied {
data,
previous_occupied_slot_index: None,
next_occupied_slot_index: self.first_occupied_slot_index,
};
self.first_occupied_slot_index = Some(key.index);
Ok(())
}
pub fn insert(&mut self, data: T) -> Result<Key, ArenaFull> {
let key = self.controller.try_reserve()?;
self.insert_with_key(key, data).unwrap();
Ok(key)
}
fn remove_from_slot(&mut self, index: usize) -> Option<T> {
let slot = &mut self.slots[index];
let state = std::mem::replace(&mut slot.state, ArenaSlotState::Free);
match state {
ArenaSlotState::Free => None,
ArenaSlotState::Occupied {
data,
previous_occupied_slot_index,
next_occupied_slot_index,
} => {
slot.generation += 1;
self.controller.free(index);
if let Some(previous_index) = previous_occupied_slot_index {
self.slots[previous_index]
.set_next_occupied_slot_index(next_occupied_slot_index);
}
if let Some(next_index) = next_occupied_slot_index {
self.slots[next_index]
.set_previous_occupied_slot_index(previous_occupied_slot_index);
}
if self.first_occupied_slot_index.unwrap() == index {
self.first_occupied_slot_index = next_occupied_slot_index;
}
Some(data)
}
}
}
pub fn remove(&mut self, key: Key) -> Option<T> {
let slot = &mut self.slots[key.index];
if slot.generation != key.generation {
return None;
}
self.remove_from_slot(key.index)
}
pub fn get(&self, key: Key) -> Option<&T> {
let slot = &self.slots[key.index];
if slot.generation != key.generation {
return None;
}
match &slot.state {
ArenaSlotState::Free => None,
ArenaSlotState::Occupied { data, .. } => Some(data),
}
}
pub fn get_mut(&mut self, key: Key) -> Option<&mut T> {
let slot = &mut self.slots[key.index];
if slot.generation != key.generation {
return None;
}
match &mut slot.state {
ArenaSlotState::Free => None,
ArenaSlotState::Occupied { data, .. } => Some(data),
}
}
pub fn retain(&mut self, mut f: impl FnMut(&T) -> bool) {
let mut index = match self.first_occupied_slot_index {
Some(index) => index,
None => return,
};
loop {
if let ArenaSlotState::Occupied {
data,
next_occupied_slot_index,
..
} = &self.slots[index].state
{
let next_occupied_slot_index = next_occupied_slot_index.as_ref().copied();
if !f(data) {
self.remove_from_slot(index);
}
index = match next_occupied_slot_index {
Some(index) => index,
None => return,
}
} else {
panic!("expected the slot pointed to by first_occupied_slot_index/next_occupied_slot_index to be occupied")
}
}
}
pub fn iter(&self) -> Iter<T> {
Iter::new(self)
}
pub fn iter_mut(&mut self) -> IterMut<T> {
IterMut::new(self)
}
pub fn drain_filter<F: FnMut(&T) -> bool>(&mut self, filter: F) -> DrainFilter<T, F> {
DrainFilter::new(self, filter)
}
}
impl<T> std::ops::Index<Key> for Arena<T> {
type Output = T;
fn index(&self, key: Key) -> &Self::Output {
self.get(key).expect("No item associated with this key")
}
}
impl<T> std::ops::IndexMut<Key> for Arena<T> {
fn index_mut(&mut self, key: Key) -> &mut Self::Output {
self.get_mut(key).expect("No item associated with this key")
}
}
impl<'a, T> IntoIterator for &'a Arena<T> {
type Item = (Key, &'a T);
type IntoIter = Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a, T> IntoIterator for &'a mut Arena<T> {
type Item = (Key, &'a mut T);
type IntoIter = IterMut<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}