Added exclusive reference: `RefEx`. Added `try_completed_{ref,mut}()` which returns a slice of all the elements if the populator has completed.

Fortune for parapop's current commit: Future blessing − 末吉
master
Avril 3 years ago
parent 7748572f79
commit fa6eb5810d
Signed by: flanchan
GPG Key ID: 284488987C31F630

@ -66,6 +66,7 @@ impl<T> ExactSizeIterator for PartialIter<T>{}
trait PopulaterIter<T>: private::Sealed + Iterator<Item=T> + FusedIterator + ExactSizeIterator{ trait PopulaterIter<T>: private::Sealed + Iterator<Item=T> + FusedIterator + ExactSizeIterator{
fn as_debug(&self) -> &dyn Debug fn as_debug(&self) -> &dyn Debug
where T: Debug; where T: Debug;
fn is_complete(&self) -> bool;
} }
impl<T> private::Sealed for PartialIter<T>{} impl<T> private::Sealed for PartialIter<T>{}
@ -85,6 +86,10 @@ impl<T> PopulaterIter<T> for PartialIter<T>
where T: Debug { where T: Debug {
self self
} }
#[inline(always)]
fn is_complete(&self) -> bool {
false
}
} }
impl<T> PopulaterIter<T> for FullIter<T> impl<T> PopulaterIter<T> for FullIter<T>
@ -94,8 +99,16 @@ impl<T> PopulaterIter<T> for FullIter<T>
where T: Debug { where T: Debug {
self self
} }
#[inline(always)]
fn is_complete(&self) -> bool {
false
}
} }
/// An iterator over a `Populator<'a, T>`'s items.
///
/// # Length
/// It is a full iterator of all completed elements, non-inserted elements are ignored.
#[derive(Debug)] #[derive(Debug)]
pub struct IntoIter<'a, T: 'a>(Box<dyn PopulaterIter<T> + 'a>); pub struct IntoIter<'a, T: 'a>(Box<dyn PopulaterIter<T> + 'a>);
@ -103,9 +116,9 @@ pub struct IntoIter<'a, T: 'a>(Box<dyn PopulaterIter<T> + 'a>);
impl<'a, Iter, T: 'a> From<Iter> for IntoIter<'a, T> impl<'a, Iter, T: 'a> From<Iter> for IntoIter<'a, T>
where Iter: private::Sealed + PopulaterIter<T> + 'a where Iter: private::Sealed + PopulaterIter<T> + 'a
{ {
#[inline(always)] #[inline(always)]
fn from(v: Iter) -> Self { fn from(v: Iter) -> Self {
Self(Box::new(v)) Self(Box::new(v))
} }
} }
*/ */
@ -118,8 +131,28 @@ unsafe fn assume_init_boxed<T>(bx: Box<[MaybeUninit<T>]>) -> Box<[T]>
Box::from_raw(raw as *mut [T]) Box::from_raw(raw as *mut [T])
} }
#[inline(always)]
pub(crate) unsafe fn assume_init_mut<T>(slice: &mut [MaybeUninit<T>]) -> &mut [T]
{
//MaybeUninit::slice_assume_init_ref(slice)
&mut (*(slice as *mut [MaybeUninit<T>] as *mut [T]))[..]
}
#[inline(always)]
pub(crate) unsafe fn assume_init_ref<T>(slice: &[MaybeUninit<T>]) -> &[T]
{
//MaybeUninit::slice_assume_init_ref(slice)
&(*(slice.as_ref() as *const [MaybeUninit<T>] as *const [T]))[..]
}
impl<'a, T> IntoIter<'a, T> impl<'a, T> IntoIter<'a, T>
{ {
/// Does this iterator represent a fully completed `Populator<'a, T>`?
#[inline]
pub fn is_complete(&self) -> bool
{
self.0.as_ref().is_complete()
}
pub(super) fn create_from(mut pop: Populator<'a, T>) -> Self pub(super) fn create_from(mut pop: Populator<'a, T>) -> Self
{ {
Self(if pop.is_full_exclusive() { Self(if pop.is_full_exclusive() {

@ -26,7 +26,7 @@ mod refer; pub use refer::*;
pub struct Populator<'a, T: 'a> pub struct Populator<'a, T: 'a>
{ {
values: UnsafeCell<Box<[MaybeUninit<T>]>>, values: UnsafeCell<Box<[MaybeUninit<T>]>>,
populates: Box<[AtomicBool]>, // pub(crate) populates: Box<[AtomicBool]>, //
populated: AtomicUsize, // number of populated items populated: AtomicUsize, // number of populated items
_lt: PhantomLifetime<'a>, _lt: PhantomLifetime<'a>,
@ -159,7 +159,42 @@ impl<'a, T> Populator<'a, T>
_lt: PhantomLifetime::new(), _lt: PhantomLifetime::new(),
} }
} }
/// Try to insert `value` at `idx` from an exclusive reference.
///
/// If `idx` already has a value, then `Err(value)` is returned, otherwise, `value` is inserted into the table and a mutable reference to it is returned.
///
/// # Exclusive accesses
/// Since this is an `&mut self` receiver, no atomic operations are required since there are no other threads with a reference to the current populator.
pub fn try_insert_exclusive(&mut self, idx: usize, value: T) -> Result<&mut T, T>
{
match self.populates[idx].get_mut() {
&mut true => return Err(value),
none => *none = true,
};
if cfg!(debug_assertions) {
match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
let mref = &mut self.values.get_mut()[idx];
*mref = MaybeUninit::new(value);
unsafe {
mref.assume_init_mut()
}
})) {
Err(p) => {
*self.populates[idx].get_mut() = false;
std::panic::resume_unwind(p)
},
Ok(mref) => Ok(mref),
}
} else {
let mref = &mut self.values.get_mut()[idx];
*mref = MaybeUninit::new(value);
Ok(unsafe {
mref.assume_init_mut()
})
}
}
/// Try to insert `value` at `idx`. /// Try to insert `value` at `idx`.
/// ///
/// If `idx` already has a value, then `Err(value)` is returned, otherwise, `value` is inserted into the table and the number of items now populated is returned. /// If `idx` already has a value, then `Err(value)` is returned, otherwise, `value` is inserted into the table and the number of items now populated is returned.
@ -176,7 +211,10 @@ impl<'a, T> Populator<'a, T>
*ptr = MaybeUninit::new(value); *ptr = MaybeUninit::new(value);
} }
})) { })) {
Err(p) => std::panic::resume_unwind(p), Err(p) => {
self.populates[idx].store(false, atomic::Ordering::SeqCst); // Re-set to unoccupied
std::panic::resume_unwind(p)
},
Ok(_) => (), Ok(_) => (),
} }
} else { } else {
@ -192,7 +230,6 @@ impl<'a, T> Populator<'a, T>
Err(value) Err(value)
} }
} }
#[inline(always)] #[inline(always)]
fn bounds_okay(&self, idx: usize) -> bool fn bounds_okay(&self, idx: usize) -> bool
@ -224,6 +261,7 @@ impl<'a, T> Populator<'a, T>
self.bounds_check(idx); self.bounds_check(idx);
Ref { Ref {
pop: self, pop: self,
inserted: &self.populates[idx],
idx idx
} }
} }
@ -235,12 +273,29 @@ impl<'a, T> Populator<'a, T>
#[inline] #[inline]
pub fn into_ref(self: Arc<Self>, idx: usize) -> OwnedRef<'a, T> pub fn into_ref(self: Arc<Self>, idx: usize) -> OwnedRef<'a, T>
{ {
self.bounds_check(idx);
OwnedRef { OwnedRef {
pop: self, pop: self,
idx idx
} }
} }
//TODO: get_excusive -> RefEx
/// Get an exclusive reference for the item at `idx` whether it exists or not.
///
/// # Panics
/// If the index is out of bounds
///
/// # Exclusivity
/// No atomic operations are performed on the returned reference, since as long as it exists, no other reference to this instance can exist.
#[inline]
pub fn get_ref_exclusive(&mut self, idx: usize) -> RefEx<'_, 'a, T>
{
self.bounds_check(idx);
RefEx {
pop: self,
idx,
}
}
/// Try to get an exclusive, mutable reference to an item at `idx` if an item exists there. /// Try to get an exclusive, mutable reference to an item at `idx` if an item exists there.
/// ///
@ -268,7 +323,7 @@ impl<'a, T> Populator<'a, T>
/// ///
/// # Panics /// # Panics
/// If `idx` already has a value inserted. /// If `idx` already has a value inserted.
#[inline] // Maybe? #[inline]
pub fn insert(&self, idx: usize, value: T) -> usize pub fn insert(&self, idx: usize, value: T) -> usize
{ {
#[inline(never)] #[inline(never)]
@ -283,8 +338,30 @@ impl<'a, T> Populator<'a, T>
Err(_) => panic_inserted(idx), Err(_) => panic_inserted(idx),
} }
} }
/// Insert `value` into `idx` through an exclusive reference.
///
/// # Panics
/// If `idx` already has a value inserted.
///
/// # Exclusivity
/// No atomic operations are required since the `&mut self` receiver guarantees no other references to this instance currently exist.
#[inline]
pub fn insert_exclusive(&mut self, idx: usize, value: T) -> &mut T
{
#[inline(never)]
#[cold]
fn panic_inserted(i: usize) -> !
{
panic!("There is already a value at {}", i)
}
match self.try_insert_exclusive(idx, value) {
Ok(v) => v,
Err(_) => panic_inserted(idx),
}
}
#[inline(always)] #[inline(always)]
fn take_all(&mut self) -> (Box<[MaybeUninit<T>]>, Box<[AtomicBool]>) fn take_all(&mut self) -> (Box<[MaybeUninit<T>]>, Box<[AtomicBool]>)
{ {
@ -299,6 +376,8 @@ impl<'a, T> Populator<'a, T>
let inner = self.values.get_mut(); let inner = self.values.get_mut();
mem::replace(inner, vec![].into_boxed_slice()) mem::replace(inner, vec![].into_boxed_slice())
} }
/// If all values are populated, then convert it into a boxed slice and return it. /// If all values are populated, then convert it into a boxed slice and return it.
pub fn try_complete(mut self) -> Result<Box<[T]>, Self> pub fn try_complete(mut self) -> Result<Box<[T]>, Self>
@ -317,6 +396,30 @@ impl<'a, T> Populator<'a, T>
} }
} }
/// If all values are populated, returns a slice of all the elements.
///
/// Performs a single atomic load of the number of currently inserted elements to check for completion
pub fn try_completed_ref(&self) -> Option<&[T]>
{
if self.populated.load(atomic::Ordering::SeqCst) == self.len() {
Some(unsafe { iter::assume_init_ref(&*self.values.get()) })
} else {
None
}
}
/// If all values are populated, returns a mutable slice of all the elements.
///
/// # Exclusivity
/// No atomic operations are required since this exclusive reference to `self` ensures there are no other references to this instance.
pub fn try_completed_mut(&mut self) -> Option<&mut [T]>
{
if *self.populated.get_mut() == self.len() {
Some(unsafe { iter::assume_init_mut(self.values.get_mut()) })
} else {
None
}
}
/// Returns the completed population. /// Returns the completed population.
/// ///
/// # Panics /// # Panics

@ -8,6 +8,7 @@ pub struct Ref<'re, 'a, T: 'a>
pub(super) idx: usize, pub(super) idx: usize,
//TODO: Maybe add inserted bool, or state representing if this Ref has made a change to the populator. The value will be loaded on creation of the Ref, and will be used as a cached version of `completes[idx].load()` //TODO: Maybe add inserted bool, or state representing if this Ref has made a change to the populator. The value will be loaded on creation of the Ref, and will be used as a cached version of `completes[idx].load()`
//TODO: OR: Hold a reference to the actual AtomicBool at `idx` itself? //TODO: OR: Hold a reference to the actual AtomicBool at `idx` itself?
pub(super) inserted: &'re AtomicBool
} }
#[derive(Debug, Clone)] // PartialEq, PartialOrd //XXX: TODO: Should this actually be `Clone`? Ref isn't, because its supposed to be a single reference. But since this is arc'd? #[derive(Debug, Clone)] // PartialEq, PartialOrd //XXX: TODO: Should this actually be `Clone`? Ref isn't, because its supposed to be a single reference. But since this is arc'd?
@ -17,6 +18,12 @@ pub struct OwnedRef<'a, T: 'a> // PartialEq, PartialOrd
pub(super) idx: usize, pub(super) idx: usize,
} }
#[derive(Debug)]
pub struct RefEx<'re, 'a, T: 'a>
{
pub(super) pop: &'re mut Populator<'a, T>,
pub(super) idx: usize,
}
impl<'a, T: 'a> PartialEq for OwnedRef<'a, T> impl<'a, T: 'a> PartialEq for OwnedRef<'a, T>
{ {
@ -78,7 +85,7 @@ impl<'re, 'a, T: 'a> Ref<'re, 'a, T>
#[inline] #[inline]
pub fn exists(&self) -> bool pub fn exists(&self) -> bool
{ {
self.pop.exists(self.idx) self.inserted.load(atomic::Ordering::SeqCst)
} }
/// Try to insert `value` at the referred slot. /// Try to insert `value` at the referred slot.
/// ///
@ -166,6 +173,107 @@ impl<'a, T:'a> OwnedRef<'a, T>
} }
} }
//RefEx: Exclusive reference, holds &'re mut Populator<'a, T>
impl<'re, 'a, T: 'a> RefEx<'re, 'a ,T>
{
/// Get a reference to the parent
#[inline]
pub fn parent(&self) -> &Populator<'a, T>
{
&self.pop
}
/// Get a mutable reference to the parent
#[inline]
pub fn parent_mut(&mut self) -> &mut Populator<'a, T>
{
self.pop
}
/// The index that this `RefEx` refers to.
#[inline]
pub fn slot(&self) -> usize
{
self.idx
}
/// Checks if the references item currently exists.
#[inline]
pub fn exists(&mut self) -> bool
{
self.pop.exists_exclusive(self.idx)
}
/// Try to insert `value` at the referred slot.
///
/// If the slot already has a value, then `Err(value)` is returned, otherwise, `value` is inserted into the table and a reference to the new element is returned
#[inline]
pub fn try_insert(&mut self, value: T) -> Result<&T, T>
{
self.pop.try_insert_exclusive(self.idx, value).map(|x| &*x)
}
/// Try to insert `value` at the referred slot.
///
/// If the slot already has a value, then `Err(value)` is returned, otherwise, `value` is inserted into the table and a mutable reference to the new element is returned.
#[inline]
pub fn try_insert_mut(&mut self, value: T) -> Result<&mut T, T>
{
self.pop.try_insert_exclusive(self.idx, value)
}
/// Insert `value` at the referred slot and returns a reference to the inserted element.
///
/// # Panics
/// If the slot has a value.
#[inline]
pub fn insert(&mut self, value: T) -> &T
{
&*self.pop.insert_exclusive(self.idx, value)
}
/// Insert `value` at the referred slot and returns a reference to the inserted element.
///
/// # Panics
/// If the slot has a value.
#[inline]
pub fn insert_mut(&mut self, value: T) -> &mut T
{
self.pop.insert_exclusive(self.idx, value)
}
/// Consume into the inner populator and slot index
#[inline]
pub fn into_parts(self) -> (&'re mut Populator<'a, T>, usize)
{
(self.pop, self.idx)
}
/// Consume into the inner populator
#[inline]
pub fn into_inner(self) -> &'re mut Populator<'a, T>
{
self.pop
}
}
impl<'re, 'a, T: 'a> From<(&'re Populator<'a, T>, usize)> for Ref<'re, 'a, T>
{
#[inline]
fn from((pop, idx): (&'re Populator<'a, T>, usize)) -> Self
{
Self {
pop,
idx,
inserted: &pop.populates[idx]
}
}
}
impl<'re, 'a, T: 'a> From<Ref<'re, 'a, T>> for (&'re Populator<'a, T>, usize)
{
#[inline]
fn from(from: Ref<'re, 'a, T>) -> Self
{
(from.pop, from.idx)
}
}
impl<'a, T: 'a> From<(Arc<Populator<'a, T>>, usize)> for OwnedRef<'a, T> impl<'a, T: 'a> From<(Arc<Populator<'a, T>>, usize)> for OwnedRef<'a, T>
{ {
#[inline] #[inline]
@ -185,4 +293,19 @@ impl<'a, T: 'a> From<OwnedRef<'a, T>> for (Arc<Populator<'a, T>>, usize)
} }
} }
//TODO: RefEx: Exclusive reference, holds &'re mut Populator<'a, T> impl<'re, 'a, T: 'a> From<RefEx<'re, 'a, T>> for (&'re mut Populator<'a, T>, usize)
{
#[inline]
fn from(from: RefEx<'re, 'a, T>) -> Self {
(from.pop, from.idx)
}
}
impl<'re, 'a, T: 'a> From<(&'re mut Populator<'a, T>, usize)> for RefEx<'re, 'a, T>
{
#[inline]
fn from((pop, idx): (&'re mut Populator<'a, T>, usize)) -> Self
{
Self { pop, idx }
}
}

Loading…
Cancel
Save