extern crate alloc as alloc_crate;
use alloc_crate::collections::TryReserveError;
use alloc_crate::vec::{self, Vec};
use core::fmt::Debug;
use core::hint::unreachable_unchecked;
use core::iter::{self, FusedIterator};
use core::mem::{align_of, replace, size_of};
use core::ops::{Index, IndexMut};
use core::ptr::{self};
use core::slice::{self};
use either::{Either, Left, Right};
pub use crate::index::*;
type ArenaItem<I, T> = Either<<I as ArenaIndex>::Optional, T>;
#[derive(Debug, Clone)]
pub struct ArenaItems<I: ArenaIndex, T> {
vec: Vec<ArenaItem<I, T>>,
vacancy: I::Optional,
}
impl<I: ArenaIndex, T> ArenaItems<I, T> {
pub const fn item_size() -> usize {
size_of::<ArenaItem<I, T>>()
}
pub const fn item_align() -> usize {
align_of::<ArenaItem<I, T>>()
}
const fn new() -> Self {
ArenaItems {
vec: Vec::new(),
vacancy: I::NONE
}
}
fn with_capacity(capacity: usize) -> Self {
ArenaItems {
vec: Vec::with_capacity(capacity),
vacancy: I::NONE
}
}
pub fn capacity(&self) -> usize { self.vec.capacity() }
pub fn len(&self) -> usize {
let mut vacancies = 0;
let mut vacancy = self.vacancy;
while let Some(i) = I::to_option(vacancy) {
vacancies += 1;
vacancy = *self.vec[I::try_to_usize(i).unwrap()].as_ref().left().unwrap();
}
self.vec.len() - vacancies
}
pub fn len_equals_to_min_capacity(&self) -> bool {
I::to_option(self.vacancy).is_none()
}
pub fn is_empty(&self) -> bool { self.vec.iter().all(|x| x.is_left()) }
pub fn min_capacity(&self) -> usize { self.vec.len() }
pub fn reserve(&mut self, additional: usize) { self.vec.reserve(additional) }
pub fn reserve_exact(&mut self, additional: usize) { self.vec.reserve_exact(additional) }
pub fn shrink_to(&mut self, min_capacity: usize) { self.vec.shrink_to(min_capacity) }
pub fn shrink_to_fit(&mut self) { self.vec.shrink_to_fit() }
pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
self.vec.try_reserve(additional)
}
pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> {
self.vec.try_reserve_exact(additional)
}
pub fn get_value(&self, index: usize) -> Option<&T> {
self.vec[index].as_ref().right()
}
pub fn get_value_mut(&mut self, index: usize) -> Option<&mut T> {
self.vec[index].as_mut().right()
}
pub fn indices(&self) -> ArenaItemsIndices<'_, I, T> {
ArenaItemsIndices(self.vec.iter().enumerate())
}
pub fn values(&self) -> ArenaItemsValues<'_, I, T> {
ArenaItemsValues(self.vec.iter())
}
pub fn values_mut(&mut self) -> ArenaItemsValuesMut<'_, I, T> {
ArenaItemsValuesMut(self.vec.iter_mut())
}
pub fn iter(&self) -> ArenaItemsIter<'_, I, T> {
ArenaItemsIter(self.vec.iter().enumerate())
}
pub fn iter_mut(&mut self) -> ArenaItemsIterMut<'_, I, T> {
ArenaItemsIterMut(self.vec.iter_mut().enumerate())
}
pub fn into_indices(self) -> ArenaItemsIntoIndices<I, T> {
ArenaItemsIntoIndices(self.vec.into_iter().enumerate())
}
pub fn into_values(self) -> ArenaItemsIntoValues<I, T> {
ArenaItemsIntoValues(self.vec.into_iter())
}
}
#[derive(Debug, Clone)]
pub struct ArenaItemsIter<'a, I: ArenaIndex, T>(
iter::Enumerate<slice::Iter<'a, Either<I::Optional, T>>>
);
impl<'a, I: ArenaIndex, T> Iterator for ArenaItemsIter<'a, I, T> {
type Item = (I, &'a T);
fn next(&mut self) -> Option<Self::Item> {
loop {
match self.0.next() {
None => return None,
Some((_, Left(_))) => { },
Some((index, Right(item))) =>
return Some((I::try_from_usize(index).unwrap(), item)),
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(0, self.0.size_hint().1)
}
}
impl<'a, I: ArenaIndex, T> DoubleEndedIterator for ArenaItemsIter<'a, I, T> {
fn next_back(&mut self) -> Option<Self::Item> {
loop {
match self.0.next_back() {
None => return None,
Some((_, Left(_))) => { },
Some((index, Right(item))) =>
return Some((I::try_from_usize(index).unwrap(), item)),
}
}
}
}
impl<'a, I: ArenaIndex, T> FusedIterator for ArenaItemsIter<'a, I, T> { }
#[derive(Debug)]
pub struct ArenaItemsIterMut<'a, I: ArenaIndex, T>(
iter::Enumerate<slice::IterMut<'a, Either<I::Optional, T>>>
);
impl<'a, I: ArenaIndex, T> Iterator for ArenaItemsIterMut<'a, I, T> {
type Item = (I, &'a mut T);
fn next(&mut self) -> Option<Self::Item> {
loop {
match self.0.next() {
None => return None,
Some((_, Left(_))) => { },
Some((index, Right(item))) =>
return Some((I::try_from_usize(index).unwrap(), item)),
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(0, self.0.size_hint().1)
}
}
impl<'a, I: ArenaIndex, T> DoubleEndedIterator for ArenaItemsIterMut<'a, I, T> {
fn next_back(&mut self) -> Option<Self::Item> {
loop {
match self.0.next_back() {
None => return None,
Some((_, Left(_))) => { },
Some((index, Right(item))) =>
return Some((I::try_from_usize(index).unwrap(), item)),
}
}
}
}
impl<'a, I: ArenaIndex, T> FusedIterator for ArenaItemsIterMut<'a, I, T> { }
#[derive(Debug, Clone)]
pub struct ArenaItemsIndices<'a, I: ArenaIndex, T>(
iter::Enumerate<slice::Iter<'a, Either<I::Optional, T>>>
);
impl<'a, I: ArenaIndex, T> Iterator for ArenaItemsIndices<'a, I, T> {
type Item = I;
fn next(&mut self) -> Option<Self::Item> {
loop {
match self.0.next() {
None => return None,
Some((_, Left(_))) => { },
Some((index, Right(_))) => return Some(I::try_from_usize(index).unwrap()),
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(0, self.0.size_hint().1)
}
}
impl<'a, I: ArenaIndex, T> DoubleEndedIterator for ArenaItemsIndices<'a, I, T> {
fn next_back(&mut self) -> Option<Self::Item> {
loop {
match self.0.next_back() {
None => return None,
Some((_, Left(_))) => { },
Some((index, Right(_))) => return Some(I::try_from_usize(index).unwrap()),
}
}
}
}
impl<'a, I: ArenaIndex, T> FusedIterator for ArenaItemsIndices<'a, I, T> { }
#[derive(Debug, Clone)]
pub struct ArenaItemsValues<'a, I: ArenaIndex, T>(
slice::Iter<'a, Either<I::Optional, T>>
);
impl<'a, I: ArenaIndex, T> Iterator for ArenaItemsValues<'a, I, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
loop {
match self.0.next() {
None => return None,
Some(Left(_)) => { },
Some(Right(item)) => return Some(item),
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(0, self.0.size_hint().1)
}
}
impl<'a, I: ArenaIndex, T> DoubleEndedIterator for ArenaItemsValues<'a, I, T> {
fn next_back(&mut self) -> Option<Self::Item> {
loop {
match self.0.next_back() {
None => return None,
Some(Left(_)) => { },
Some(Right(item)) => return Some(item),
}
}
}
}
impl<'a, I: ArenaIndex, T> FusedIterator for ArenaItemsValues<'a, I, T> { }
#[derive(Debug)]
pub struct ArenaItemsValuesMut<'a, I: ArenaIndex, T>(
slice::IterMut<'a, Either<I::Optional, T>>
);
impl<'a, I: ArenaIndex, T> Iterator for ArenaItemsValuesMut<'a, I, T> {
type Item = &'a mut T;
fn next(&mut self) -> Option<Self::Item> {
loop {
match self.0.next() {
None => return None,
Some(Left(_)) => { },
Some(Right(item)) => return Some(item),
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(0, self.0.size_hint().1)
}
}
impl<'a, I: ArenaIndex, T> DoubleEndedIterator for ArenaItemsValuesMut<'a, I, T> {
fn next_back(&mut self) -> Option<Self::Item> {
loop {
match self.0.next_back() {
None => return None,
Some(Left(_)) => { },
Some(Right(item)) => return Some(item),
}
}
}
}
impl<'a, I: ArenaIndex, T> FusedIterator for ArenaItemsValuesMut<'a, I, T> { }
#[derive(Debug)]
pub struct ArenaItemsIntoIndices<I: ArenaIndex, T>(
iter::Enumerate<vec::IntoIter<Either<I::Optional, T>>>,
);
impl<I: ArenaIndex, T> Iterator for ArenaItemsIntoIndices<I, T> {
type Item = I;
fn next(&mut self) -> Option<Self::Item> {
loop {
match self.0.next() {
None => return None,
Some((_, Left(_))) => { },
Some((index, Right(_))) => return Some(I::try_from_usize(index).unwrap()),
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(0, self.0.size_hint().1)
}
}
impl<I: ArenaIndex, T> DoubleEndedIterator for ArenaItemsIntoIndices<I, T> {
fn next_back(&mut self) -> Option<Self::Item> {
loop {
match self.0.next_back() {
None => return None,
Some((_, Left(_))) => { },
Some((index, Right(_))) => return Some(I::try_from_usize(index).unwrap()),
}
}
}
}
impl<I: ArenaIndex, T> FusedIterator for ArenaItemsIntoIndices<I, T> { }
#[derive(Debug)]
pub struct ArenaItemsIntoValues<I: ArenaIndex, T>(
vec::IntoIter<Either<I::Optional, T>>,
);
impl<I: ArenaIndex, T> Iterator for ArenaItemsIntoValues<I, T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
loop {
match self.0.next() {
None => return None,
Some(Left(_)) => { },
Some(Right(item)) => return Some(item),
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(0, self.0.size_hint().1)
}
}
impl<I: ArenaIndex, T> DoubleEndedIterator for ArenaItemsIntoValues<I, T> {
fn next_back(&mut self) -> Option<Self::Item> {
loop {
match self.0.next_back() {
None => return None,
Some(Left(_)) => { },
Some(Right(item)) => return Some(item),
}
}
}
}
impl<I: ArenaIndex, T> FusedIterator for ArenaItemsIntoValues<I, T> { }
#[derive(Debug, Clone)]
pub struct ArenaItemsIntoIter<I: ArenaIndex, T>(
iter::Enumerate<vec::IntoIter<Either<I::Optional, T>>>,
);
impl<I: ArenaIndex, T> Iterator for ArenaItemsIntoIter<I, T> {
type Item = (I, T);
fn next(&mut self) -> Option<Self::Item> {
loop {
match self.0.next() {
None => return None,
Some((_, Left(_))) => { },
Some((index, Right(item))) =>
return Some((I::try_from_usize(index).unwrap(), item)),
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(0, self.0.size_hint().1)
}
}
impl<I: ArenaIndex, T> DoubleEndedIterator for ArenaItemsIntoIter<I, T> {
fn next_back(&mut self) -> Option<Self::Item> {
loop {
match self.0.next_back() {
None => return None,
Some((_, Left(_))) => { },
Some((index, Right(item))) =>
return Some((I::try_from_usize(index).unwrap(), item)),
}
}
}
}
impl<I: ArenaIndex, T> FusedIterator for ArenaItemsIntoIter<I, T> { }
impl<I: ArenaIndex, T> IntoIterator for ArenaItems<I, T> {
type Item = (I, T);
type IntoIter = ArenaItemsIntoIter<I, T>;
fn into_iter(self) -> Self::IntoIter {
ArenaItemsIntoIter(self.vec.into_iter().enumerate())
}
}
impl<'a, I: ArenaIndex, T> IntoIterator for &'a ArenaItems<I, T> {
type Item = (I, &'a T);
type IntoIter = ArenaItemsIter<'a, I, T>;
fn into_iter(self) -> Self::IntoIter { self.iter() }
}
mod forgettable_field {
use core::fmt::{self, Debug, Formatter};
use core::mem::{MaybeUninit, forget, replace};
use core::ops::{Deref, DerefMut};
pub struct ForgettableField<T>(MaybeUninit<T>);
impl<T> ForgettableField<T> {
pub const fn new(value: T) -> Self { ForgettableField(MaybeUninit::new(value)) }
pub fn into_inner(mut this: Self) -> T {
let inner = replace(&mut this.0, MaybeUninit::uninit());
forget(this);
unsafe { inner.assume_init() }
}
pub fn take_and_forget<Owner>(mut owner: Owner, f: impl FnOnce(&mut Owner) -> &mut Self) -> T {
let this = replace(f(&mut owner), ForgettableField(MaybeUninit::uninit()));
forget(owner);
Self::into_inner(this)
}
}
impl<T> Drop for ForgettableField<T> {
fn drop(&mut self) {
unsafe { self.0.assume_init_drop() }
}
}
impl<T> Deref for ForgettableField<T> {
type Target = T;
fn deref(&self) -> &T { unsafe { self.0.assume_init_ref() } }
}
impl<T> DerefMut for ForgettableField<T> {
fn deref_mut(&mut self) -> &mut T { unsafe { self.0.assume_init_mut() } }
}
impl<T: Default> Default for ForgettableField<T> {
fn default() -> Self { ForgettableField::new(T::default()) }
}
impl<T: Debug> Debug for ForgettableField<T> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
self.deref().fmt(f)
}
}
}
use forgettable_field::*;
#[derive(Debug)]
pub struct Arena<I: ArenaIndex, T: 'static> {
items: ForgettableField<ArenaItems<I, T>>,
}
impl<I: ArenaIndex, T> Arena<I, T> {
pub fn into_raw_parts(self) -> (usize, usize, usize, I::Optional) {
let items = ForgettableField::take_and_forget(self, |x| &mut x.items);
let (ptr, len, capacity) = items.vec.into_raw_parts();
let vacancy = items.vacancy;
let ptr = ptr.expose_provenance();
(ptr, len, capacity, vacancy)
}
pub unsafe fn from_raw_parts(a: usize, b: usize, c: usize, d: I::Optional) -> Self {
Arena {
items: ForgettableField::new(ArenaItems {
vec: Vec::from_raw_parts(ptr::with_exposed_provenance_mut(a), b, c),
vacancy: d,
})
}
}
pub const fn new() -> Self {
Arena {
items: ForgettableField::new(ArenaItems::new())
}
}
pub fn with_capacity(capacity: usize) -> Self {
Arena {
items: ForgettableField::new(ArenaItems::with_capacity(capacity))
}
}
pub fn into_items(#[allow(unused_mut)] mut self) -> ArenaItems<I, T> {
ForgettableField::take_and_forget(self, |x| &mut x.items)
}
pub fn items(&self) -> &ArenaItems<I, T> { &self.items }
pub fn items_mut(&mut self) -> &mut ArenaItems<I, T> { &mut self.items }
pub fn reserve(&mut self) {
if self.items().len_equals_to_min_capacity() {
self.items_mut().reserve(1);
assert!(I::try_from_usize(self.items().min_capacity()).is_some());
}
}
pub fn reserve_exact(&mut self) {
if self.items().len_equals_to_min_capacity() {
self.items_mut().reserve_exact(1);
assert!(I::try_from_usize(self.items().min_capacity()).is_some());
}
}
pub fn insert<R>(&mut self, item: impl FnOnce(I) -> (T, R)) -> R {
if let Some(index) = I::to_option(self.items.vacancy) {
let (item, result) = item(index);
self.items.vacancy = replace(&mut self.items.vec[I::try_to_usize(index).unwrap()], Right(item)).left()
.unwrap_or_else(|| unsafe { unreachable_unchecked() });
result
} else {
let index = I::try_from_usize(self.items.len()).expect("out of indices");
let (item, result) = item(index);
self.items.vec.push(Right(item));
result
}
}
pub fn remove(&mut self, index: I) -> T {
let vacancy = self.items.vacancy;
match replace(&mut self.items.vec[I::try_to_usize(index).expect("invalid index")], Left(vacancy)) {
Left(vacancy) => {
self.items.vec[I::try_to_usize(index).unwrap()] = Left(vacancy);
panic!("invalid index");
},
Right(item) => {
self.items.vacancy = I::some(index);
item
}
}
}
}
impl<I: ArenaIndex, T> Default for Arena<I, T> {
fn default() -> Self { Arena::new() }
}
impl<I: ArenaIndex, T> Index<I> for Arena<I, T> {
type Output = T;
fn index(&self, index: I) -> &T {
self.items.vec[I::try_to_usize(index).expect("invalid index")].as_ref().right().expect("invalid index")
}
}
impl<I: ArenaIndex, T> IndexMut<I> for Arena<I, T> {
fn index_mut(&mut self, index: I) -> &mut T {
self.items.vec[I::try_to_usize(index).expect("invalid index")].as_mut().right().expect("invalid index")
}
}
#[cfg(test)]
mod test {
use quickcheck_macros::quickcheck;
use core::num::NonZeroU32;
use core::sync::atomic::{AtomicI8, Ordering};
use crate::*;
struct Test {
this: NonZeroU32,
value: i8
}
const fn _new_test_arena() -> Arena<NonZeroU32, Test> {
Arena::new()
}
struct TestWithDrop {
value: i8
}
static TEST_DROP: AtomicI8 = AtomicI8::new(-1);
const fn _new_test_with_drop_arena() -> Arena<NonZeroU32, TestWithDrop> {
Arena::new()
}
impl Drop for TestWithDrop {
fn drop(&mut self) {
TEST_DROP.store(self.value, Ordering::SeqCst);
}
}
#[quickcheck]
fn new_arena_min_capacity_is_zero(capacity: Option<u8>) -> bool {
let capacity = capacity.map(|capacity| capacity as usize);
capacity.map_or_else(
|| <Arena::<NonZeroU32, Test>>::new(),
|capacity| <Arena::<NonZeroU32, Test>>::with_capacity(capacity)
).items().min_capacity() == 0
}
#[quickcheck]
fn arena_contains_inserted_item(capacity: Option<u8>, value: i8) -> bool {
let capacity = capacity.map(|capacity| capacity as usize);
let mut arena = capacity.map_or_else(
|| <Arena::<NonZeroU32, Test>>::new(),
|capacity| <Arena::<NonZeroU32, Test>>::with_capacity(capacity)
);
let index = arena.insert(|this| (Test { this, value }, this));
arena[index].this == index && arena[index].value == value
}
#[test]
fn drop_components() {
{
let mut arena: Arena<NonZeroU32, TestWithDrop> = Arena::new();
arena.insert(|this: NonZeroU32| (TestWithDrop { value: 7 }, this));
TEST_DROP.store(-1, Ordering::SeqCst);
}
assert_eq!(TEST_DROP.load(Ordering::SeqCst), 7);
}
#[test]
fn try_reserve() {
let mut arena: Arena<i8, ()> = Arena::new();
while arena.try_reserve().is_ok() {
arena.insert(|_| ((), ()));
}
}
}