#![allow(unused)]
use std::cell::{Cell, UnsafeCell};
use std::cmp;
use std::marker::PhantomData;
use std::ops::{Index, IndexMut};
const CHUNK_SIZE: usize = 128;
pub(crate) struct Arena<TId: ArenaId, TValue> {
chunks: UnsafeCell<Vec<Vec<TValue>>>,
len: Cell<usize>,
phantom: PhantomData<TId>,
}
impl<TId: ArenaId, TValue> Default for Arena<TId, TValue> {
fn default() -> Self {
Self::new()
}
}
impl<TId: ArenaId, TValue> Arena<TId, TValue> {
pub(crate) fn new() -> Self {
Arena::with_capacity(1)
}
pub fn clear(&mut self) {
self.len.set(0);
for chunk in self.chunks.get_mut().iter_mut() {
chunk.clear();
}
}
pub fn with_capacity(n: usize) -> Self {
let n = cmp::max(1, n);
let n_chunks = n.div_ceil(CHUNK_SIZE);
let mut chunks = Vec::new();
chunks.resize_with(n_chunks, || Vec::with_capacity(CHUNK_SIZE));
Self {
chunks: UnsafeCell::from(chunks),
len: Cell::new(0),
phantom: Default::default(),
}
}
pub fn len(&self) -> usize {
self.len.get()
}
pub fn alloc(&self, value: TValue) -> TId {
let id = self.len.get();
let (chunk_idx, _) = Self::chunk_and_offset(id);
let chunks = unsafe { &mut *self.chunks.get() };
if chunk_idx >= chunks.len() {
chunks.resize_with(chunks.len() + 1, || Vec::with_capacity(CHUNK_SIZE));
}
chunks[chunk_idx].push(value);
self.len.set(id + 1);
TId::from_usize(id)
}
pub fn iter(&self) -> ArenaIter<'_, TId, TValue> {
ArenaIter {
arena: self,
index: 0,
}
}
pub fn iter_mut(&mut self) -> ArenaIterMut<'_, TId, TValue> {
ArenaIterMut {
arena: self,
index: 0,
}
}
fn chunk_and_offset(index: usize) -> (usize, usize) {
let offset = index % CHUNK_SIZE;
let chunk = index / CHUNK_SIZE;
(chunk, offset)
}
pub fn get_two_mut(&mut self, a: TId, b: TId) -> (&mut TValue, &mut TValue) {
let a_index = a.to_usize();
let b_index = b.to_usize();
debug_assert!(a_index < self.len());
debug_assert!(b_index < self.len());
debug_assert_ne!(a_index, b_index);
let (a_chunk, a_offset) = Self::chunk_and_offset(a_index);
let (b_chunk, b_offset) = Self::chunk_and_offset(b_index);
unsafe {
let chunks = self.chunks.get();
(
(&mut (*chunks))
.get_unchecked_mut(a_chunk)
.get_unchecked_mut(a_offset),
(&mut (*chunks))
.get_unchecked_mut(b_chunk)
.get_unchecked_mut(b_offset),
)
}
}
}
impl<TId: ArenaId, TValue> Index<TId> for Arena<TId, TValue> {
type Output = TValue;
fn index(&self, index: TId) -> &Self::Output {
let index = index.to_usize();
assert!(index < self.len());
let (chunk, offset) = Self::chunk_and_offset(index);
unsafe {
let vec = self.chunks.get();
(&(*vec)).get_unchecked(chunk).get_unchecked(offset)
}
}
}
impl<TId: ArenaId, TValue> IndexMut<TId> for Arena<TId, TValue> {
fn index_mut(&mut self, index: TId) -> &mut Self::Output {
let index = index.to_usize();
assert!(index < self.len());
let (chunk, offset) = Self::chunk_and_offset(index);
unsafe {
self.chunks
.get_mut()
.get_unchecked_mut(chunk)
.get_unchecked_mut(offset)
}
}
}
pub trait ArenaId {
fn from_usize(x: usize) -> Self;
fn to_usize(self) -> usize;
}
pub struct ArenaIter<'a, TId: ArenaId, TValue> {
arena: &'a Arena<TId, TValue>,
index: usize,
}
impl<'a, TId: ArenaId, TValue> Iterator for ArenaIter<'a, TId, TValue> {
type Item = (TId, &'a TValue);
fn next(&mut self) -> Option<Self::Item> {
if self.index < self.arena.len.get() {
let (chunk, offset) = Arena::<TId, TValue>::chunk_and_offset(self.index);
let element = unsafe {
let vec = self.arena.chunks.get();
Some((
TId::from_usize(self.index),
(&(*vec)).get_unchecked(chunk).get_unchecked(offset),
))
};
self.index += 1;
element
} else {
None
}
}
}
pub struct ArenaIterMut<'a, TId: ArenaId, TValue> {
arena: &'a mut Arena<TId, TValue>,
index: usize,
}
impl<'a, TId: ArenaId, TValue> Iterator for ArenaIterMut<'a, TId, TValue> {
type Item = (TId, &'a mut TValue);
fn next(&mut self) -> Option<Self::Item> {
if self.index < self.arena.len.get() {
let (chunk, offset) = Arena::<TId, TValue>::chunk_and_offset(self.index);
let element = unsafe {
let vec = self.arena.chunks.get();
Some((
TId::from_usize(self.index),
(&mut (*vec))
.get_unchecked_mut(chunk)
.get_unchecked_mut(offset),
))
};
self.index += 1;
element
} else {
None
}
}
}