#![feature(never_type)]
#![feature(new_uninit)]
#![feature(btree_cursors)]
#![feature(maybe_uninit_slice)]
#![doc = include_str!("../Readme.md")]
pub mod cache;
use std::mem::MaybeUninit;
use std::ops::{Deref, DerefMut};
use std::rc::*;
use std::ptr;
pub trait MemoryProviderObject<T> {
fn deref_uninit(&mut self) -> &mut [MaybeUninit<T>];
unsafe fn drop_or_recycle(self: Box<Self>);
unsafe fn deref_initialized(&self) -> &[T];
unsafe fn deref_mut_initialized(&mut self) -> &mut [T];
fn get_creator_identifier(&self) -> &u8;
}
pub struct ManagedSlice<'a, T> {
content: Option<Box<dyn 'a + MemoryProviderObject<T>>>
}
impl<'a, T> Deref for ManagedSlice<'a, T> {
type Target = [T];
fn deref(&self) -> &Self::Target {
unsafe { self.content.as_ref().unwrap().deref_initialized() }
}
}
impl<'a, T> DerefMut for ManagedSlice<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { self.content.as_mut().unwrap().deref_mut_initialized() }
}
}
impl<'a, T> Drop for ManagedSlice<'a, T> {
fn drop(&mut self) {
if self.content.is_some() {
unsafe { self.content.take().unwrap().drop_or_recycle() }
}
}
}
fn try_initialize<T, E, F: FnMut(usize) -> Result<T, E>>(mem: &mut [MaybeUninit<T>], mut initializer: F) -> Result<(), E> {
let mut i = 0;
while i < mem.len() {
match initializer(i) {
Ok(val) => {
mem[i] = MaybeUninit::new(val);
i += 1;
},
Err(err) => {
for j in 0..i {
unsafe { mem[j].assume_init_drop() };
}
return Err(err);
}
};
}
return Ok(());
}
pub trait MemoryProvider<'a, T> {
unsafe fn new(&self, self_rc: &Rc<dyn 'a + MemoryProvider<T>>, size: usize) -> Box<dyn 'a + MemoryProviderObject<T>>;
}
pub trait GrowableMemoryProvider<'a, T>: MemoryProvider<'a, T> {
unsafe fn change_size(&self, data: Box<dyn 'a + MemoryProviderObject<T>>, new_size: usize) -> Box<dyn 'a + MemoryProviderObject<T>>;
unsafe fn new(&self, self_rc: &Rc<dyn 'a + GrowableMemoryProvider<T>>, size: usize) -> Box<dyn 'a + MemoryProviderObject<T>>;
fn upcast(self: Rc<Self>) -> Rc<dyn 'a + MemoryProvider<'a, T>>;
}
pub struct MemProviderRc<'a, T> {
pub ptr: Rc<dyn 'a + MemoryProvider<'a, T>>
}
pub struct GrowableMemProviderRc<'a, T> {
pub ptr: Rc<dyn 'a + GrowableMemoryProvider<'a, T>>
}
impl<'a, T> Clone for GrowableMemProviderRc<'a, T> {
fn clone(&self) -> Self {
Self {
ptr: self.ptr.clone()
}
}
}
impl<'a, T> MemProviderRc<'a, T> {
pub fn new_init<F: FnMut(usize) -> T>(&self, size: usize, mut initializer: F) -> ManagedSlice<'a, T> {
self.try_new_init::<!, _>(size, |i| Ok(initializer(i))).unwrap_or_else(|x| x)
}
pub fn try_new_init<E, F: FnMut(usize) -> Result<T, E>>(&self, size: usize, initializer: F) -> Result<ManagedSlice<'a, T>, E> {
let mut data: Box<dyn 'a + MemoryProviderObject<T>> = unsafe {
self.ptr.new(&self.ptr, size)
};
try_initialize(data.as_mut().deref_uninit(), initializer)?;
return Ok(ManagedSlice { content: Some(data) });
}
}
impl<'a, T> GrowableMemProviderRc<'a, T> {
pub fn as_memory_provider(self) -> MemProviderRc<'a, T> {
MemProviderRc { ptr: self.ptr.upcast() }
}
pub fn shrink(&self, el: &mut ManagedSlice<'a, T>, new_size: usize) {
let old_size = el.len();
assert!(new_size < old_size);
let mut data = el.content.take().unwrap();
for i in new_size..old_size {
unsafe { data.deref_uninit()[i].assume_init_drop() };
}
el.content = Some(unsafe {
self.ptr.change_size(data, new_size)
});
debug_assert_eq!(el.len(), new_size);
}
pub fn try_grow_init<E, F: FnMut(usize) -> Result<T, E>>(&self, el: &mut ManagedSlice<'a, T>, new_size: usize, mut initializer: F) -> Result<(), E> {
let old_size = el.len();
assert!(new_size > old_size);
let mut new_data = unsafe {
self.ptr.change_size(el.content.take().unwrap(), new_size)
};
debug_assert_eq!(new_data.deref_uninit().len(), new_size);
match try_initialize(&mut new_data.deref_uninit()[old_size..], |i| initializer(i + old_size)) {
Ok(()) => {
el.content = Some(new_data);
return Ok(());
},
Err(e) => {
for i in 0..old_size {
unsafe { new_data.deref_uninit()[i].assume_init_drop() };
}
return Err(e);
}
}
}
pub fn grow_init<F: FnMut(usize) -> T>(&self, el: &mut ManagedSlice<'a, T>, new_size: usize, mut initializer: F) {
self.try_grow_init::<!, _>(el, new_size, |i| Ok(initializer(i))).unwrap_or_else(|x| x)
}
pub fn new_init<F: FnMut(usize) -> T>(&self, size: usize, mut initializer: F) -> ManagedSlice<'a, T> {
self.try_new_init::<!, _>(size, |i| Ok(initializer(i))).unwrap_or_else(|x| x)
}
pub fn try_new_init<E, F: FnMut(usize) -> Result<T, E>>(&self, size: usize, initializer: F) -> Result<ManagedSlice<'a, T>, E> {
let mut data: Box<dyn 'a + MemoryProviderObject<T>> = unsafe {
<_ as GrowableMemoryProvider<T>>::new(&*self.ptr, &self.ptr, size)
};
try_initialize(data.as_mut().deref_uninit(), initializer)?;
return Ok(ManagedSlice { content: Some(data) });
}
}
static VEC_MEMORY_OBJECT_TYPE_IDENTIFIER: u8 = 0;
impl<T> MemoryProviderObject<T> for Vec<MaybeUninit<T>> {
unsafe fn drop_or_recycle(mut self: Box<Self>) {
for i in 0..self.len() {
self[i].assume_init_drop();
}
drop(self)
}
unsafe fn deref_initialized(&self) -> &[T] {
MaybeUninit::slice_assume_init_ref(self.as_ref())
}
unsafe fn deref_mut_initialized(&mut self) -> &mut [T] {
MaybeUninit::slice_assume_init_mut(self.as_mut())
}
fn deref_uninit(&mut self) -> &mut [MaybeUninit<T>] {
&mut *self
}
fn get_creator_identifier(&self) -> &u8 {
&VEC_MEMORY_OBJECT_TYPE_IDENTIFIER
}
}
#[derive(Copy, Clone)]
pub struct AllocatingMemoryProvider;
impl AllocatingMemoryProvider {
unsafe fn new_base<'a, T>(size: usize) -> Box<dyn 'a + MemoryProviderObject<T>>
where T: 'a
{
Box::new(Box::new_uninit_slice(size).into_vec())
}
unsafe fn change_size_base<'a, T>(mut data: Box<dyn 'a + MemoryProviderObject<T>>, new_size: usize) -> Box<dyn 'a + MemoryProviderObject<T>> {
assert!(ptr::addr_eq(data.get_creator_identifier(), &VEC_MEMORY_OBJECT_TYPE_IDENTIFIER));
let data_cast = &mut *(&mut *data as *mut (dyn 'a + MemoryProviderObject<T>) as *mut () as *mut Vec<MaybeUninit<T>>);
data_cast.resize_with(new_size, || MaybeUninit::uninit());
return data;
}
}
impl<'a, T> MemoryProvider<'a, T> for AllocatingMemoryProvider
where T: 'a
{
unsafe fn new(&self, _self_rc: &Rc<dyn 'a + MemoryProvider<T>>, size: usize) -> Box<dyn 'a + MemoryProviderObject<T>> {
Self::new_base(size)
}
}
impl<'a, T> GrowableMemoryProvider<'a, T> for AllocatingMemoryProvider
where T: 'a
{
unsafe fn change_size(&self, data: Box<dyn 'a + MemoryProviderObject<T>>, new_size: usize) -> Box<dyn 'a + MemoryProviderObject<T>> {
Self::change_size_base(data, new_size)
}
unsafe fn new(&self, _self_rc: &Rc<dyn 'a + GrowableMemoryProvider<T>>, size: usize) -> Box<dyn 'a + MemoryProviderObject<T>> {
Self::new_base(size)
}
fn upcast(self: Rc<Self>) -> Rc<dyn 'a + MemoryProvider<'a, T>> {
unsafe { Rc::from_raw(Rc::into_raw(self)) }
}
}
#[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<'a, T> for LoggingMemoryProvider
where T: 'a
{
unsafe fn new(&self, _self_rc: &Rc<dyn 'a + MemoryProvider<T>>, size: usize) -> Box<dyn 'a + MemoryProviderObject<T>> {
println!("[{}]: Allocating {} entries of size {}", self.description, size, std::mem::size_of::<T>());
AllocatingMemoryProvider::new_base(size)
}
}
impl<'a, T> GrowableMemoryProvider<'a, T> for LoggingMemoryProvider
where T: 'a
{
unsafe fn change_size(&self, data: Box<dyn 'a + MemoryProviderObject<T>>, new_size: usize) -> Box<dyn 'a + MemoryProviderObject<T>> {
AllocatingMemoryProvider::change_size_base(data, new_size)
}
unsafe fn new(&self, _self_rc: &Rc<dyn 'a + GrowableMemoryProvider<T>>, size: usize) -> Box<dyn 'a + MemoryProviderObject<T>> {
AllocatingMemoryProvider::new_base(size)
}
fn upcast(self: Rc<Self>) -> Rc<dyn 'a + MemoryProvider<'a, T>> {
unsafe { Rc::from_raw(Rc::into_raw(self)) }
}
}
#[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::GrowableMemProviderRc { ptr: std::rc::Rc::new($crate::AllocatingMemoryProvider) }
};
}
#[macro_export]
#[cfg(feature = "log_memory")]
macro_rules! default_memory_provider {
() => {
$crate::GrowableMemProviderRc { ptr: std::rc::Rc::new($crate::LoggingMemoryProvider::new($crate::current_function!())) }
};
}
#[cfg(test)]
use std::cell::RefCell;
#[cfg(test)]
use std::collections::HashSet;
#[cfg(test)]
pub(self) struct TraceDrop {
content: i32,
drop_tracer: Rc<RefCell<HashSet<i32>>>
}
#[cfg(test)]
impl Drop for TraceDrop {
fn drop(&mut self) {
self.drop_tracer.as_ref().borrow_mut().insert(self.content);
}
}
#[test]
fn test_new_init_drop_after_error() {
let drop_tracer = Rc::new(RefCell::new(HashSet::new()));
let result = default_memory_provider!().try_new_init(16, |i| if i < 8 {
Ok(TraceDrop { content: i as i32, drop_tracer: drop_tracer.clone() })
} else {
Err(i)
});
assert_eq!(8, result.err().unwrap());
assert_eq!((0..8).collect::<HashSet<_>>(), *drop_tracer.as_ref().borrow());
}
#[test]
fn test_new_init_drop() {
let drop_tracer = Rc::new(RefCell::new(HashSet::new()));
{
default_memory_provider!().new_init(12, |i| TraceDrop { content: i as i32, drop_tracer: drop_tracer.clone() });
}
assert_eq!((0..12).collect::<HashSet<_>>(), *drop_tracer.as_ref().borrow());
}
#[test]
fn test_new_init() {
let result = default_memory_provider!().new_init(10, |i| i);
assert_eq!(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9][..], &*result);
}
#[test]
fn test_type_erasure() {
let memory_provider: MemProviderRc<i32> = default_memory_provider!().as_memory_provider();
memory_provider.new_init(100, |i| i as i32);
}
#[test]
fn test_grow_init() {
let mut base = default_memory_provider!().new_init(5, |i| i as i32);
assert_eq!(&[0, 1, 2, 3, 4][..], &*base);
default_memory_provider!().grow_init(&mut base, 7, |i| i as i32);
assert_eq!(&[0, 1, 2, 3, 4, 5, 6][..], &*base);
}
#[test]
fn test_shrink_drop() {
let drop_tracer = Rc::new(RefCell::new(HashSet::new()));
let mut result = default_memory_provider!().new_init(5, |i| TraceDrop { content: i as i32, drop_tracer: drop_tracer.clone() });
default_memory_provider!().shrink(&mut result, 2);
assert_eq!((2..5).collect::<HashSet<_>>(), *drop_tracer.as_ref().borrow());
}
#[test]
fn test_try_grow_error_drop() {
let drop_tracer = Rc::new(RefCell::new(HashSet::new()));
let mut result = default_memory_provider!().new_init(5, |i| TraceDrop { content: i as i32, drop_tracer: drop_tracer.clone() });
let error = default_memory_provider!().try_grow_init(&mut result, 7, |i| if i <= 5 {
Ok(TraceDrop { content: i as i32, drop_tracer: drop_tracer.clone() })
} else {
Err(())
});
assert!(error.is_err());
assert!(result.content.is_none());
assert_eq!((0..6).collect::<HashSet<_>>(), *drop_tracer.as_ref().borrow());
}