use rustc_hash::FxHashMap;
use std::cell::UnsafeCell;
use std::fmt::Debug;
use std::mem::{self, ManuallyDrop};
use std::ops::{Deref, DerefMut};
use std::ptr::NonNull;
struct RawBuf {
ptr: NonNull<u8>,
capacity: usize, }
const FAST_LANES: usize = 9;
struct Pool {
fast: [Vec<RawBuf>; FAST_LANES],
slow: FxHashMap<(usize, usize), Vec<RawBuf>>,
}
impl Pool {
fn new() -> Self {
Self {
fast: std::array::from_fn(|_| Vec::new()),
slow: FxHashMap::default(),
}
}
#[inline(always)]
fn pop(&mut self, size: usize, align: usize) -> Option<RawBuf> {
if let Some(idx) = fast_index(size, align) {
self.fast[idx].pop()
} else {
self.slow.get_mut(&(size, align))?.pop()
}
}
#[inline(always)]
fn push(&mut self, size: usize, align: usize, buf: RawBuf) {
if let Some(idx) = fast_index(size, align) {
self.fast[idx].push(buf);
} else {
self.slow.entry((size, align)).or_default().push(buf);
}
}
fn clear(&mut self) {
for (idx, bufs) in self.fast.iter_mut().enumerate() {
let align = 1 << idx;
for buf in bufs.drain(..) {
unsafe {
if buf.capacity > 0 {
let layout =
std::alloc::Layout::from_size_align_unchecked(buf.capacity, align);
std::alloc::dealloc(buf.ptr.as_ptr(), layout);
}
}
}
}
for (&(_, align), bufs) in self.slow.iter_mut() {
for buf in bufs.drain(..) {
unsafe {
if buf.capacity > 0 {
let layout =
std::alloc::Layout::from_size_align_unchecked(buf.capacity, align);
std::alloc::dealloc(buf.ptr.as_ptr(), layout);
}
}
}
}
self.slow.clear();
}
}
#[inline(always)]
fn fast_index(size: usize, align: usize) -> Option<usize> {
if size == align && size.is_power_of_two() && size <= 256 {
Some(size.trailing_zeros() as usize)
} else {
None
}
}
impl Drop for Pool {
fn drop(&mut self) {
self.clear();
}
}
thread_local! {
static POOL: UnsafeCell<Pool> = UnsafeCell::new(Pool::new());
}
pub struct PoolVec<T> {
vec: ManuallyDrop<Vec<T>>,
}
#[must_use]
pub fn get<T>() -> PoolVec<T> {
if mem::size_of::<T>() == 0 {
return PoolVec {
vec: ManuallyDrop::new(Vec::new()),
};
}
let vec = POOL
.try_with(|pool| {
let pool = unsafe { &mut *pool.get() };
pool.pop(mem::size_of::<T>(), mem::align_of::<T>())
.map(|buf| unsafe {
Vec::from_raw_parts(
buf.ptr.as_ptr() as *mut T,
0,
buf.capacity / mem::size_of::<T>(),
)
})
})
.ok()
.flatten()
.unwrap_or_default();
PoolVec {
vec: ManuallyDrop::new(vec),
}
}
#[must_use]
pub fn with_capacity<T>(capacity: usize) -> PoolVec<T> {
if mem::size_of::<T>() == 0 {
return PoolVec {
vec: ManuallyDrop::new(Vec::new()),
};
}
let vec = POOL
.try_with(|pool| {
let pool = unsafe { &mut *pool.get() };
pool.pop(mem::size_of::<T>(), mem::align_of::<T>())
.and_then(|buf| {
let cap = buf.capacity / mem::size_of::<T>();
if cap >= capacity {
Some(unsafe { Vec::from_raw_parts(buf.ptr.as_ptr() as *mut T, 0, cap) })
} else {
pool.push(mem::size_of::<T>(), mem::align_of::<T>(), buf);
None
}
})
})
.ok()
.flatten()
.unwrap_or_else(|| Vec::with_capacity(capacity));
PoolVec {
vec: ManuallyDrop::new(vec),
}
}
pub fn clear_pool() {
let _ = POOL.try_with(|pool| {
let pool = unsafe { &mut *pool.get() };
pool.clear();
});
}
impl<T> Default for PoolVec<T> {
fn default() -> Self {
Self::new()
}
}
impl<T> PoolVec<T> {
pub fn new() -> Self {
get()
}
#[must_use]
pub fn into_vec(mut self) -> Vec<T> {
let vec = unsafe { ManuallyDrop::take(&mut self.vec) };
mem::forget(self);
vec
}
}
impl<T> From<Vec<T>> for PoolVec<T> {
fn from(vec: Vec<T>) -> Self {
PoolVec {
vec: ManuallyDrop::new(vec),
}
}
}
impl<T> Deref for PoolVec<T> {
type Target = Vec<T>;
fn deref(&self) -> &Vec<T> {
&self.vec
}
}
impl<T> DerefMut for PoolVec<T> {
fn deref_mut(&mut self) -> &mut Vec<T> {
&mut self.vec
}
}
impl<T> Drop for PoolVec<T> {
fn drop(&mut self) {
if mem::size_of::<T>() == 0 {
unsafe {
ManuallyDrop::drop(&mut self.vec);
}
return;
}
self.vec.clear();
let ptr = self.vec.as_mut_ptr();
let capacity = self.vec.capacity();
if capacity == 0 {
return;
}
let buf = RawBuf {
ptr: unsafe { NonNull::new_unchecked(ptr as *mut u8) },
capacity: capacity * mem::size_of::<T>(),
};
let returned = POOL
.try_with(|pool| {
let pool = unsafe { &mut *pool.get() };
pool.push(mem::size_of::<T>(), mem::align_of::<T>(), buf);
})
.is_ok();
if !returned {
unsafe {
ManuallyDrop::drop(&mut self.vec);
}
}
}
}
impl<T> IntoIterator for PoolVec<T> {
type Item = T;
type IntoIter = std::vec::IntoIter<T>;
fn into_iter(self) -> Self::IntoIter {
self.into_vec().into_iter()
}
}
impl<T> FromIterator<T> for PoolVec<T> {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
let mut v = get::<T>();
v.extend(iter);
v
}
}
impl<T: Debug> Debug for PoolVec<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(**self).fmt(f)
}
}
impl<T> AsRef<[T]> for PoolVec<T> {
fn as_ref(&self) -> &[T] {
&self.vec
}
}
impl<T> AsMut<[T]> for PoolVec<T> {
fn as_mut(&mut self) -> &mut [T] {
&mut self.vec
}
}
impl<T> AsRef<Vec<T>> for PoolVec<T> {
fn as_ref(&self) -> &Vec<T> {
&self.vec
}
}
impl<T> AsMut<Vec<T>> for PoolVec<T> {
fn as_mut(&mut self) -> &mut Vec<T> {
&mut self.vec
}
}