diff --git a/src/iter.rs b/src/iter.rs index 95139cb..64a65dd 100644 --- a/src/iter.rs +++ b/src/iter.rs @@ -183,11 +183,20 @@ impl<'a, T> Iterator for IntoIter<'a, T> impl<'a, T> FusedIterator for IntoIter<'a, T>{} impl<'a, T> ExactSizeIterator for IntoIter<'a, T>{} +/// A reference iterator for a full `Populator<'re, T>`. #[derive(Debug)] -struct FullIterRef<'a, T>(std::slice::Iter<'a, T>); -//struct PartialIterRef<'a, T>(&) //XXX: This probably isn't possible unless it takes an exclusive reference of Populator<'a, T>. Having to pass 'a around really sucks hey. +pub struct FullIterRef<'re, 'a: 're, T: 'a>(std::slice::Iter<'a, T>, PhantomLifetime<'re>); -impl<'a, T> Iterator for FullIterRef<'a, T> +impl<'re, 'a: 're, T: 'a> FullIterRef<'re, 'a, T> +{ + #[inline(always)] + pub(super) fn new(slice: &'a [T]) -> Self + { + Self (slice.iter(), PhantomLifetime::new()) + } +} + +impl<'re, 'a: 're, T: 'a> Iterator for FullIterRef<'re, 'a, T> { type Item = &'a T; #[inline] @@ -200,14 +209,166 @@ impl<'a, T> Iterator for FullIterRef<'a, T> } } -impl<'a, T> DoubleEndedIterator for FullIterRef<'a, T> +impl<'re, 'a: 're, T: 'a> DoubleEndedIterator for FullIterRef<'re, 'a, T> { fn next_back(&mut self) -> Option { self.0.next_back() } } -impl<'a, T> FusedIterator for FullIterRef<'a, T>{} -impl<'a, T> ExactSizeIterator for FullIterRef<'a, T>{} +impl<'re, 'a: 're, T: 'a> FusedIterator for FullIterRef<'re, 'a, T>{} +impl<'re, 'a: 're, T: 'a> ExactSizeIterator for FullIterRef<'re, 'a, T>{} + +/// A mutable reference iterator for a full `Populator<'re, T>`. +#[derive(Debug)] +pub struct FullIterMut<'re, 'a: 're, T: 'a>(std::slice::IterMut<'a, T>, PhantomLifetime<'re>); + +impl<'re, 'a: 're, T: 'a> FullIterMut<'re, 'a, T> +{ + #[inline(always)] + pub(super) fn new(slice: &'a mut [T]) -> Self + { + Self (slice.iter_mut(), PhantomLifetime::new()) + } +} +impl<'re, 'a: 're, T: 'a> Iterator for FullIterMut<'re, 'a, T> +{ + type Item = &'a mut T; + #[inline] + fn next(&mut self) -> Option { + self.0.next() + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } +} +impl<'re, 'a: 're, T: 'a> DoubleEndedIterator for FullIterMut<'re, 'a, T> +{ + fn next_back(&mut self) -> Option { + self.0.next_back() + } +} + +impl<'re, 'a: 're, T: 'a> FusedIterator for FullIterMut<'re, 'a, T>{} +impl<'re, 'a: 're, T: 'a> ExactSizeIterator for FullIterMut<'re, 'a, T>{} + +/// Internal iterator over a `Populator<'a, T>` +#[derive(Debug, Clone)] // PartialEq, Eq +struct IterInternal<'a, T> +{ + //pop: &'re Populator<'a, T>, + values: std::slice::Iter<'a, MaybeUninit>, + populated: std::slice::Iter<'a, AtomicBool>, //XXX: When the iterator ends, this iter will be 1 item behind `values`, so use `values` for size hint. +} + +impl<'a, T: 'a> Iterator for IterInternal<'a, T> +{ + type Item = (&'a MaybeUninit, &'a AtomicBool); + #[inline] + fn next(&mut self) -> Option + { + self.values.next() + .and_then(move |v| self.populated.next() + .map(move |p| (v, p))) + } + #[inline(always)] + fn size_hint(&self) -> (usize, Option) { + self.values.size_hint() + } +} + + +/// An iterator over a full populator, or a range inside a populator. +#[derive(Debug, Clone)] // PartialEq, Eq +pub struct Iter<'re, 'a, T>{ + pop: &'re Populator<'a, T>, + indecies: as IntoIterator>::IntoIter, +} + +impl<'re, 'a, T: 'a> Eq for Iter<'re, 'a, T>{} +impl<'re, 'a, T: 'a> PartialEq for Iter<'re, 'a, T> +{ + #[inline] + fn eq(&self, other: &Self) -> bool + { + std::ptr::eq(self.pop, other.pop) + && self.indecies == other.indecies + } +} + +impl<'re, 'a: 're, T: 'a> Iter<'re, 'a, T> +{ + #[inline] + fn create_from(&self, idx: usize) -> Ref<'re, 'a, T> + { + Ref { + pop: self.pop, + inserted: &self.pop.populates[idx], + idx, + } + } + + #[inline(always)] + pub(crate) fn new_range(pop: &'re Populator<'a, T>, indecies: std::ops::Range) -> Self + { + Self { + pop, + indecies + } + } + pub(crate) fn new_ranged(pop: &'re Populator<'a, T>, indecies: impl Into<(usize, usize)>) -> Self + { + let (a, b) = indecies.into(); + Self { + indecies: (a..b), + pop, + } + } + #[inline(always)] + pub(crate) fn new(pop: &'re Populator<'a, T>) -> Self + { + Self::new_ranged(pop, (0, pop.len())) + } +} + +#[inline(always)] +fn create_from_iter<'iter, 're, 'a: 're, T: 'a>(iter: &'iter Iter<'re, 'a, T>) -> impl Fn(usize) -> Ref<'re, 'a, T> + 'iter +{ + move |idx| iter.create_from(idx) +} + +impl<'re, 'a: 're, T: 'a> Iterator for Iter<'re, 'a, T> +{ + type Item = Ref<'re, 'a, T>; + #[inline] + fn next(&mut self) -> Option + { + self.indecies.next().map(create_from_iter(self)) + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.indecies.size_hint() + } + #[inline] + fn nth(&mut self, idx: usize) -> Option + { + self.indecies.nth(idx).map(create_from_iter(self)) + } +} + +impl<'re, 'a: 're, T: 'a> FusedIterator for Iter<'re, 'a, T>{} +impl<'re, 'a: 're, T: 'a> ExactSizeIterator for Iter<'re, 'a, T>{} +impl<'re, 'a: 're, T: 'a> DoubleEndedIterator for Iter<'re, 'a, T> +{ + #[inline] + fn next_back(&mut self) -> Option { + self.indecies.next_back().map(create_from_iter(self)) + } + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + self.indecies.nth_back(n).map(create_from_iter(self)) + } +} diff --git a/src/lib.rs b/src/lib.rs index 9cf5728..6ca4bd6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -423,7 +423,7 @@ impl<'a, T> Populator<'a, T> /// # Panics /// If the collection was not full. #[inline] - pub fn completed_mut(&mut self) -> &[T] + pub fn completed_mut(&mut self) -> &mut [T] { self.try_completed_mut().expect("Collection was not fully populated") } @@ -459,6 +459,69 @@ impl<'a, T> Populator<'a, T> Err(_) => panic_uncomplete(), } } + + /// Create an iterator over references to a completed population if it is completed. + #[inline] + pub fn try_completed_iter(&self) -> Option> + { + self.try_completed_ref().map(iter::FullIterRef::new) + } + + /// Create an iterator over references to a completed population. + /// + /// # Panics + /// If the collection is not fully populated + #[inline] + pub fn completed_iter(&self) -> iter::FullIterRef<'a, '_, T> + { + iter::FullIterRef::new(self.completed_ref()) + } + + + /// Create a mutable iterator over references to a completed population if it is completed. + #[inline] + pub fn try_completed_iter_mut(&mut self) -> Option> + { + self.try_completed_mut().map(iter::FullIterMut::new) + } + + /// Create a mutable iterator over references to a completed population. + /// + /// # Panics + /// If the collection is not fully populated + #[inline] + pub fn completed_iter_mut(&mut self) -> iter::FullIterMut<'a, '_, T> + { + iter::FullIterMut::new(self.completed_mut()) + } + + /// Create an iterator of references to this `Populator<'a, T>` + #[inline] + pub fn iter(&self) -> iter::Iter<'a, '_, T> + { + iter::Iter::new(self) + } + + /// Create an iterator of references to a slice of this `Populator<'a, T>` + /// + /// # Panics + /// if `range.end` is larger than `len()`. + #[inline] + pub fn iter_slice(&self, range: impl Into>) -> iter::Iter<'a, '_, T> + { + let range = range.into(); + if range.end > self.len() { + #[inline(never)] + #[cold] + fn _panic_oob(end: usize, idx: usize) -> ! + { + panic!("Range ends out of the bounds of the populator (length is {end}, range end is {idx})") + } + _panic_oob(self.len(), range.end); + } + + iter::Iter::new_range(self, range) + } } impl<'a, T: 'a> FromIterator> for Populator<'a, T> @@ -494,10 +557,4 @@ impl<'a, T: 'a> IntoIterator for Populator<'a, T> } #[cfg(test)] -mod tests { - #[test] - fn it_works() { - let result = 2 + 2; - assert_eq!(result, 4); - } -} +mod tests; diff --git a/src/refer.rs b/src/refer.rs index b254059..06d717f 100644 --- a/src/refer.rs +++ b/src/refer.rs @@ -1,16 +1,18 @@ //! Single-index references. use super::*; +/// A non-mutable reference to an item in `Populator<'a, T>`, inserted or not. #[derive(Debug)] // PartialEq, PartialOrd ///XXX: TODO: Should this be Clone (and maybe even Copy)? Check OwnedRef below... pub struct Ref<'re, 'a, T: 'a> { - pub(super) pop: &'re Populator<'a, T>, - pub(super) idx: usize, + pub(crate) pop: &'re Populator<'a, T>, + pub(crate) 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? - pub(super) inserted: &'re AtomicBool + pub(crate) inserted: &'re AtomicBool } +/// A mutable reference to an item in `Populator<'a, T>`, inserted or not. #[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? pub struct OwnedRef<'a, T: 'a> // PartialEq, PartialOrd { @@ -18,6 +20,7 @@ pub struct OwnedRef<'a, T: 'a> // PartialEq, PartialOrd pub(super) idx: usize, } +/// An exclusive reference to an item in `Populator<'a, T>`, inserted or not. #[derive(Debug)] pub struct RefEx<'re, 'a, T: 'a> { diff --git a/src/tests.rs b/src/tests.rs new file mode 100644 index 0000000..2fe8077 --- /dev/null +++ b/src/tests.rs @@ -0,0 +1,9 @@ +//! Unit tests +use super::*; + +#[test] +fn single_threaded() +{ + let pop = Populator::new(10); + //for r in pop.iter +}