Moved Ref related things to own private submodule

Fortune for parapop's current commit: Future small blessing − 末小吉
master
Avril 3 years ago
parent 6a4b2e918d
commit c7932794f0
Signed by: flanchan
GPG Key ID: 284488987C31F630

@ -0,0 +1,28 @@
//! Helper functions & types
use super::*;
/// Like PhantomData but for a lifetime. Essentially PhantomData &'a ()
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Copy)]
#[repr(transparent)]
pub struct PhantomLifetime<'a>(std::marker::PhantomData<&'a ()>);
impl<'a> PhantomLifetime<'a>
{
#[inline(always)]
pub const fn new() -> Self { Self (std::marker::PhantomData) }
}
unsafe impl<'a> Send for PhantomLifetime<'a>{}
unsafe impl<'a> Sync for PhantomLifetime<'a>{}
impl<'a> private::Sealed for PhantomLifetime<'a>{}
#[inline(always)]
pub unsafe fn address_eq_overlap<'t, 'u, T, U>(a: &'t T, b: &'u U) -> bool
{
std::ptr::eq(a as *const _, b as *const _ as *const T)
}
#[inline(always)]
pub fn address_eq<'a, 'b, T: ?Sized>(a: &'a T, b: &'b T) -> bool
{
std::ptr::eq(a as *const _, b as *const _)
}

@ -1,5 +1,3 @@
//#![cfg_attr(all(nightly, feature="nightly"), feature(never_type))]
#![allow(dead_code)] #![allow(dead_code)]
use std::sync::atomic::{ use std::sync::atomic::{
@ -12,34 +10,16 @@ use std::mem::{self, MaybeUninit};
use std::cell::UnsafeCell; use std::cell::UnsafeCell;
use std::ops::Drop; use std::ops::Drop;
pub mod iter;
/* XXX: We don't need this. We can just use `()`
#[cfg(all(nightly, feature="nightly"))]
type Void = !;
#[cfg(not(all(nightly, feature="nightly")))]
type Void = std::convert::Infallible;
*/
/// Like PhantomData but for a lifetime. Essentially PhantomData &'a ()
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Copy)]
#[repr(transparent)]
struct PhantomLifetime<'a>(std::marker::PhantomData<&'a ()>);
impl<'a> PhantomLifetime<'a>
{
#[inline(always)]
pub const fn new() -> Self { Self (std::marker::PhantomData) }
}
unsafe impl<'a> Send for PhantomLifetime<'a>{}
unsafe impl<'a> Sync for PhantomLifetime<'a>{}
mod private mod private
{ {
pub(crate) trait Sealed{} pub(crate) trait Sealed{}
} }
mod ext; use ext::*;
pub mod iter;
mod refer; pub use refer::*;
/// A parallel, atomic populator of items /// A parallel, atomic populator of items
#[derive(Debug)] #[derive(Debug)]
pub struct Populator<'a, T: 'a> pub struct Populator<'a, T: 'a>
@ -51,60 +31,6 @@ pub struct Populator<'a, T: 'a>
_lt: PhantomLifetime<'a>, _lt: PhantomLifetime<'a>,
} }
#[derive(Debug)] // PartialEq, PartialOrd
pub struct Ref<'re, 'a, T: 'a>
{
pop: &'re Populator<'a, T>,
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: OR: Hold a reference to the actual AtomicBool at `idx` itself?
}
#[inline(always)]
unsafe fn address_eq_overlap<'t, 'u, T, U>(a: &'t T, b: &'u U) -> bool
{
std::ptr::eq(a as *const _, b as *const _ as *const T)
}
#[inline(always)]
fn address_eq<'a, 'b, T: ?Sized>(a: &'a T, b: &'b T) -> bool
{
std::ptr::eq(a as *const _, b as *const _)
}
impl<'re, 'a, T: 'a> PartialEq for Ref<'re, 'a, T>
{
#[inline]
fn eq(&self, other: &Self) -> bool
{
address_eq(self.pop, other.pop) && self.idx == other.idx
}
}
impl<'re, 'a, T: 'a> PartialOrd for Ref<'re, 'a, T>
{
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
if address_eq(self.pop, other.pop) {
self.idx.partial_cmp(&other.idx)
} else {
None
}
}
}
impl<'re, 'a, T: 'a> Ref<'re, 'a, T>
{
/// Checks if the references item currently exists.
#[inline]
pub fn exists(&self) -> bool
{
self.pop.exists(self.idx)
}
//TODO: Rest, including insertions, etc.
}
//TODO: RefEx: Exclusive reference, holds &'ref mut Populator<'a, T>
impl<'a, T: 'a> Populator<'a, T> impl<'a, T: 'a> Populator<'a, T>
{ {
#[inline(always)] #[inline(always)]
@ -197,6 +123,12 @@ impl<'a, T> Populator<'a, T>
{ {
self.populated.load(atomic::Ordering::Acquire) self.populated.load(atomic::Ordering::Acquire)
} }
/// Faster fullness check for when this instance has no other references
#[inline]
pub fn is_full_exclusive(&mut self) -> bool {
*self.populated.get_mut() == self.len()
}
/// Is the populator full? /// Is the populator full?
#[inline] #[inline]
pub fn is_full(&self) -> bool pub fn is_full(&self) -> bool
@ -207,16 +139,7 @@ impl<'a, T> Populator<'a, T>
#[inline] #[inline]
pub fn len(&self) -> usize pub fn len(&self) -> usize
{ {
self.values_ref().len() self.populates.len()
}
/// Number of items held by the populator
///
/// A faster access than normal `len()`, since this is an exclusive reference
#[inline]
pub fn len_exclusive(&mut self) -> usize
{
self.values.get_mut().len()
} }
/// Create a new, empty populator with this size /// Create a new, empty populator with this size
@ -273,11 +196,21 @@ impl<'a, T> Populator<'a, T>
#[inline] #[inline]
pub fn get_ref(&self, idx: usize) -> Ref<'_, 'a, T> pub fn get_ref(&self, idx: usize) -> Ref<'_, 'a, T>
{ {
#[inline(never)]
#[cold]
fn _panic_oob(idx: usize, len: usize) -> !
{
panic!("Cannot reference slot at index {} (length is {})", idx,len)
}
if idx >= self.populates.len() {
_panic_oob(idx, self.populates.len())
}
Ref { Ref {
pop: self, pop: self,
idx idx
} }
} }
//TODO: get_into(Arc<Self>) -> OwnedRef
//TODO: get_excusive -> RefEx //TODO: get_excusive -> RefEx
/// 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.
@ -322,11 +255,6 @@ impl<'a, T> Populator<'a, T>
} }
} }
/// Faster fullness check for when this instance has no other references
#[inline]
pub fn is_full_exclusive(&mut self) -> bool {
*self.populated.get_mut() == self.len()
}
#[inline(always)] #[inline(always)]
fn take_all(&mut self) -> (Box<[MaybeUninit<T>]>, Box<[AtomicBool]>) fn take_all(&mut self) -> (Box<[MaybeUninit<T>]>, Box<[AtomicBool]>)

@ -0,0 +1,70 @@
//! Single-index references.
use super::*;
#[derive(Debug)] // PartialEq, PartialOrd
pub struct Ref<'re, 'a, T: 'a>
{
pub(super) pop: &'re Populator<'a, T>,
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: OR: Hold a reference to the actual AtomicBool at `idx` itself?
}
impl<'re, 'a, T: 'a> PartialEq for Ref<'re, 'a, T>
{
#[inline]
fn eq(&self, other: &Self) -> bool
{
address_eq(self.pop, other.pop) && self.idx == other.idx
}
}
impl<'re, 'a, T: 'a> PartialOrd for Ref<'re, 'a, T>
{
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
if address_eq(self.pop, other.pop) {
self.idx.partial_cmp(&other.idx)
} else {
None
}
}
}
impl<'re, 'a, T: 'a> Ref<'re, 'a, T>
{
/// The index that this `Ref` refers to.
#[inline]
pub fn slot(&self) -> usize
{
self.idx
}
/// Checks if the references item currently exists.
#[inline]
pub fn exists(&self) -> bool
{
self.pop.exists(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 the number of items now populated is returned.
#[inline]
pub fn try_insert(&self, value: T) -> Result<usize, T>
{
self.pop.try_insert(self.idx, value)
}
/// Insert `value` at the referred slot.
///
/// # Panics
/// If the slot has a value.
#[inline]
pub fn insert(&self, value: T) -> usize
{
self.pop.insert(self.idx, value)
}
}
//TODO: OwnedRef: From Arc<Self> receiver of Arc<Populator<'static, T>>
//TODO: RefEx: Exclusive reference, holds &'ref mut Populator<'a, T>
Loading…
Cancel
Save