You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

296 lines
5.9 KiB

//! Pool of objects
use parking_lot::{
RwLock,
Mutex,
};
use atomic_refcell::{
AtomicRefCell,
AtomicRefMut,
};
use std::{
iter,
ops,
mem::{ ManuallyDrop, self },
borrow::{
Borrow,
BorrowMut,
},
};
#[derive(Debug)]
pub struct Pool<T>(RwLock<Vec<AtomicRefCell<T>>>);
#[derive(Debug)]
pub enum PoolRef<'a, T>
{
Inside(AtomicRefMut<'a, T>),
Outside(DeferredRef<'a, T>),
}
impl<'o, T: Send + Sync> PoolRef<'o, T>
{
#[inline]
pub fn as_ref(&self) -> &T
{
self.borrow()
}
#[inline]
pub fn as_mut(&mut self) -> &mut T
{
self.borrow_mut()
}
/// Force insert into pool, then return the mutable ref guard.
pub fn force(self) -> AtomicRefMut<'o, T>
{
match self {
Self::Inside(s) => s,
Self::Outside(deferred) => {
let pool = deferred.1;
let value = AtomicRefCell::new(deferred.detach());
let mut writer = pool.0.write();
let len = writer.len();
writer.push(value);
parking_lot::lock_api::RwLockWriteGuard::downgrade(writer)[len].borrow_mut()
},
}
}
pub fn forget(self)
{
if let Self::Outside(v) = self {
v.forget()
}
}
pub fn try_detach(self) -> Result<T, AtomicRefMut<'o, T>>
{
match self {
Self::Inside(v) => Err(v),
Self::Outside(v) => Ok(v.detach())
}
}
pub fn replace_with<F>(&mut self, with: F) -> T
where F: FnOnce() -> T
{
mem::replace(self.borrow_mut(), with())
}
#[inline]
pub fn replace(&mut self, val: T) -> T
{
self.replace_with(move || val)
}
}
impl<'o, T: Send + Sync + Default> PoolRef<'o, T>
{
#[inline(always)]
pub fn take(&mut self) -> T
{
self.replace_with(T::default)
}
#[inline]
pub fn into_inner(mut self) -> T
{
self.take()
}
}
impl<'o, T> Borrow<T> for PoolRef<'o, T>
{
#[inline]
fn borrow(&self) -> &T {
ops::Deref::deref(self)
}
}
impl<'o, T> BorrowMut<T> for PoolRef<'o, T>
{
#[inline]
fn borrow_mut(&mut self) -> &mut T {
&mut self
}
}
impl<'o, T> ops::Deref for PoolRef<'o, T>
{
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
match self {
Self::Inside(s) => s.deref(),
Self::Outside(s) => s.deref(),
}
}
}
impl<'o, T> ops::DerefMut for PoolRef<'o, T>
{
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
match self {
Self::Inside(s) => s.deref_mut(),
Self::Outside(s) => s.deref_mut(),
}
}
}
#[derive(Debug)]
pub struct DeferredRef<'owner, T>(ManuallyDrop<T>, &'owner Pool<T>);
impl<'o, T: Send + Sync> DeferredRef<'o, T>
{
#[inline(always)]
pub fn detach(mut self) -> T
{
let v= unsafe {
ManuallyDrop::take(&mut self.0)
};
mem::forget(self);
v
}
#[inline(always)]
pub fn forget(mut self)
{
unsafe {
ManuallyDrop::drop(&mut self.0);
}
mem::forget(self);
}
}
impl<'o, T> ops::Drop for DeferredRef<'o, T>
{
fn drop(&mut self) {
self.1.0.write().push(AtomicRefCell::new( unsafe { ManuallyDrop::take(&mut self.0) } ));
}
}
impl<'o, T> ops::Deref for DeferredRef<'o, T>
{
type Target = T;
#[inline(always)]
fn deref(&self) -> &Self::Target {
self.0.deref()
}
}
impl<'o, T> ops::DerefMut for DeferredRef<'o, T>
{
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
self.0.deref_mut()
}
}
impl<T: Send+ Sync + Default> Pool<T>
{
pub fn new(size: usize) -> Self
{
Self(RwLock::new(iter::repeat_with(T::default).map(AtomicRefCell::new).take(size).collect()))
}
#[inline]
pub fn take_one(&self) -> PoolRef<'_, T>
{
self.take_one_or_else(T::default)
}
#[inline]
pub fn take_one_or_default(&self) -> AtomicRefMut<'_, T>
{
self.take_one_or_insert_with(T::default)
}
}
impl<T: Send+Sync> iter::FromIterator<T> for Pool<T>
{
fn from_iter<I: IntoIterator<Item=T>>(iter: I) -> Self
{
Self(RwLock::new(iter.into_iter().map(AtomicRefCell::new).collect()))
}
}
impl<T: Send+Sync> Pool<T>
{
#[inline]
pub fn take_one_or(&self, value: T) -> PoolRef<'_, T>
{
self.take_one_or_else(move || value)
}
pub fn try_take_one(&self) -> Option<AtomicRefMut<'_, T>>
{
for possible in self.0.read().iter() {
possible.try_borrow_mut().ok()?;
}
None
}
pub fn take_one_or_else<F>(&self, new: F) -> PoolRef<'_, T>
where F: FnOnce() -> T
{
let try_borrow = {
let this = &self;
move || -> Option<AtomicRefMut<T>> {
for possible in this.0.read().iter() {
possible.try_borrow_mut().ok()?;
}
None
}
};
if let Some(v) = try_borrow() {
PoolRef::Inside(v)
} else {
PoolRef::Outside(DeferredRef(ManuallyDrop::new(new()), self))
}
}
#[inline]
pub fn new_with_value(size: usize, value: T) -> Self
where T: Clone
{
iter::repeat(value).take(size).collect()
}
pub fn new_with<F>(size: usize, with: F) -> Self
where F: FnMut() -> T
{
Self(RwLock::new(iter::repeat_with(with).map(AtomicRefCell::new).take(size).collect()))
}
#[inline]
pub const fn new_empty() -> Self
{
Self(parking_lot::const_rwlock(Vec::new()))
}
pub fn take_one_or_insert_with<F>(&self, with: F) -> AtomicRefMut<'_, T>
where F: FnOnce() -> T
{
let try_borrow = {
let this = &self;
move || -> Result<AtomicRefMut<T>, parking_lot::RwLockWriteGuard<_>> {
let reader = this.0.upgradable_read();
for possible in reader.iter() {
if let Ok(val) = possible.try_borrow_mut() {
return Ok(val);
}
}
Err(parking_lot::lock_api::RwLockUpgradableReadGuard::upgrade(reader))
}
};
match try_borrow() {
Ok(val) => val,
Err(writer) => {
let l = writer.len();
writer.push(AtomicRefCell::new(with()));
parking_lot::lock_api::RwLockWriteGuard::downgrade(writer)[l].borrow_mut()
},
}
}
#[inline]
pub fn take_one_or_insert_value(&self, value: T) -> AtomicRefMut<'_, T>
{
self.take_one_or_insert_with(move || value)
}
}