#![cfg_attr( feature = "no_std", no_std )]
#![cfg_attr( feature = "no_std", feature( alloc ))]
#[cfg(not(feature="no_std"))] pub(crate) use std::boxed::Box;
#[cfg(not(feature="no_std"))] pub(crate) use std::fmt::{self,Debug};
#[cfg(not(feature="no_std"))] pub(crate) use std::marker::PhantomData;
#[cfg(not(feature="no_std"))] pub(crate) use std::mem::{self,transmute};
#[cfg(not(feature="no_std"))] pub(crate) use std::ops;
#[cfg(not(feature="no_std"))] pub(crate) use std::pin::Pin;
#[cfg(not(feature="no_std"))] pub(crate) use std::ptr::{self,NonNull,drop_in_place};
#[cfg(feature="no_std")] extern crate alloc;
#[cfg(feature="no_std")] pub(crate) use self::alloc::boxed::Box;
#[cfg(feature="no_std")] pub(crate) use self::alloc::vec::Vec;
#[cfg(feature="no_std")] pub(crate) use core::fmt::{self,Debug};
#[cfg(feature="no_std")] pub(crate) use core::marker::PhantomData;
#[cfg(feature="no_std")] pub(crate) use core::mem::{self,transmute};
#[cfg(feature="no_std")] pub(crate) use core::ops;
#[cfg(feature="no_std")] pub(crate) use core::pin::Pin;
#[cfg(feature="no_std")] pub(crate) use core::ptr::{self,NonNull,drop_in_place};
pub enum ChunkLen {
B5 = 32, B6 = 64, B7 = 128, B8 = 256, B9 = 512, B10 = 1024, B11 = 2048, B12 = 4096, B13 = 8192, B14 = 16384, B15 = 32768, B16 = 65536,
}
pub fn chunk_len<T:Indexed>() -> usize { <T as Indexed>::chunk_len() as isize as usize }
pub unsafe trait Indexed: Sized {
fn chunk_len() -> ChunkLen { ChunkLen::B8 }
fn null() -> usize { !0_usize }
unsafe fn get_index( &self ) -> usize;
unsafe fn set_index( &mut self, index: usize );
fn pool( &self ) -> &Pool<Self> { Pool::pool( self )}
unsafe fn pool_mut( &self ) -> &mut Pool<Self> { Pool::pool_mut( self )}
fn pool_non_null( &self ) -> NonNull<Pool<Self>> { unsafe{ NonNull::new_unchecked( Pool::pool_mut( self ))}}
fn pool_push( &self, value: Self ) { unsafe{ self.pool_mut().push( value )}}
unsafe fn pool_write( &self, index: usize, value: Self ) { self.pool_mut().write( index, value ); }
fn pool_reserve( &self, additional: usize ) { unsafe{ self.pool_mut().reserve( additional ); }}
}
#[derive(PartialEq,Eq)]
struct Chunk<T>( Vec<u8>, PhantomData<T> );
type PPool<T> = NonNull<Pool<T>>;
impl<T:Indexed> Chunk<T> {
#[inline] fn data_size() -> usize { mem::size_of::<[T;1]>() * chunk_len::<T>() }
#[inline] fn buffer_size() -> usize { Self::data_size() + mem::size_of::<PPool<T>>() }
#[inline] fn as_ptr( &self ) -> *const T { self.0.as_ptr() as *const T }
#[inline] fn as_mut_ptr( &mut self ) -> *mut T { self.0.as_mut_ptr() as *mut T }
#[inline] fn data_ptr( &self, index: usize ) -> *const T { unsafe{( self.as_ptr() ).add( index )}}
#[inline] fn data_mut_ptr( &mut self, index: usize ) -> *mut T { unsafe{( self.as_mut_ptr() ).add( index )}}
#[inline] fn ppool( &self ) -> *const PPool<T> { self.data_ptr( chunk_len::<T>() ) as *const PPool<T> }
#[inline] fn new( ppool: PPool<T> ) -> Self {
let mut buffer = Vec::<u8>::with_capacity( Self::buffer_size() );
unsafe {
ptr::write( buffer.as_mut_ptr().add( Self::data_size() ) as *mut NonNull<_>, ppool );
}
Chunk( buffer, PhantomData )
}
#[inline] fn write( &mut self, index: usize, value: T ) {
assert!( index <= chunk_len::<T>() );
unsafe{ ptr::write( self.data_mut_ptr( index ), value )};
}
}
impl<T:Indexed+Debug> Debug for Chunk<T> {
fn fmt( &self, fmt: &mut fmt::Formatter ) -> fmt::Result {
let mut p = self.as_ptr();
let mut count = chunk_len::<T>();
let mut buffer = Vec::with_capacity( count );
while count > 0 {
buffer.push( unsafe{ ptr::read( p )});
unsafe{ p = p.offset(1) };
count -= 1;
}
fmt.write_str( "\n" )?;
fmt.debug_struct( "Chunk" )
.field( "ppool", unsafe{ &ptr::read( self.ppool() )})
.field( "buffer", &buffer )
.finish()?;
unsafe{ buffer.set_len(0); }
Ok(())
}
}
impl<T:Indexed> ops::Index<usize> for Chunk<T> {
type Output = T;
fn index( &self, index: usize ) -> &T { unsafe{ &*self.data_ptr( index )}}
}
impl<T:Indexed> ops::IndexMut<usize> for Chunk<T> {
fn index_mut( &mut self, index: usize ) -> &mut T { unsafe{ &mut *self.data_mut_ptr( index )}}
}
#[derive(Debug,PartialEq,Eq)]
pub struct Pool<T:Indexed> {
chunks : Vec<Chunk<T>>, managed : bool, ppool : PPool<T>, subidx : usize, len : usize, cap : usize, }
impl<T:Indexed> Pool<T> {
pub fn new() -> Pin<Box<Self>> { Self::new_pool( true )}
pub fn new_unmanaged() -> Pin<Box<Self>> { Self::new_pool( false )}
fn new_pool( managed: bool ) -> Pin<Box<Self>> {
if mem::size_of::<T>() == 0 {
panic!( "ZSTs are not allowed to be the `Pool`'s element type." );
} else {
let pool = Box::new( Self {
chunks : Vec::new(),
managed ,
ppool : NonNull::dangling(),
subidx : chunk_len::<T>()-1,
len : 0,
cap : 0,
});
unsafe {
let pool = Box::into_raw( pool );
let ppool = NonNull::new_unchecked( pool );
let mut pool = Box::from_raw( pool );
pool.ppool = ppool;
Pin::new_unchecked( pool )
}
}
}
pub fn push( &mut self, mut value: T ) {
self.subidx += 1;
let chunk_len = chunk_len::<T>();
if self.subidx == chunk_len {
if self.len == Self::check( self.chunks.len(), usize::checked_mul, chunk_len ) {
self.chunks.push( Chunk::new( self.ppool ));
self.cap += chunk_len;
}
self.subidx = 0;
}
let len = self.len;
unsafe{ value.set_index( len )};
self.chunks.last_mut().unwrap().write( self.subidx, value );
self.len += 1;
}
#[inline]
pub unsafe fn write( &mut self, index: usize, mut value: T ) {
value.set_index( index );
self.chunks[ index / chunk_len::<T>() ].write( index % chunk_len::<T>(), value );
}
pub fn reserve( &mut self, additional: usize ) {
if let Some( inc_cap ) = self.check_len( usize::checked_add, additional ) .checked_sub( self.cap ) {
let mut chunk_count = inc_cap / chunk_len::<T>();
if inc_cap > 0 && chunk_count == 0 {
chunk_count = 1;
}
for _ in 0..chunk_count {
self.chunks.push( Chunk::new( self.ppool ));
}
self.cap += inc_cap;
}
}
#[inline]
#[inline]
pub fn len( &self ) -> usize { self.len }
#[inline]
pub unsafe fn set_len( &mut self, len: usize ) {
self.len = len;
let sublen = len % chunk_len::<T>();
self.subidx = if sublen == 0 { chunk_len::<T>()-1 } else { sublen-1 };
}
#[inline]
pub fn capacity( &self ) -> usize { self.cap }
pub fn non_null( &self ) -> NonNull<Self> { self.ppool }
pub fn pool( value: &T ) -> &Self {
unsafe {
let remainder = value.get_index() % chunk_len::<T>();
let value = value as *const T;
let off = ( chunk_len::<T>() - remainder ) as isize;
let ppool = ptr::read( value.offset( off ) as *const PPool<T> );
&*ppool.as_ptr()
}
}
pub unsafe fn pool_mut( value: &T ) -> &mut Self {
let remainder = value.get_index() % chunk_len::<T>();
let value = value as *const T;
let off = ( chunk_len::<T>() - remainder ) as isize;
let ppool = ptr::read( value.offset( off ) as *const PPool<T> );
&mut *ppool.as_ptr()
}
pub fn pool_non_null( value: &T ) -> NonNull<Self> { unsafe{ NonNull::new_unchecked( Self::pool_mut( value ))}}
pub fn new_index( &self ) -> usize { self.len }
pub fn is_empty( &self ) -> bool { self.len == 0 }
#[inline]
pub fn iter( &self ) -> Iter<T> {
let last = if self.chunks.is_empty() {(0,0)} else {( self.chunks.len()-1, self.subidx )};
Iter{ pool: self, chunk_idx: 0, elem_idx: 0, last }
}
pub fn iter_mut( &mut self ) -> IterMut<T> {
let last = if self.chunks.is_empty() {(0,0)} else {( self.chunks.len()-1, self.subidx )};
IterMut{ pool: self, chunk_idx: 0, elem_idx: 0, last }
}
pub unsafe fn get_unchecked_data( &self, index: usize ) -> &T {
&self.chunks.get_unchecked( index / chunk_len::<T>() )[ index % chunk_len::<T>() ]
}
pub unsafe fn get_unchecked_data_mut( &mut self, index: usize ) -> &mut T {
&mut self.chunks.get_unchecked_mut( index / chunk_len::<T>() )[ index % chunk_len::<T>() ]
}
fn check( len: usize, grow: fn(usize,usize) -> Option<usize>, additional: usize ) -> usize {
let len = grow( len, additional ).expect( "the requested capacity should be less or equal to `usize::MAX`" );
if mem::size_of::<usize>() < 8 && len > !0_isize as usize {
panic!( "the requested capacity on 32/16 bit platform should be less or equal to `isize::MAX`" );
}
len
}
fn check_len( &self, grow: fn(usize,usize) -> Option<usize>, additional: usize ) -> usize { Self::check( self.len, grow, additional )}
}
impl<T:Indexed> Drop for Pool<T> {
fn drop( &mut self ) {
let len = self.chunks.len();
if self.managed && len > 0 {
for i in 0..len-1 {
let chunk = unsafe{ self.chunks.get_unchecked_mut(i) };
unsafe{ chunk.0.set_len( 0 ); }
for j in 0..chunk_len::<T>() {
unsafe{ drop_in_place( &mut chunk[j] ); }
}
}
unsafe {
let last_chunk = self.chunks.get_unchecked_mut( len-1 );
for j in 0..=self.subidx {
last_chunk.0.set_len( 0 );
drop_in_place( &mut last_chunk[ j ]);
}
}
}
}
}
impl<T:Indexed> ops::Index<usize> for Pool<T> {
type Output = T;
fn index( &self, index: usize ) -> &T {
&self.chunks[ index / chunk_len::<T>() ][ index % chunk_len::<T>() ]
}
}
impl<T:Indexed> ops::IndexMut<usize> for Pool<T> {
fn index_mut( &mut self, index: usize ) -> &mut T {
&mut self.chunks[ index / chunk_len::<T>() ][ index % chunk_len::<T>() ]
}
}
pub struct Iter<'a, T:'a+Indexed> {
pool : &'a Pool<T>,
chunk_idx : usize,
elem_idx : usize,
last : ( usize, usize ),
}
impl<'a, T:'a+Indexed> Iterator for Iter<'a,T> {
type Item = &'a T;
fn next( &mut self ) -> Option<&'a T> {
if ( self.chunk_idx, self.elem_idx ) <= self.last {
let chunk = unsafe{ self.pool.chunks.get_unchecked( self.chunk_idx )};
let elem = &chunk[ self.elem_idx ];
if self.elem_idx == chunk_len::<T>() {
self.elem_idx = 0;
self.chunk_idx += 1;
} else {
self.elem_idx += 1;
}
Some( elem )
} else {
None
}
}
}
pub struct IterMut<'a, T:'a+Indexed> {
pool : &'a mut Pool<T>,
chunk_idx : usize,
elem_idx : usize,
last : ( usize, usize ),
}
impl<'a, T:'a+Indexed> Iterator for IterMut<'a,T> {
type Item = &'a mut T;
fn next( &mut self ) -> Option<&'a mut T> {
if ( self.chunk_idx, self.elem_idx ) <= self.last {
let chunk = unsafe{ self.pool.chunks.get_unchecked_mut( self.chunk_idx )};
let elem = &mut chunk[ self.elem_idx ];
if self.elem_idx == chunk_len::<T>() {
self.elem_idx = 0;
self.chunk_idx += 1;
} else {
self.elem_idx += 1;
}
Some( unsafe{ transmute( elem )})
} else {
None
}
}
}
#[macro_export]
macro_rules! pool {
( $ty:ty[ $($x:expr),* ] ) => {{
let mut pool = $crate::Pool::<$ty>::new();
$( pool.push( $x.into() ); )*
pool
}};
( $ty:ty[ $($x:expr,)* ] ) => { pool!( $ty[ $($x),* ])};
}
#[macro_export]
macro_rules! impl_indexed {
( $name:ident { $field:ident:$field_ty:ty } ) => {
unsafe impl Indexed for $name {
unsafe fn get_index( &self ) -> usize { self.$field as usize }
unsafe fn set_index( &mut self, index: usize ) { self.$field = index as $field_ty; }
}
};
}
#[macro_export]
macro_rules! extrusive_indexed {
($vis:vis $outer:ident { inner: $inner:ty }) => {
$vis struct $outer { index: usize, pub inner: $inner }
unsafe impl Indexed for $outer {
unsafe fn get_index( &self ) -> usize { self.index }
unsafe fn set_index( &mut self, index: usize ) { self.index = index; }
}
impl From<$inner> for $outer {
fn from( inner: $inner ) -> Self { $outer{ index: <Self as Indexed>::null(), inner }}
}
};
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
unsafe impl Indexed for (usize,usize) {
unsafe fn get_index( &self ) -> usize { self.0 }
unsafe fn set_index( &mut self, index: usize ) { self.0 = index; }
}
let pool: Pin<Box<Pool<(usize,usize)>>> = Pool::new();
let addr: *mut Pool<_> = Box::into_raw( Pin::into_inner( pool ));
let mut pool: Box<Pool<(usize,usize)>> = unsafe{ Box::from_raw( addr )};
let mut ptrs = Vec::new();
let ( a, b ) = ( 256_usize, 1024 );
for i in 0..a {
pool.push( (0,i) );
ptrs.push( &pool[i] as *const _ );
}
for i in a..b {
pool.push( (0,i) );
}
for i in 0..a {
assert_eq!( ptrs[i], &pool[i] as *const _ );
assert_eq!( pool[i].pool() as *const _, addr );
}
for i in a..b {
assert_eq!( pool[i].pool() as *const _, addr );
}
}
#[test]
#[should_panic( expected = "ZSTs are not allowed to be the `Pool`'s element type." )]
fn test_zst() {
struct S;
unsafe impl Indexed for S {
unsafe fn get_index( &self ) -> usize { !0 }
unsafe fn set_index( &mut self, _index: usize ) {}
}
let _pool = Pool::<S>::new();
}
}