use std::cell;
use std::fmt;
use std::fmt::Debug;
use std::mem::size_of;
use std::ops::{Deref, Index, RangeBounds};
use std::rc;
use std::result;
use std::vec::Drain;
#[derive(Clone, Debug, Eq, PartialEq, Copy)]
pub enum MemoryErrors {
MemoryLimitExceededError,
}
impl fmt::Display for MemoryErrors {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
MemoryErrors::MemoryLimitExceededError => write!(f, "The memory limit has been exceeded"),
}
}
}
impl std::error::Error for MemoryErrors {}
type SharedMemoryLimiter = rc::Rc<cell::RefCell<MemoryLimiter>>;
type MemoryResult<T> = result::Result<T, MemoryErrors>;
#[derive(Debug, Clone)]
pub struct MemoryLimiter {
current_usage: usize,
max: usize,
}
impl MemoryLimiter {
#[must_use]
pub fn create_shared(max: usize) -> SharedMemoryLimiter {
rc::Rc::new(cell::RefCell::new(MemoryLimiter {
current_usage: 0,
max,
}))
}
#[must_use]
pub fn non_shared(max: usize) -> MemoryLimiter {
Self {
current_usage: 0,
max,
}
}
#[inline]
pub fn set_capacity(&mut self, new_max: usize) {
self.max = new_max;
}
#[inline]
#[must_use]
pub fn capacity(&self) -> usize {
self.max
}
#[inline]
#[must_use]
pub fn current_usage(&self) -> usize {
self.current_usage
}
#[inline]
pub fn preallocate(&mut self, by_amount: usize) {
self.increase_usage(by_amount)
.expect("allocated memory size amount");
}
#[inline]
pub fn decrease_usage(&mut self, by_amount: usize) {
if self.current_usage == 0 {
return;
}
self.current_usage -= by_amount;
}
#[inline]
pub fn increase_usage(&mut self, by_amount: usize) -> MemoryResult<()> {
self.current_usage += by_amount;
if self.current_usage > self.max {
return Err(MemoryErrors::MemoryLimitExceededError);
}
Ok(())
}
}
#[derive(Debug, Clone)]
pub struct Arena {
limiter: SharedMemoryLimiter,
data: Vec<u8>,
}
impl Arena {
pub fn new(limiter: SharedMemoryLimiter, preallocate: usize) -> Self {
limiter.borrow_mut().preallocate(preallocate);
Self {
limiter,
data: Vec::with_capacity(preallocate),
}
}
#[inline]
#[must_use]
pub fn capacity(&self) -> usize {
self.data.capacity()
}
#[must_use]
pub fn bytes(&self) -> &[u8] {
&self.data
}
pub fn shift(&mut self, by_amount: usize) {
self.data.copy_within(by_amount.., 0);
self.data.truncate(self.data.len() - by_amount);
}
pub fn init_with(&mut self, slice: &[u8]) -> MemoryResult<()> {
self.data.clear();
self.append(slice)
}
pub fn append(&mut self, slice: &[u8]) -> MemoryResult<()> {
let new_len = self.data.len() + slice.len();
let capacity = self.data.capacity();
if new_len > capacity {
let diff_size = new_len - capacity;
self.limiter.borrow_mut().increase_usage(diff_size)?;
self.data.reserve_exact(slice.len());
}
self.data.extend_from_slice(slice);
Ok(())
}
}
impl Deref for Arena {
type Target = [u8];
#[inline]
fn deref(&self) -> &Self::Target {
self.data.as_slice()
}
}
impl Index<usize> for Arena {
type Output = u8;
fn index(&self, index: usize) -> &Self::Output {
&self.data[index]
}
}
impl Drop for Arena {
fn drop(&mut self) {
self.limiter.borrow_mut().decrease_usage(self.data.len());
}
}
#[must_use]
pub fn calculate_size_for<T>(by_multiple: Option<usize>) -> usize {
if let Some(by_value) = by_multiple {
return size_of::<T>() * by_value;
}
size_of::<T>()
}
#[derive(Debug, Clone)]
pub struct TypeArena<T> {
limiter: SharedMemoryLimiter,
data: Vec<T>,
}
impl<T> TypeArena<T> {
pub fn new(limiter: SharedMemoryLimiter) -> Self {
Self {
limiter,
data: vec![],
}
}
pub fn preallocate(limiter: SharedMemoryLimiter, multiple_of: usize) -> Self {
let preallocate = calculate_size_for::<T>(Some(multiple_of));
limiter.borrow_mut().preallocate(preallocate);
Self {
limiter,
data: Vec::with_capacity(preallocate),
}
}
pub fn push(&mut self, element: T) -> MemoryResult<()> {
let by_amount = calculate_size_for::<T>(None);
self.limiter.borrow_mut().increase_usage(by_amount)?;
self.data.push(element);
Ok(())
}
#[inline]
pub fn first_mut(&mut self) -> Option<&mut T> {
self.data.first_mut()
}
#[inline]
#[must_use]
pub fn first(&self) -> Option<&T> {
self.data.first()
}
#[inline]
pub fn last_mut(&mut self) -> Option<&mut T> {
self.data.last_mut()
}
#[inline]
#[must_use]
pub fn last(&self) -> Option<&T> {
self.data.last()
}
#[inline]
#[must_use]
pub fn capacity(&self) -> usize {
self.data.capacity()
}
#[inline]
#[must_use]
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
#[inline]
#[must_use]
pub fn len(&self) -> usize {
self.data.len()
}
pub fn drain_last(&mut self) -> Option<T> {
let by_amount = calculate_size_for::<T>(None);
self.limiter.borrow_mut().decrease_usage(by_amount);
self.data.pop()
}
pub fn drain<R>(&mut self, range: R) -> Drain<'_, T>
where
R: RangeBounds<usize>,
{
use std::ops::Bound::{Excluded, Included, Unbounded};
let start = match range.start_bound() {
Included(&n) => n,
Excluded(&n) => n + 1,
Unbounded => 0,
};
let end = match range.end_bound() {
Included(&n) => n + 1,
Excluded(&n) => n,
Unbounded => self.len(),
};
self.limiter
.borrow_mut()
.decrease_usage(calculate_size_for::<T>(Some(end - start)));
self.data.drain(range)
}
}
impl<T> Deref for TypeArena<T> {
type Target = [T];
#[inline]
fn deref(&self) -> &Self::Target {
self.data.as_slice()
}
}
impl<T> Index<usize> for TypeArena<T> {
type Output = T;
fn index(&self, index: usize) -> &Self::Output {
&self.data[index]
}
}
impl<T> Drop for TypeArena<T> {
fn drop(&mut self) {
self.limiter
.borrow_mut()
.decrease_usage(calculate_size_for::<T>(Some(self.data.len())));
}
}
pub type ReferencedType<T> = rc::Rc<cell::RefCell<T>>;
pub type GeneratorFunc<T> = dyn Fn(&mut ArenaPool<T>) -> T;
pub trait Resettable {
fn reset(&mut self);
}
pub trait PoolGenerator<T: Resettable> {
fn generate(&self, pool: &mut ArenaPool<T>) -> T;
}
pub struct FnGenerator<T: Resettable> {
handler: Box<GeneratorFunc<T>>,
}
impl<T: Resettable> FnGenerator<T> {
pub fn new(handler: impl Fn(&mut ArenaPool<T>) -> T + 'static) -> Self {
Self {
handler: Box::new(handler),
}
}
}
impl<T: Resettable> PoolGenerator<T> for FnGenerator<T> {
fn generate(&self, pool: &mut ArenaPool<T>) -> T {
(self.handler)(pool)
}
}
#[derive(Clone)]
pub struct ArenaPool<T: Resettable> {
arena: TypeArena<T>,
tracker: MemoryLimiter,
limiter: SharedMemoryLimiter,
generator: rc::Rc<dyn PoolGenerator<T>>,
}
pub type SharedArenaPool<T> = rc::Rc<cell::RefCell<ArenaPool<T>>>;
impl<T: Resettable> ArenaPool<T> {
pub fn create_shared(
limiter: &SharedMemoryLimiter,
gen: impl PoolGenerator<T> + 'static,
) -> SharedArenaPool<T> {
let tracker = MemoryLimiter::non_shared(limiter.borrow().capacity());
rc::Rc::new(cell::RefCell::new(Self {
tracker,
generator: rc::Rc::new(gen),
limiter: rc::Rc::clone(limiter),
arena: TypeArena::new(rc::Rc::clone(limiter)),
}))
}
pub fn new(limiter: &SharedMemoryLimiter, gen: impl PoolGenerator<T> + 'static) -> Self {
let tracker = MemoryLimiter::non_shared(limiter.borrow().capacity());
Self {
tracker,
generator: rc::Rc::new(gen),
limiter: rc::Rc::clone(limiter),
arena: TypeArena::new(rc::Rc::clone(limiter)),
}
}
#[inline]
#[must_use]
pub fn remaining_allocation(&self) -> usize {
self.limiter.borrow().capacity() - self.tracker.current_usage()
}
#[inline]
#[must_use]
pub fn allocated(&self) -> usize {
self.tracker.current_usage()
}
#[inline]
#[must_use]
pub fn capacity(&self) -> usize {
self.limiter.borrow().capacity()
}
#[inline]
pub fn deallocate(&mut self, mut elem: T) {
self.tracker.set_capacity(self.limiter.borrow().capacity());
elem.reset();
self.arena.push(elem).expect("should push in element");
self.tracker.decrease_usage(calculate_size_for::<T>(None));
}
#[inline]
pub fn allocate(&mut self) -> MemoryResult<T> {
self.tracker.set_capacity(self.limiter.borrow().capacity());
if !self.arena.is_empty() {
self.tracker.increase_usage(calculate_size_for::<T>(None))?;
let elem = self.arena.drain_last().expect("should have element");
return Ok(elem);
}
self.tracker.increase_usage(calculate_size_for::<T>(None))?;
let gen = self.generator.clone();
let elem = gen.generate(self);
Ok(elem)
}
}