#![deny(missing_docs, missing_debug_implementations)]
#![feature(allocator_api, coerce_unsized, slice_ptr_get, unsize)]
use std::{
alloc::{handle_alloc_error, Allocator, Global, Layout},
cmp,
collections::VecDeque,
fmt,
marker::Unsize,
mem,
ops::{self, CoerceUnsized},
ptr::{self, NonNull},
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct GrowablePoolBuilder {
len: usize,
per_growable_len: usize,
per_growable_ptr_alignment: usize,
overgrow: bool,
}
impl Default for GrowablePoolBuilder {
fn default() -> Self {
GrowablePoolBuilder::new()
}
}
impl GrowablePoolBuilder {
pub fn new() -> Self {
GrowablePoolBuilder {
len: 0,
per_growable_len: 8,
per_growable_ptr_alignment: 8,
overgrow: true,
}
}
pub fn enable_overgrow(&mut self, enable: bool) -> &mut Self {
self.overgrow = enable;
self
}
pub fn with_default_capacity(&mut self, len: usize) -> &mut Self {
self.per_growable_len = len;
self
}
pub fn with_default_ptr_alignment(&mut self, ptr_alignment: usize) -> &mut Self {
self.per_growable_ptr_alignment = ptr_alignment;
self
}
pub fn with_capacity(&mut self, capacity: usize) -> &mut Self {
self.len = capacity;
self
}
pub fn build(&self) -> GrowablePool {
let vec = {
let default = Growable::with_capacity(self.per_growable_len, self.per_growable_ptr_alignment);
let mut vec = VecDeque::with_capacity(self.len);
vec.resize(self.len, default);
vec
};
GrowablePool {
len: self.len,
per_growable_len: self.per_growable_len,
per_growable_ptr_alignment: self.per_growable_ptr_alignment,
overgrow: self.overgrow,
vec,
}
}
}
pub struct GrowablePool {
len: usize,
per_growable_len: usize,
per_growable_ptr_alignment: usize,
overgrow: bool,
vec: VecDeque<Growable>,
}
impl Clone for GrowablePool {
fn clone(&self) -> Self {
GrowablePoolBuilder::default()
.with_default_capacity(self.per_growable_len)
.with_default_ptr_alignment(self.per_growable_ptr_alignment)
.with_capacity(self.len)
.enable_overgrow(self.overgrow)
.build()
}
}
impl fmt::Debug for GrowablePool {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "GrowablePool {{ .. {} more allocations available .. }}", self.vec.len())
}
}
impl Default for GrowablePool {
fn default() -> Self {
GrowablePool::new()
}
}
impl GrowablePool {
pub fn new() -> Self {
GrowablePoolBuilder::default().build()
}
pub fn builder() -> GrowablePoolBuilder {
GrowablePoolBuilder::default()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline]
pub fn len(&self) -> usize {
self.vec.len()
}
#[inline]
pub fn allocate<T>(&mut self, t: T) -> Reusable<T> {
match self.vec.pop_front() {
Some(growable) => growable.consume(t),
None => {
let default = Growable::with_capacity(self.per_growable_len, self.per_growable_ptr_alignment);
self.vec.resize(cmp::max(self.len, 1), default);
self.allocate(t)
},
}
}
#[inline]
pub fn free<T>(&mut self, t: Reusable<T>)
where
T: ?Sized,
{
if !self.overgrow && self.vec.len() >= self.len {
return;
}
self.vec.push_front(Reusable::free(t));
}
}
pub struct Growable {
len: usize,
ptr_alignment: usize,
ptr: NonNull<u8>,
}
unsafe impl Send for Growable {}
unsafe impl Sync for Growable {}
impl Clone for Growable {
#[inline]
fn clone(&self) -> Self {
Self::with_capacity(self.len, self.ptr_alignment)
}
}
impl fmt::Pointer for Growable {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
fmt::Pointer::fmt(&self.ptr, formatter)
}
}
impl fmt::Debug for Growable {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
match self.len {
0 => write!(formatter, "Growable::None"),
_ => {
write!(
formatter,
"Growable::Some<len = {:?}, align = {:?}>({:p})",
self.len, self.ptr_alignment, self.ptr
)
},
}
}
}
impl Default for Growable {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl Drop for Growable {
fn drop(&mut self) {
if self.len != 0 {
unsafe {
Global.deallocate(self.ptr, Layout::from_size_align_unchecked(self.len, self.ptr_alignment));
}
}
}
}
impl Growable {
#[inline]
pub fn new() -> Self {
Self::with_capacity(0, 1)
}
#[inline]
pub fn with_capacity_for_type<T>() -> Self {
Self::with_capacity(mem::size_of::<T>(), mem::align_of::<T>())
}
#[inline]
pub fn with_capacity(len: usize, ptr_alignment: usize) -> Self {
let ptr = if len != 0 {
let layout = Layout::from_size_align(len, ptr_alignment).expect("Growable::with_capacity: invalid layout");
Global.allocate(layout).map_or_else(|_| handle_alloc_error(layout), |ptr| ptr.as_non_null_ptr())
} else {
assert!(ptr_alignment.is_power_of_two(), "Growable::with_capacity: alignment must be a power of two");
NonNull::<u8>::dangling()
};
Growable {
len,
ptr_alignment,
ptr,
}
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline]
pub fn len(&self) -> usize {
self.len
}
#[inline]
pub fn alignment(&self) -> usize {
self.ptr_alignment
}
#[inline]
pub fn consume<T>(mut self, t: T) -> Reusable<T> {
self.grow(mem::size_of::<T>(), mem::align_of::<T>());
self.copy(t)
}
fn grow(&mut self, len: usize, ptr_alignment: usize) {
if self.len == 0 {
*self = Self::with_capacity(len, ptr_alignment);
return;
}
if self.len >= len && self.ptr_alignment >= ptr_alignment {
return;
}
let len = cmp::max(self.len, len);
assert_ne!(len, 0, "Growable::grow: realloc to zero");
unsafe {
let layout_curr = Layout::from_size_align_unchecked(self.len, self.ptr_alignment);
let layout = Layout::from_size_align_unchecked(len, ptr_alignment);
let ptr = if layout.align() == layout_curr.align() {
Global.grow(self.ptr, layout_curr, layout)
} else {
Global.deallocate(self.ptr, layout_curr);
Global.allocate(layout)
}
.map_or_else(|_| handle_alloc_error(layout), |ptr| ptr.as_non_null_ptr());
self.len = len;
self.ptr_alignment = ptr_alignment;
self.ptr = ptr;
}
}
fn copy<T>(self, t: T) -> Reusable<T> {
let result = unsafe {
let ptr_raw = self.ptr.cast::<T>().as_ptr();
ptr_raw.write(t);
let ptr = NonNull::new_unchecked(ptr_raw);
Reusable {
len: self.len,
ptr_alignment: self.ptr_alignment,
ptr,
}
};
mem::forget(self);
result
}
}
pub struct Reusable<T: ?Sized> {
len: usize,
ptr_alignment: usize,
ptr: NonNull<T>,
}
unsafe impl<T> Send for Reusable<T> where T: Send + ?Sized {}
unsafe impl<T> Sync for Reusable<T> where T: Sync + ?Sized {}
impl<T> Clone for Reusable<T>
where
T: ?Sized + Clone,
{
fn clone(&self) -> Self {
let growable = Growable::with_capacity_for_type::<T>();
growable.consume(T::clone(&*self))
}
}
impl<T: ?Sized> ops::Deref for Reusable<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { self.ptr.as_ref() }
}
}
impl<T: ?Sized> ops::DerefMut for Reusable<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { self.ptr.as_mut() }
}
}
impl<T> fmt::Pointer for Reusable<T>
where
T: ?Sized,
{
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
fmt::Pointer::fmt(&self.ptr, formatter)
}
}
impl<T> fmt::Debug for Reusable<T>
where
T: ?Sized + fmt::Debug,
{
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
let t: &T = &*self;
fmt::Debug::fmt(t, formatter)
}
}
impl<T: ?Sized> Drop for Reusable<T> {
fn drop(&mut self) {
self.free_in_place();
}
}
impl<T, U> CoerceUnsized<Reusable<U>> for Reusable<T>
where
T: ?Sized + Unsize<U>,
U: ?Sized,
{
}
impl<T: ?Sized> Reusable<T> {
#[inline]
pub fn free(mut this: Self) -> Growable {
let growable = this.free_in_place();
mem::forget(this);
growable
}
#[inline]
pub fn free_move(this: Self) -> (T, Growable)
where
T: Sized,
{
unsafe {
let t = ptr::read(this.ptr.as_ptr());
let growable = Growable {
len: this.len,
ptr_alignment: this.ptr_alignment,
ptr: this.ptr.cast(),
};
mem::forget(this);
(t, growable)
}
}
#[inline]
fn free_in_place(&mut self) -> Growable {
unsafe {
ptr::drop_in_place(self.ptr.as_ptr());
Growable {
len: self.len,
ptr_alignment: self.ptr_alignment,
ptr: self.ptr.cast(),
}
}
}
}
#[inline]
pub fn replace<T, U>(this: Reusable<T>, u: U) -> Reusable<U>
where
T: ?Sized,
{
Reusable::free(this).consume(u)
}