#![deny(missing_docs)]
#![cfg_attr(not(any(feature = "std", test)), no_std)]
#[cfg(not(feature = "std"))]
extern crate alloc;
#[cfg(any(feature = "std", test))]
extern crate core;
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
use core::cell::RefCell;
use core::cmp;
use core::iter;
use core::mem;
use core::ptr;
use core::slice;
use core::str;
use mem::MaybeUninit;
#[cfg(test)]
mod test;
const INITIAL_SIZE: usize = 1024;
const MIN_CAPACITY: usize = 1;
pub struct Arena<T> {
chunks: RefCell<ChunkList<T>>,
}
struct ChunkList<T> {
current: Vec<T>,
rest: Vec<Vec<T>>,
}
impl<T> Arena<T> {
pub fn new() -> Arena<T> {
let size = cmp::max(1, mem::size_of::<T>());
Arena::with_capacity(INITIAL_SIZE / size)
}
pub fn with_capacity(n: usize) -> Arena<T> {
let n = cmp::max(MIN_CAPACITY, n);
Arena {
chunks: RefCell::new(ChunkList {
current: Vec::with_capacity(n),
rest: Vec::new(),
}),
}
}
pub fn len(&self) -> usize {
let chunks = self.chunks.borrow();
let mut res = 0;
for vec in chunks.rest.iter() {
res += vec.len()
}
res + chunks.current.len()
}
#[inline]
pub fn alloc(&self, value: T) -> &mut T {
self.alloc_fast_path(value)
.unwrap_or_else(|value| self.alloc_slow_path(value))
}
#[inline]
fn alloc_fast_path(&self, value: T) -> Result<&mut T, T> {
let mut chunks = self.chunks.borrow_mut();
let len = chunks.current.len();
if len < chunks.current.capacity() {
chunks.current.push(value);
debug_assert!(len < chunks.current.len()); Ok(unsafe { &mut *chunks.current.as_mut_ptr().add(len) })
} else {
Err(value)
}
}
fn alloc_slow_path(&self, value: T) -> &mut T {
&mut self.alloc_extend(iter::once(value))[0]
}
pub fn alloc_extend<I>(&self, iterable: I) -> &mut [T]
where
I: IntoIterator<Item = T>,
{
let mut iter = iterable.into_iter();
let mut chunks = self.chunks.borrow_mut();
let iter_min_len = iter.size_hint().0;
let mut next_item_index;
debug_assert!(
chunks.current.capacity() >= chunks.current.len(),
"capacity is always greater than or equal to len, so we don't need to worry about underflow"
);
if iter_min_len > chunks.current.capacity() - chunks.current.len() {
chunks.reserve(iter_min_len);
chunks.current.extend(iter);
next_item_index = 0;
} else {
next_item_index = chunks.current.len();
let mut i = 0;
while let Some(elem) = iter.next() {
if chunks.current.len() == chunks.current.capacity() {
let chunks = &mut *chunks;
chunks.reserve(i + 1);
let previous_chunk = chunks.rest.last_mut().unwrap();
let previous_chunk_len = previous_chunk.len();
chunks
.current
.extend(previous_chunk.drain(previous_chunk_len - i..));
chunks.current.push(elem);
chunks.current.extend(iter);
next_item_index = 0;
break;
} else {
chunks.current.push(elem);
}
i += 1;
}
}
unsafe {
let new_len = chunks.current.len() - next_item_index;
slice::from_raw_parts_mut(chunks.current.as_mut_ptr().add(next_item_index), new_len)
}
}
pub unsafe fn alloc_uninitialized(&self, num: usize) -> &mut [MaybeUninit<T>] {
let mut chunks = self.chunks.borrow_mut();
debug_assert!(
chunks.current.capacity() >= chunks.current.len(),
"capacity is always greater than or equal to len, so we don't need to worry about underflow"
);
if num > chunks.current.capacity() - chunks.current.len() {
chunks.reserve(num);
}
let next_item_index = chunks.current.len();
chunks.current.set_len(next_item_index + num);
let start = chunks.current.as_mut_ptr().offset(next_item_index as isize);
let start_uninit = start as *mut MaybeUninit<T>;
slice::from_raw_parts_mut(start_uninit, num)
}
pub fn reserve_extend(&self, num: usize) {
let mut chunks = self.chunks.borrow_mut();
debug_assert!(
chunks.current.capacity() >= chunks.current.len(),
"capacity is always greater than or equal to len, so we don't need to worry about underflow"
);
if num > chunks.current.capacity() - chunks.current.len() {
chunks.reserve(num);
}
}
pub fn uninitialized_array(&self) -> *mut [MaybeUninit<T>] {
let mut chunks = self.chunks.borrow_mut();
let len = chunks.current.capacity() - chunks.current.len();
let next_item_index = chunks.current.len();
unsafe {
let start = chunks.current.as_mut_ptr().offset(next_item_index as isize);
let start_uninit = start as *mut MaybeUninit<T>;
ptr::slice_from_raw_parts_mut(start_uninit, len)
}
}
pub fn into_vec(self) -> Vec<T> {
let mut chunks = self.chunks.into_inner();
let n = chunks
.rest
.iter()
.fold(chunks.current.len(), |a, v| a + v.len());
let mut result = Vec::with_capacity(n);
for mut vec in chunks.rest {
result.append(&mut vec);
}
result.append(&mut chunks.current);
result
}
#[inline]
pub fn iter_mut(&mut self) -> IterMut<T> {
let chunks = self.chunks.get_mut();
let position = if !chunks.rest.is_empty() {
let index = 0;
let inner_iter = chunks.rest[index].iter_mut();
let inner_iter = unsafe { mem::transmute(inner_iter) };
IterMutState::ChunkListRest { index, inner_iter }
} else {
let iter = unsafe { mem::transmute(chunks.current.iter_mut()) };
IterMutState::ChunkListCurrent { iter }
};
IterMut {
chunks,
state: position,
}
}
}
impl Arena<u8> {
#[inline]
pub fn alloc_str(&self, s: &str) -> &mut str {
let buffer = self.alloc_extend(s.bytes());
unsafe { str::from_utf8_unchecked_mut(buffer) }
}
}
impl<T> Default for Arena<T> {
fn default() -> Self {
Self::new()
}
}
impl<T> ChunkList<T> {
#[inline(never)]
#[cold]
fn reserve(&mut self, additional: usize) {
let double_cap = self
.current
.capacity()
.checked_mul(2)
.expect("capacity overflow");
let required_cap = additional
.checked_next_power_of_two()
.expect("capacity overflow");
let new_capacity = cmp::max(double_cap, required_cap);
let chunk = mem::replace(&mut self.current, Vec::with_capacity(new_capacity));
self.rest.push(chunk);
}
}
enum IterMutState<'a, T> {
ChunkListRest {
index: usize,
inner_iter: slice::IterMut<'a, T>,
},
ChunkListCurrent {
iter: slice::IterMut<'a, T>,
},
}
pub struct IterMut<'a, T: 'a> {
chunks: &'a mut ChunkList<T>,
state: IterMutState<'a, T>,
}
impl<'a, T> Iterator for IterMut<'a, T> {
type Item = &'a mut T;
fn next(&mut self) -> Option<&'a mut T> {
loop {
self.state = match self.state {
IterMutState::ChunkListRest {
mut index,
ref mut inner_iter,
} => {
match inner_iter.next() {
Some(item) => return Some(item),
None => {
index += 1;
if index < self.chunks.rest.len() {
let inner_iter = self.chunks.rest[index].iter_mut();
let inner_iter = unsafe { mem::transmute(inner_iter) };
IterMutState::ChunkListRest { index, inner_iter }
} else {
let iter = self.chunks.current.iter_mut();
let iter = unsafe { mem::transmute(iter) };
IterMutState::ChunkListCurrent { iter }
}
}
}
}
IterMutState::ChunkListCurrent { ref mut iter } => return iter.next(),
};
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let current_len = self.chunks.current.len();
let current_cap = self.chunks.current.capacity();
if self.chunks.rest.is_empty() {
(current_len, Some(current_len))
} else {
let rest_len = self.chunks.rest.len();
let last_chunk_len = self
.chunks
.rest
.last()
.map(|chunk| chunk.len())
.unwrap_or(0);
let min = current_len + last_chunk_len;
let max = min + (rest_len * current_cap / rest_len);
(min, Some(max))
}
}
}