use std::{ops::{Deref, DerefMut}, mem::MaybeUninit};
use crate::vector::VectorViewMut;
pub mod caching;
pub trait MemoryProvider<T> {
type Object: Deref<Target = [T]> + DerefMut + VectorViewMut<T>;
unsafe fn get_new<F: FnOnce(&mut [MaybeUninit<T>])>(&self, size: usize, initializer: F) -> Self::Object;
fn get_new_init<F: FnMut(usize) -> T>(&self, size: usize, mut initializer: F) -> Self::Object {
unsafe {
self.get_new(size, |mem| {
for i in 0..mem.len() {
mem[i] = MaybeUninit::new(initializer(i))
}
})
}
}
fn try_get_new_init<E, F: FnMut(usize) -> Result<T, E>>(&self, size: usize, mut initializer: F) -> Result<Self::Object, E> {
unsafe {
let mut aborted = None;
let result = self.get_new(size, |mem| {
let mut i = 0;
while i < mem.len() {
match initializer(i) {
Ok(val) => {
mem[i] = MaybeUninit::new(val);
i += 1;
},
Err(err) => {
aborted = Some(err);
for j in 0..i {
mem[j].assume_init_drop();
}
break;
}
};
}
});
if let Some(err) = aborted {
Err(err)
} else {
Ok(result)
}
}
}
}
pub trait GrowableMemoryProvider<T>: MemoryProvider<T> {
fn shrink(&self, el: &mut Self::Object, new_len: usize);
unsafe fn grow<F: FnOnce(&mut [MaybeUninit<T>])>(&self, el: &mut Self::Object, new_size: usize, initializer: F);
fn grow_init<F: FnMut(usize) -> T>(&self, el: &mut Self::Object, new_size: usize, mut initializer: F) {
assert!(new_size > el.len());
let old_len = el.len();
unsafe {
self.grow(el, new_size, |mem| {
for i in 0..mem.len() {
mem[i] = MaybeUninit::new(initializer(old_len + i))
}
})
}
}
}
#[derive(Copy, Clone)]
pub struct AllocatingMemoryProvider;
impl<T> MemoryProvider<T> for AllocatingMemoryProvider {
type Object = Vec<T>;
unsafe fn get_new<F: FnOnce(&mut [MaybeUninit<T>])>(&self, size: usize, initializer: F) -> Self::Object {
let mut result = Box::new_uninit_slice(size);
initializer(&mut *result);
return result.assume_init().into_vec();
}
}
impl<T> GrowableMemoryProvider<T> for AllocatingMemoryProvider {
unsafe fn grow<F: FnOnce(&mut [MaybeUninit<T>])>(&self, el: &mut Vec<T>, new_size: usize, initializer: F) {
assert!(new_size > el.len());
let old_len = el.len();
el.reserve(new_size - old_len);
initializer(&mut el.spare_capacity_mut()[..(new_size - old_len)]);
el.set_len(new_size);
}
fn shrink(&self, el: &mut Self::Object, new_len: usize) {
el.truncate(new_len)
}
}
pub static ALLOCATING_MEMORY_PROVIDER_SINGLETON: AllocatingMemoryProvider = AllocatingMemoryProvider;
impl Default for AllocatingMemoryProvider {
fn default() -> Self {
AllocatingMemoryProvider
}
}
#[derive(Clone, Copy)]
pub struct LoggingMemoryProvider {
description: &'static str
}
impl LoggingMemoryProvider {
pub const fn new(description: &'static str) -> Self {
LoggingMemoryProvider { description }
}
}
impl<'a, T> MemoryProvider<T> for &'a LoggingMemoryProvider {
type Object = Vec<T>;
unsafe fn get_new<F: FnOnce(&mut [MaybeUninit<T>])>(&self, size: usize, initializer: F) -> Self::Object {
println!("[{}]: Allocating {} entries of size {}", self.description, size, std::mem::size_of::<T>());
AllocatingMemoryProvider.get_new(size, initializer)
}
}
impl<'a, T> GrowableMemoryProvider<T> for &'a LoggingMemoryProvider {
unsafe fn grow<F: FnOnce(&mut [MaybeUninit<T>])>(&self, el: &mut Vec<T>, new_size: usize, initializer: F) {
assert!(new_size > el.len());
let old_len = el.len();
el.reserve(new_size - old_len);
initializer(&mut el.spare_capacity_mut()[..(new_size - old_len)]);
el.set_len(new_size);
}
fn shrink(&self, el: &mut Self::Object, new_len: usize) {
el.truncate(new_len)
}
}
#[cfg(not(feature = "log_memory"))]
pub type DefaultMemoryProvider = AllocatingMemoryProvider;
#[cfg(feature = "log_memory")]
pub type DefaultMemoryProvider = &'static LoggingMemoryProvider;
#[macro_export]
macro_rules! current_function {
() => {{
struct LocalMemoryProvider;
std::any::type_name::<LocalMemoryProvider>()
}}
}
#[macro_export]
#[cfg(not(feature = "log_memory"))]
macro_rules! default_memory_provider {
() => {
$crate::mempool::ALLOCATING_MEMORY_PROVIDER_SINGLETON
};
}
#[macro_export]
#[cfg(feature = "log_memory")]
macro_rules! default_memory_provider {
() => {
{
static LOCAL_MEMORY_PROVIDER: $crate::mempool::LoggingMemoryProvider = $crate::mempool::LoggingMemoryProvider::new($crate::current_function!());
&LOCAL_MEMORY_PROVIDER as &'static $crate::mempool::LoggingMemoryProvider
}
};
}