diff --git a/makefile b/makefile index 637134b0..cac0fb0d 100644 --- a/makefile +++ b/makefile @@ -78,14 +78,16 @@ nextest: $(source_files) test_all: fmt_check test doc_check | clippy +fmt_check_cmd := $(cargo) $(rust_nightly) $(cargo_fmt) $(cargo_all_flag) $(rustfmt_check_flag) .PHONY: fmt_check fmt_check: $(source_files) - $(cargo) $(rust_nightly) $(cargo_fmt) $(cargo_all_flag) $(rustfmt_check_flag) + $(fmt_check_cmd) .PHONY: fmt_check fmt: $(source_files) - $(cargo) $(rust_nightly) $(cargo_all_flag) $(cargo_fmt) + - $(fmt_check_cmd) + $(cargo) $(rust_nightly) $(cargo_fmt) $(cargo_all_flag) .PHONY: clippy diff --git a/src/lattice/direction/direction_enum.rs b/src/lattice/direction/direction_enum.rs index b880d567..bcd21166 100644 --- a/src/lattice/direction/direction_enum.rs +++ b/src/lattice/direction/direction_enum.rs @@ -13,7 +13,6 @@ use serde::{Deserialize, Serialize}; use utils_lib::Sealed; use super::{Direction, DirectionIndexing, DirectionList, DirectionTrait}; -use crate::lattice::{LatticeCyclic, LatticeElementToIndex}; use crate::Real; //--------------------------------------- diff --git a/src/lattice/direction/mod.rs b/src/lattice/direction/mod.rs index 05df3638..de76a7d9 100644 --- a/src/lattice/direction/mod.rs +++ b/src/lattice/direction/mod.rs @@ -285,21 +285,6 @@ impl Display for Direction { } } -// /// TODO impl doc -// impl NumberOfLatticeElement for Direction { -// #[inline] -// fn number_of_elements(_lattice: &LatticeCyclic) -> usize { -// D -// } -// } - -// // TODO impl doc -// impl IndexToElement for Direction { -// fn index_to_element(_lattice: &LatticeCyclic, index: usize) -> Option { -// Self::new(index, true) -// } -// } - /// Partial ordering is set as follows: two directions can be compared if they have the same index /// or the same direction sign. In the first case a positive direction is greater than a negative direction /// In the latter case the ordering is done on the index. @@ -542,8 +527,24 @@ implement_direction_from!(); //--------------------------------------- // trait DirectionIndexing +/// An internal trait that direction implements. It is used for auto implementation +/// of trait to avoid conflict. For example [`LatticeElementToIndex`] is implemented +/// for type that are [`DirectionIndexing`] and [`DirectionTrait`]. Moreover we want +/// +/// +/// This trait is a super trait of [`Sealed`] which is private meaning that It can't be +/// implemented outside of this trait. pub trait DirectionTrait: Sealed {} +/// Trait to transform (directions) Types to and from indices independently of a Lattice +/// Contrary to [`LatticeElementToIndex`] [`NumberOfLatticeElement`] and [`IndexToElement`]. +/// +/// This trait is used to automate the code generation for [`Iterator`] and +/// [`rayon::iter::IndexedParallelIterator`] without the overhead of a lattice. +/// +/// +/// This trait is a super trait of [`Sealed`] which is private meaning that i +/// it can't be implemented outside of this trait. pub trait DirectionIndexing: Sealed + Sized { /// Transform an element to an index. #[must_use] @@ -590,12 +591,12 @@ impl DirectionTrait for Direction {} impl DirectionIndexing for Direction { #[inline] fn direction_to_index(&self) -> usize { - self.index() * 2 + if self.is_positive() { 1 } else { 0 } + self.index() * 2 + usize::from(!self.is_positive()) } #[inline] fn direction_from_index(index: usize) -> Option { - Self::new((index.saturating_sub(1)) / 2, index % 2 == 1) + Self::new((index.saturating_sub(1)) / 2, index % 2 == 0) } #[inline] diff --git a/src/lattice/iterator/direction.rs b/src/lattice/iterator/direction.rs index 149d9dc7..1f3f05c2 100644 --- a/src/lattice/iterator/direction.rs +++ b/src/lattice/iterator/direction.rs @@ -12,8 +12,7 @@ use rayon::iter::{ #[cfg(feature = "serde-serialize")] use serde::{Deserialize, Serialize}; -use super::{super::Direction, DoubleEndedCounter, IteratorElement, RandomAccessIterator}; -use crate::lattice::direction::DirectionIndexing; +use super::{super::Direction, IteratorElement, RandomAccessIterator}; /// Iterator over [`Direction`] with the same sign. /// # Example diff --git a/src/lattice/iterator/double_ended_counter.rs b/src/lattice/iterator/double_ended_counter.rs new file mode 100644 index 00000000..fa4925ce --- /dev/null +++ b/src/lattice/iterator/double_ended_counter.rs @@ -0,0 +1,267 @@ +//! Contains [`DoubleEndedCounter`] + +//--------------------------------------- +// uses + +use std::{ + fmt::{self, Display}, + iter::FusedIterator, +}; + +#[cfg(feature = "serde-serialize")] +use serde::{Deserialize, Serialize}; +use utils_lib::{Getter, Sealed}; + +use super::{IteratorElement, RandomAccessIterator}; +use crate::lattice::direction::DirectionIndexing; + +//--------------------------------------- +// struct definition + +/// An iterator that track the front and the back in order to be able to implement +/// [`DoubleEndedIterator`]. +/// +/// By itself it is not use a lot in the library it is used as a properties and use +/// to track the front and the back. [`Iterator`] traits are not (yet ?) implemented +/// on this type. +#[derive(Sealed, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] +#[derive(Getter)] +pub struct DoubleEndedCounter { + /// Front element of the iterator. The state need to be increased before + /// being returned by the next [`Iterator::next`] call. + #[get(Const, Pub)] + #[get_mut(Pub)] + pub(super) front: IteratorElement, + /// End element of the iterator. + /// It needs to be decreased before the next [`DoubleEndedIterator::next_back`] call. + #[get(Const, Pub)] + #[get_mut(Pub)] + pub(super) end: IteratorElement, +} + +impl DoubleEndedCounter { + /// Create a new [`Self`] with [`IteratorElement::FirstElement`] as `front` and + /// [`IteratorElement::LastElement`] as `end` + /// # Example + /// ```ignore + /// use lattice_qcd_rs::lattice::iter::{DoubleEndedCounter,IteratorElement}; + /// let counter = DoubleEndedCounter::<()>::new(); + /// assert_eq!(counter.front(), IteratorElement::FirstElement); + /// assert_eq!(counter.end(), IteratorElement::LastElement); + /// ``` + /// TODO restrict to valid iter ? + pub const fn new() -> Self { + Self { + front: IteratorElement::FirstElement, + end: IteratorElement::LastElement, + } + } + + /// Create a new self with a given `front` and `end` element + pub(super) const fn new_with_front_end( + front: IteratorElement, + end: IteratorElement, + ) -> Self { + Self { front, end } + } + + // possible with_first, with_last +} + +//--------------------------------------- +// common traits + +/// It is [`Self::new`], +impl Default for DoubleEndedCounter { + #[inline] + fn default() -> Self { + Self::new() + } +} + +impl Display for DoubleEndedCounter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "front: {}, end: {}", self.front(), self.end()) + } +} +//--------------------------------------- +// conversion + +impl From> for [IteratorElement; 2] { + #[inline] + fn from(value: DoubleEndedCounter) -> Self { + [value.front, value.end] + } +} + +impl From> for (IteratorElement, IteratorElement) { + #[inline] + fn from(value: DoubleEndedCounter) -> Self { + (value.front, value.end) + } +} + +//--------------------------------------- +// impl of RandomAccessIterator + +impl RandomAccessIterator for DoubleEndedCounter { + type Item = D; + + fn iter_len(&self) -> usize { + self.front() + .direction_to_index() + .saturating_sub(self.end().direction_to_index()) + } + + fn increase_front_element_by(&self, advance_by: usize) -> IteratorElement { + let index = match self.front() { + IteratorElement::FirstElement => 0, + IteratorElement::Element(ref element) => element.direction_to_index() + 1, + IteratorElement::LastElement => { + // early return + return IteratorElement::LastElement; + } + }; + + let new_index = index + advance_by; + IteratorElement::index_to_element(new_index, |index| { + Self::Item::direction_from_index(index) + }) + } + + fn decrease_end_element_by(&self, back_by: usize) -> IteratorElement { + let index = match self.end() { + IteratorElement::FirstElement => { + // early return + return IteratorElement::FirstElement; + } + IteratorElement::Element(ref element) => element.direction_to_index() + 1, + IteratorElement::LastElement => D::number_of_directions() + 1, + }; + + let new_index = index.saturating_sub(back_by); + IteratorElement::index_to_element(new_index, |index| { + Self::Item::direction_from_index(index) + }) + } +} + +//--------------------------------------- +// impl of Iterator traits + +/// TODO DOC +impl Iterator for DoubleEndedCounter +where + Self: RandomAccessIterator, + T: Clone, +{ + type Item = T; + + #[inline] + fn next(&mut self) -> Option { + self.nth(0) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let size = self.iter_len(); + (size, Some(size)) + } + + #[inline] + fn count(self) -> usize + where + Self: Sized, + { + self.iter_len() + } + + #[inline] + fn last(mut self) -> Option + where + Self: Sized, + { + self.nth(self.iter_len().saturating_sub(1)) + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + let len = self.iter_len(); + if len <= n { + if len != 0 { + // we need to change the state of the iterator other wise it could + // produce element we should have otherwise skipped. + *self.front_mut() = self.end().clone(); + } + return None; + } + let next_element = self.increase_front_element_by(n + 1); + *self.front_mut() = next_element.clone(); + next_element.into() + } + + #[inline] + fn max(self) -> Option + where + Self: Sized, + Self::Item: Ord, + { + self.last() + } + + #[inline] + fn min(mut self) -> Option + where + Self: Sized, + Self::Item: Ord, + { + self.next() + } +} + +/// TODO DOC +impl DoubleEndedIterator for DoubleEndedCounter +where + Self: RandomAccessIterator, + T: Clone, +{ + #[inline] + fn next_back(&mut self) -> Option { + self.nth_back(0) + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + let len = self.iter_len(); + if len <= n { + if len != 0 { + // we need to change the state of the iterator other wise it could + // produce element we should have otherwise skipped. + *self.end_mut() = self.front().clone(); + } + return None; + } + let previous_element = self.decrease_end_element_by(n + 1); + *self.end_mut() = previous_element.clone(); + previous_element.into() + } +} + +impl FusedIterator for DoubleEndedCounter +where + Self: RandomAccessIterator, + T: Clone, +{ +} + +impl ExactSizeIterator for DoubleEndedCounter +where + Self: RandomAccessIterator, + T: Clone, +{ + #[inline] + fn len(&self) -> usize { + self.iter_len() + } +} diff --git a/src/lattice/iterator/element.rs b/src/lattice/iterator/element.rs new file mode 100644 index 00000000..8c857c0b --- /dev/null +++ b/src/lattice/iterator/element.rs @@ -0,0 +1,190 @@ +//! Contains [`IteratorElement`] + +//--------------------------------------- +// uses + +use std::fmt::{self, Display}; + +#[cfg(feature = "serde-serialize")] +use serde::{Deserialize, Serialize}; +use utils_lib::Sealed; + +use crate::lattice::{ + direction::DirectionIndexing, LatticeCyclic, LatticeElementToIndex, NumberOfLatticeElement, +}; + +//--------------------------------------- +// enum definition + +/// Enum for internal use of iterator. It store the previous element returned by `next` +#[allow(clippy::exhaustive_enums)] +#[derive(Sealed, Debug, Clone, Copy, Hash, PartialOrd, Ord, PartialEq, Eq)] +#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] +pub enum IteratorElement { + /// First element of the iterator + FirstElement, + /// An element of the iterator + Element(T), + /// The Iterator is exhausted + LastElement, +} + +//--------------------------------------- +// impl block + +impl IteratorElement { + // TODO useful fn like map or other think like Option + + /// Map an [`IteratorElement::`] to [`IteratorElement::`] + #[inline] + #[must_use] + pub fn map U>(self, func: F) -> IteratorElement { + match self { + Self::FirstElement => IteratorElement::FirstElement, + Self::Element(element) => IteratorElement::Element(func(element)), + Self::LastElement => IteratorElement::LastElement, + } + } + + /// Convert a `&IteratorElement` to an `IteratorElement<&T>`. + #[inline] + #[must_use] + pub const fn as_ref(&self) -> IteratorElement<&T> { + match self { + Self::FirstElement => IteratorElement::FirstElement, + Self::Element(ref t) => IteratorElement::Element(t), + Self::LastElement => IteratorElement::LastElement, + } + } + + /// Convert a `&mut IteratorElement` to an `IteratorElement<&mut T>`. + #[inline] + #[must_use] + pub fn as_mut(&mut self) -> IteratorElement<&mut T> { + match self { + Self::FirstElement => IteratorElement::FirstElement, + Self::Element(ref mut t) => IteratorElement::Element(t), + Self::LastElement => IteratorElement::LastElement, + } + } + + /// Transform an index to an element mapping o to [`Self::FirstElement`] and + /// index - 1 to the closure. If the closure returns None [`Self::LastElement`] is + /// returned instead. + #[inline] + #[must_use] + pub(super) fn index_to_element Option>( + index: usize, + closure: F, + ) -> Self { + if index == 0 { + Self::FirstElement + } else { + closure(index - 1).map_or(Self::LastElement, Self::Element) + } + } + + /// Computes the number of elements left with the given element as the `front` + /// of an potential iterator. + #[must_use] + #[inline] + pub(super) fn size_position(&self, lattice: &LatticeCyclic) -> usize + where + T: LatticeElementToIndex + NumberOfLatticeElement, + { + match self { + Self::FirstElement => T::number_of_elements(lattice), + Self::Element(ref element) => { + T::number_of_elements(lattice).saturating_sub(element.to_index(lattice) + 1) + } + Self::LastElement => 0, + } + } +} + +//--------------------------------------- +// common traits + +impl Display for IteratorElement { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::FirstElement => write!(f, "first element"), + Self::Element(t) => write!(f, "element {t}"), + Self::LastElement => write!(f, "last element"), + } + } +} + +/// Returns [`IteratorElement::FirstElement`] +impl Default for IteratorElement { + #[inline] + fn default() -> Self { + Self::FirstElement + } +} + +//--------------------------------------- +// conversion traits + +/// Returns [`Some`] in the case of [`IteratorElement::Element`], [`None`] otherwise. +impl From> for Option { + #[inline] + fn from(element: IteratorElement) -> Self { + match element { + IteratorElement::Element(el) => Some(el), + IteratorElement::LastElement | IteratorElement::FirstElement => None, + } + } +} + +//--------------------------------------- +// Lattice indexing + +/// Index [`Self`] as 0 for the [`Self::FirstElement`], +/// [`NumberOfLatticeElement::number_of_elements`] + 1 for [`Self::LastElement`] +/// and index + 1 for any other element. +impl + NumberOfLatticeElement> + LatticeElementToIndex for IteratorElement +{ + #[inline] + fn to_index(&self, lattice: &LatticeCyclic) -> usize { + match self { + Self::FirstElement => 0, + Self::Element(ref element) => element.to_index(lattice) + 1, + Self::LastElement => T::number_of_elements(lattice) + 1, + } + } +} + +/// The number of element is the number of element of `T` + 2 +impl + NumberOfLatticeElement> + NumberOfLatticeElement for IteratorElement +{ + #[inline] + fn number_of_elements(lattice: &LatticeCyclic) -> usize { + T::number_of_elements(lattice) + 2 + } +} + +//--------------------------------------- +// DirectionIndexing + +impl DirectionIndexing for IteratorElement { + fn direction_to_index(&self) -> usize { + match self { + Self::FirstElement => 0, + Self::Element(ref e) => e.direction_to_index() + 1, + Self::LastElement => D::number_of_directions() + 1, + } + } + + fn direction_from_index(index: usize) -> Option { + (index < Self::number_of_directions()) + .then(|| Self::index_to_element(index, |index| D::direction_from_index(index))) + } + + fn number_of_directions() -> usize { + D::number_of_directions() + 2 + } +} diff --git a/src/lattice/iterator/lattice_iterator.rs b/src/lattice/iterator/lattice_iterator.rs new file mode 100644 index 00000000..ffed1386 --- /dev/null +++ b/src/lattice/iterator/lattice_iterator.rs @@ -0,0 +1,493 @@ +use std::{ + fmt::{self, Display}, + iter::FusedIterator, + mem, +}; + +use rayon::iter::{IntoParallelIterator, ParallelIterator}; +use utils_lib::{Getter, Sealed}; + +use super::{DoubleEndedCounter, IteratorElement, ParIter, RandomAccessIterator}; +use crate::lattice::{ + IndexToElement, LatticeCyclic, LatticeElementToIndex, NumberOfLatticeElement, +}; + +/// Iterator over a lattice. This is a way to generate fast a ensemble of predetermine +/// element without the need of being allocated for big collection. It is also possible +/// to use a parallel version of the iterator (as explained below). +/// +/// This struct is use for generically implementing [`Iterator`], [`DoubleEndedIterator`] +/// [`ExactSizeIterator`] and [`FusedIterator`]. +/// +/// We can also easily transform to a parallel iterator [`ParIter`] using +/// [`Self::par_iter`], [`Self::as_par_iter`] or [`Self::as_par_iter_mut`]. +/// +/// It is only used +/// for `T` = [`crate::lattice::LatticePoint`] (see [`super::IteratorLatticePoint`]) and +/// for `T` = [`crate::lattice::LatticeLinkCanonical`] (see [`super::IteratorLatticeLinkCanonical`]). +/// (Public) constructors only exist for these possibilities. +/// +/// The iterators can be created from [`crate::lattice::LatticeCyclic::get_points`] and +/// [`crate::lattice::LatticeCyclic::get_links`]. +/// +/// # Example +/// TODO +/// ``` +/// use lattice_qcd_rs::lattice::{LatticeCyclic, LatticeIterator, LatticePoint}; +/// use rayon::prelude::*; +/// # use lattice_qcd_rs::error::ImplementationError; +/// +/// # fn main() -> Result<(), Box> { +/// let lattice = LatticeCyclic::<4>::new(1_f64, 10)?; +/// let iter = LatticeIterator::<'_, 4, LatticePoint<4>>::new(&lattice); +/// # let long_op = |p| {}; +/// let vec = iter +/// .par_iter() +/// .map(|point| long_op(point)) +/// .collect::>(); +/// # Ok(()) +/// # } +/// ``` +// TODO bound explanation +#[derive(Sealed, Debug, Clone, PartialEq, Getter)] +pub struct LatticeIterator<'a, const D: usize, T> { + /// Reference to the lattice. + #[get(Const, copy)] + pub(super) lattice: &'a LatticeCyclic, + + /// Double ended counter using [`IteratorElement`]. + #[get(Const)] + #[get_mut] + pub(super) counter: DoubleEndedCounter, +} + +impl<'a, const D: usize, T> LatticeIterator<'a, D, T> { + /// create a new iterator with a ref to a given lattice, [`IteratorElement::FirstElement`] + /// as the `front` and [`IteratorElement::LastElement`] as the `end`. + /// + /// This method is implemented only for T = [`crate::lattice::LatticePoint`] + /// or [`crate::lattice::LatticeLinkCanonical`]. + /// + /// # Example + /// TODO + /// ``` + /// use lattice_qcd_rs::lattice::{LatticeCyclic, LatticeIterator, LatticePoint}; + /// use nalgebra::Vector4; + /// + /// # fn main() -> Result<(), Box> { + /// let lattice = LatticeCyclic::<4>::new(1_f64, 3)?; + /// let mut iter = LatticeIterator::new(&lattice); + /// + /// assert_eq!( + /// iter.next(), + /// Some(LatticePoint::new(Vector4::new(0, 0, 0, 0))) + /// ); + /// assert_eq!( + /// iter.next(), + /// Some(LatticePoint::new(Vector4::new(1, 0, 0, 0))) + /// ); + /// assert_eq!( + /// iter.next(), + /// Some(LatticePoint::new(Vector4::new(2, 0, 0, 0))) + /// ); + /// assert_eq!( + /// iter.next(), + /// Some(LatticePoint::new(Vector4::new(0, 1, 0, 0))) + /// ); + /// // nth forward + /// assert_eq!( + /// iter.nth(5), + /// Some(LatticePoint::new(Vector4::new(0, 0, 1, 0))) + /// ); + /// + /// // the iterator is double ended so we can poll back + /// assert_eq!( + /// iter.next_back(), + /// Some(LatticePoint::new(Vector4::new(2, 2, 2, 2))) + /// ); + /// assert_eq!( + /// iter.next_back(), + /// Some(LatticePoint::new(Vector4::new(1, 2, 2, 2))) + /// ); + /// assert_eq!( + /// iter.next_back(), + /// Some(LatticePoint::new(Vector4::new(0, 2, 2, 2))) + /// ); + /// // we can also use `nth_back()` + /// assert_eq!( + /// iter.nth_back(8), + /// Some(LatticePoint::new(Vector4::new(0, 2, 1, 2))) + /// ); + /// # Ok(()) + /// # } + /// ``` + // TODO + #[must_use] + #[inline] + pub const fn new(lattice: &'a LatticeCyclic) -> Self + where + Self: RandomAccessIterator, + T: Clone, + { + Self { + lattice, + counter: DoubleEndedCounter::new(), + } + } + + /// Get the front element tracker. + #[must_use] + #[inline] + const fn front(&self) -> &IteratorElement { + self.counter().front() + } + + /// Get the end element tracker. + #[must_use] + #[inline] + const fn end(&self) -> &IteratorElement { + self.counter().end() + } + + /// Get a mutable reference on the front element tracker. + #[must_use] + #[inline] + fn front_mut(&mut self) -> &mut IteratorElement { + self.counter_mut().front_mut() + } + + /// Get a mutable reference on the end element tracker. + #[must_use] + #[inline] + fn end_mut(&mut self) -> &mut IteratorElement { + self.counter_mut().end_mut() + } + + /// create a new iterator. The first [`LatticeIterator::next()`] will return `first_el`. + /// + /// This method is implemented only for T = [`crate::lattice::LatticePoint`] + /// or [`crate::lattice::LatticeLinkCanonical`]. + /// + /// # Example + /// ``` + /// use lattice_qcd_rs::error::ImplementationError; + /// use lattice_qcd_rs::lattice::{ + /// Direction, DirectionEnum, IteratorLatticeLinkCanonical, IteratorLatticePoint, + /// LatticeCyclic, LatticeLinkCanonical, LatticePoint, + /// }; + /// # + /// # fn main() -> Result<(), Box> { + /// + /// let lattice = LatticeCyclic::new(1_f64, 4)?; + /// let first_el = LatticePoint::from([1, 0, 2, 0]); + /// let mut iter = IteratorLatticePoint::new_with_first_element(&lattice, first_el); + /// assert_eq!( + /// iter.next() + /// .ok_or(ImplementationError::OptionWithUnexpectedNone)?, + /// first_el + /// ); + /// + /// let first_el = LatticeLinkCanonical::<4>::new( + /// LatticePoint::from([1, 0, 2, 0]), + /// DirectionEnum::YPos.into(), + /// ) + /// .ok_or(ImplementationError::OptionWithUnexpectedNone)?; + /// let mut iter = IteratorLatticeLinkCanonical::new_with_first_element(&lattice, first_el); + /// assert_eq!( + /// iter.next() + /// .ok_or(ImplementationError::OptionWithUnexpectedNone)?, + /// first_el + /// ); + /// # Ok(()) + /// # } + /// ``` + #[must_use] + #[inline] + pub fn new_with_first_element(lattice: &'a LatticeCyclic, first_el: T) -> Self + where + Self: RandomAccessIterator, + T: Clone, + { + //TODO / FIXME + + // we can't really decrease the first element so we use some trick. + let mut s = Self { + lattice, + counter: DoubleEndedCounter::new_with_front_end( + // we define the front and end reversed. + // we will swap both value afterward + IteratorElement::LastElement, + IteratorElement::Element(first_el), + ), + }; + + // Then we decrease `end`. Also this is fine we don't verify both end of + // the iterator so we don't care that the iter should produce None. + *s.end_mut() = s.decrease_end_element_by(1); + // we then swap the value to get a properly define iterator + mem::swap(&mut s.counter.front, &mut s.counter.end); + s + } + + /// Convert the iterator into an [`rayon::iter::IndexedParallelIterator`]. + #[must_use] + #[inline] + pub const fn par_iter(self) -> ParIter<'a, D, T> + where + Self: RandomAccessIterator, + { + ParIter::new(self) + } + + /// Take a reference of self and return a reference to an [`rayon::iter::IndexedParallelIterator`]. + /// This might not be very useful. Look instead at [`Self::as_par_iter_mut`]. + #[allow(unsafe_code)] + #[must_use] + #[inline] + pub const fn as_par_iter<'b>(&'b self) -> &'b ParIter<'a, D, T> { + // SAFETY: the representation is transparent and the lifetime is not extended + unsafe { &*(self as *const Self).cast::>() } + } + + /// Take a mutable reference of self and return a mutable reference to an + /// [`rayon::iter::IndexedParallelIterator`] + #[allow(unsafe_code)] + #[must_use] + #[inline] + pub fn as_par_iter_mut<'b>(&'b mut self) -> &'b mut ParIter<'a, D, T> { + // SAFETY: the representation is transparent and the lifetime is not extended + unsafe { &mut *(self as *mut Self).cast::>() } + } +} + +// TODO IntoIter trait + +/// Simply display the counter +impl<'a, const D: usize, T: Display> Display for LatticeIterator<'a, D, T> { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.counter()) + } +} + +impl<'a, const D: usize, T> AsRef> for LatticeIterator<'a, D, T> { + #[inline] + fn as_ref(&self) -> &DoubleEndedCounter { + self.counter() + } +} + +impl<'a, const D: usize, T> AsMut> for LatticeIterator<'a, D, T> { + #[inline] + fn as_mut(&mut self) -> &mut DoubleEndedCounter { + self.counter_mut() + } +} + +impl<'a, const D: usize, T> AsRef> for LatticeIterator<'a, D, T> { + #[inline] + fn as_ref(&self) -> &LatticeCyclic { + self.lattice() + } +} + +impl<'a, const D: usize, T> From> for DoubleEndedCounter { + #[inline] + fn from(value: LatticeIterator<'a, D, T>) -> Self { + value.counter + } +} + +impl<'a, const D: usize, T> From<&'a LatticeIterator<'a, D, T>> for &'a LatticeCyclic { + #[inline] + fn from(value: &'a LatticeIterator<'a, D, T>) -> Self { + value.lattice() + } +} + +impl<'a, const D: usize, T> RandomAccessIterator for LatticeIterator<'a, D, T> +where + T: LatticeElementToIndex + NumberOfLatticeElement + IndexToElement, +{ + type Item = T; + + fn iter_len(&self) -> usize { + // we use a saturating sub because the front could go further than the back + // it should not however. + self.front() + .size_position(self.lattice()) + .saturating_sub(self.end().size_position(self.lattice())) + } + + fn increase_front_element_by(&self, advance_by: usize) -> IteratorElement { + let index = match self.front() { + IteratorElement::FirstElement => 0, + IteratorElement::Element(ref element) => element.to_index(self.lattice()) + 1, + IteratorElement::LastElement => { + // early return + return IteratorElement::LastElement; + } + }; + + let new_index = index + advance_by; + IteratorElement::index_to_element(new_index, |index| { + Self::Item::index_to_element(self.lattice(), index) + }) + } + + fn decrease_end_element_by(&self, back_by: usize) -> IteratorElement { + let index = match self.end() { + IteratorElement::FirstElement => { + // early return + return IteratorElement::FirstElement; + } + IteratorElement::Element(ref element) => element.to_index(self.lattice()) + 1, + IteratorElement::LastElement => self.lattice().number_of_points() + 1, + }; + + let new_index = index.saturating_sub(back_by); + IteratorElement::index_to_element(new_index, |index| { + Self::Item::index_to_element(self.lattice(), index) + }) + } +} + +/// TODO DOC +impl<'a, const D: usize, T> Iterator for LatticeIterator<'a, D, T> +where + Self: RandomAccessIterator, + T: Clone, +{ + type Item = T; + + #[inline] + fn next(&mut self) -> Option { + self.nth(0) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let size = self.iter_len(); + (size, Some(size)) + } + + #[inline] + fn count(self) -> usize + where + Self: Sized, + { + self.iter_len() + } + + #[inline] + fn last(mut self) -> Option + where + Self: Sized, + { + self.nth(self.iter_len().saturating_sub(1)) + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + let len = self.iter_len(); + if len <= n { + if len != 0 { + // we need to change the state of the iterator other wise it could + // produce element we should have otherwise skipped. + //*self.front_mut() = self.end().clone(); + *self.front_mut() = IteratorElement::LastElement; + } + return None; + } + let next_element = self.increase_front_element_by(n + 1); + *self.front_mut() = next_element; + // TODO refactor code to save this clone and not have Clone in the bound + self.front().clone().into() + } + + #[inline] + fn max(self) -> Option + where + Self: Sized, + Self::Item: Ord, + { + self.last() + } + + #[inline] + fn min(mut self) -> Option + where + Self: Sized, + Self::Item: Ord, + { + self.next() + } +} + +/// TODO DOC +impl<'a, const D: usize, T> DoubleEndedIterator for LatticeIterator<'a, D, T> +where + Self: RandomAccessIterator, + T: Clone, +{ + #[inline] + fn next_back(&mut self) -> Option { + self.nth_back(0) + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + let len = self.iter_len(); + if len <= n { + if len != 0 { + // we need to change the state of the iterator other wise it could + // produce element we should have otherwise skipped. + //*self.end_mut() = self.front().clone(); + *self.end_mut() = IteratorElement::FirstElement; + } + return None; + } + let previous_element = self.decrease_end_element_by(n + 1); + *self.end_mut() = previous_element; + self.end().clone().into() + } +} + +impl<'a, const D: usize, T> FusedIterator for LatticeIterator<'a, D, T> +where + Self: RandomAccessIterator, + T: Clone, +{ +} + +impl<'a, const D: usize, T> ExactSizeIterator for LatticeIterator<'a, D, T> +where + Self: RandomAccessIterator, + T: Clone, +{ + #[inline] + fn len(&self) -> usize { + self.iter_len() + } +} + +impl<'a, const D: usize, T> From> for LatticeIterator<'a, D, T> { + #[inline] + fn from(value: ParIter<'a, D, T>) -> Self { + value.into_iterator() + } +} + +impl<'a, const D: usize, T> IntoParallelIterator for LatticeIterator<'a, D, T> +where + Self: RandomAccessIterator, + T: Clone + Send, +{ + type Iter = ParIter<'a, D, T>; + type Item = ::Item; + + #[inline] + fn into_par_iter(self) -> Self::Iter { + self.par_iter() + } +} diff --git a/src/lattice/iterator/link_canonical.rs b/src/lattice/iterator/link_canonical.rs index 2e57475a..14546b7e 100644 --- a/src/lattice/iterator/link_canonical.rs +++ b/src/lattice/iterator/link_canonical.rs @@ -2,7 +2,7 @@ //! # Example // TODO -use super::{LatticeIterator, LatticeParIter}; +use super::{LatticeIterator, ParIter}; use crate::lattice::LatticeLinkCanonical; /// Iterator over [`LatticeLinkCanonical`] associated to a particular @@ -13,8 +13,7 @@ pub type IteratorLatticeLinkCanonical<'a, const D: usize> = /// Parallel iterator over [`LatticeLinkCanonical`] /// # Example -pub type ParIterLatticeLinkCanonical<'a, const D: usize> = - LatticeParIter<'a, D, LatticeLinkCanonical>; +pub type ParIterLatticeLinkCanonical<'a, const D: usize> = ParIter<'a, D, LatticeLinkCanonical>; #[cfg(test)] mod test { diff --git a/src/lattice/iterator/mod.rs b/src/lattice/iterator/mod.rs index 26a81b44..1ee123e6 100644 --- a/src/lattice/iterator/mod.rs +++ b/src/lattice/iterator/mod.rs @@ -13,37 +13,40 @@ // - more doc // - optimize other part of the code +//--------------------------------------- +// mod + mod direction; +mod double_ended_counter; +mod element; +mod lattice_iterator; mod link_canonical; +mod parallel_iterator; mod point; +mod producer; -use std::{ - fmt::{self, Display}, - iter::FusedIterator, - mem, -}; - -use rayon::iter::{ - plumbing::{bridge, Consumer, Producer, ProducerCallback, UnindexedConsumer}, - IndexedParallelIterator, IntoParallelIterator, ParallelIterator, -}; -#[cfg(feature = "serde-serialize")] -use serde::{Deserialize, Serialize}; -use utils_lib::{Getter, Sealed}; +//--------------------------------------- +// uses pub use self::direction::IteratorDirection; +pub use self::double_ended_counter::DoubleEndedCounter; +pub use self::element::IteratorElement; +pub use self::lattice_iterator::LatticeIterator; pub use self::link_canonical::{IteratorLatticeLinkCanonical, ParIterLatticeLinkCanonical}; +pub use self::parallel_iterator::ParIter; pub use self::point::{IteratorLatticePoint, ParIterLatticePoint}; -use super::{ - direction::DirectionIndexing, IndexToElement, LatticeCyclic, LatticeElementToIndex, - NumberOfLatticeElement, -}; use crate::private::Sealed; +//--------------------------------------- +// Trait RandomAccessIterator definition + /// Trait for generic implementation of [`Iterator`] for implementor of this trait. /// /// It has a notion of dimension as it is link to the notion of lattice element. /// And a lattice takes a dimension. +/// +/// This trait is a super trait of [`Sealed`] which is private meaning that It can't be +/// implemented outside of this trait. pub trait RandomAccessIterator: Sealed { /// Type of element return by the iterator type Item; @@ -73,1162 +76,6 @@ pub trait RandomAccessIterator: Sealed { // } } -/// Enum for internal use of iterator. It store the previous element returned by `next` -#[allow(clippy::exhaustive_enums)] -#[derive(Sealed, Debug, Clone, Copy, Hash, PartialOrd, Ord, PartialEq, Eq)] -#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] -pub enum IteratorElement { - /// First element of the iterator - FirstElement, - /// An element of the iterator - Element(T), - /// The Iterator is exhausted - LastElement, -} - -impl IteratorElement { - // TODO useful fn like map or other think like Option - - /// Map an [`IteratorElement::`] to [`IteratorElement::`] - #[inline] - #[must_use] - pub fn map U>(self, func: F) -> IteratorElement { - match self { - Self::FirstElement => IteratorElement::FirstElement, - Self::Element(element) => IteratorElement::Element(func(element)), - Self::LastElement => IteratorElement::LastElement, - } - } - - /// Convert a `&IteratorElement` to an `IteratorElement<&T>`. - #[inline] - #[must_use] - pub const fn as_ref(&self) -> IteratorElement<&T> { - match self { - Self::FirstElement => IteratorElement::FirstElement, - Self::Element(ref t) => IteratorElement::Element(t), - Self::LastElement => IteratorElement::LastElement, - } - } - - /// Convert a `&mut IteratorElement` to an `IteratorElement<&mut T>`. - #[inline] - #[must_use] - pub fn as_mut(&mut self) -> IteratorElement<&mut T> { - match self { - Self::FirstElement => IteratorElement::FirstElement, - Self::Element(ref mut t) => IteratorElement::Element(t), - Self::LastElement => IteratorElement::LastElement, - } - } - - /// Transform an index to an element mapping o to [`Self::FirstElement`] and - /// index - 1 to the closure. If the closure returns None [`Self::LastElement`] is - /// returned instead. - #[inline] - #[must_use] - fn index_to_element Option>(index: usize, closure: F) -> Self { - if index == 0 { - Self::FirstElement - } else { - closure(index - 1).map_or(Self::LastElement, Self::Element) - } - } - - /// Computes the number of elements left with the given element as the `front` - /// of an potential iterator. - #[must_use] - #[inline] - fn size_position(&self, lattice: &LatticeCyclic) -> usize - where - T: LatticeElementToIndex + NumberOfLatticeElement, - { - match self { - Self::FirstElement => T::number_of_elements(lattice), - Self::Element(ref element) => { - T::number_of_elements(lattice).saturating_sub(element.to_index(lattice) + 1) - } - Self::LastElement => 0, - } - } -} - -impl Display for IteratorElement { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::FirstElement => write!(f, "first element"), - Self::Element(t) => write!(f, "element {t}"), - Self::LastElement => write!(f, "last element"), - } - } -} - -/// Returns [`IteratorElement::FirstElement`] -impl Default for IteratorElement { - #[inline] - fn default() -> Self { - Self::FirstElement - } -} - -/// Returns [`Some`] in the case of [`IteratorElement::Element`], [`None`] otherwise. -impl From> for Option { - #[inline] - fn from(element: IteratorElement) -> Self { - match element { - IteratorElement::Element(el) => Some(el), - IteratorElement::LastElement | IteratorElement::FirstElement => None, - } - } -} - -/// Index [`Self`] as 0 for the [`Self::FirstElement`], -/// [`NumberOfLatticeElement::number_of_elements`] + 1 for [`Self::LastElement`] -/// and index + 1 for any other element. -impl + NumberOfLatticeElement> - LatticeElementToIndex for IteratorElement -{ - #[inline] - fn to_index(&self, lattice: &LatticeCyclic) -> usize { - match self { - Self::FirstElement => 0, - Self::Element(ref element) => element.to_index(lattice) + 1, - Self::LastElement => T::number_of_elements(lattice) + 1, - } - } -} - -/// The number of element is the number of element of `T` + 2 -impl + NumberOfLatticeElement> - NumberOfLatticeElement for IteratorElement -{ - #[inline] - fn number_of_elements(lattice: &LatticeCyclic) -> usize { - T::number_of_elements(lattice) + 2 - } -} - -impl DirectionIndexing for IteratorElement { - fn direction_to_index(&self) -> usize { - match self { - Self::FirstElement => 0, - Self::Element(ref e) => e.direction_to_index() + 1, - Self::LastElement => D::number_of_directions() + 1, - } - } - - fn direction_from_index(index: usize) -> Option { - (index < Self::number_of_directions()) - .then(|| Self::index_to_element(index, |index| D::direction_from_index(index))) - } - - fn number_of_directions() -> usize { - D::number_of_directions() + 2 - } -} - -/// An iterator that track the front and the back in order to be able to implement -/// [`DoubleEndedIterator`]. -/// -/// By itself it is not use a lot in the library it is used as a properties and use -/// to track the front and the back. [`Iterator`] traits are not (yet ?) implemented -/// on this type. -#[derive(Sealed, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] -#[derive(Getter)] -pub struct DoubleEndedCounter { - /// Front element of the iterator. The state need to be increased before - /// being returned by the next [`Iterator::next`] call. - #[get(Const)] - #[get_mut] - front: IteratorElement, - /// End element of the iterator. - /// It needs to be decreased before the next [`DoubleEndedIterator::next_back`] call. - #[get(Const)] - #[get_mut] - end: IteratorElement, -} - -impl DoubleEndedCounter { - /// Create a new [`Self`] with [`IteratorElement::FirstElement`] as `front` and - /// [`IteratorElement::LastElement`] as `end` - /// # Example - /// ```ignore - /// use lattice_qcd_rs::lattice::iter::{DoubleEndedCounter,IteratorElement}; - /// let counter = DoubleEndedCounter::<()>::new(); - /// assert_eq!(counter.front(), IteratorElement::FirstElement); - /// assert_eq!(counter.end(), IteratorElement::LastElement); - /// ``` - /// TODO restrict to valid iter ? - pub const fn new() -> Self { - Self { - front: IteratorElement::FirstElement, - end: IteratorElement::LastElement, - } - } - - // possible with_first, with_last -} - -/// It is [`Self::new`], -impl Default for DoubleEndedCounter { - #[inline] - fn default() -> Self { - Self::new() - } -} - -impl From> for [IteratorElement; 2] { - #[inline] - fn from(value: DoubleEndedCounter) -> Self { - [value.front, value.end] - } -} - -impl From> for (IteratorElement, IteratorElement) { - #[inline] - fn from(value: DoubleEndedCounter) -> Self { - (value.front, value.end) - } -} - -impl Display for DoubleEndedCounter { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "front: {}, end: {}", self.front(), self.end()) - } -} - -//--------------------------------------- -// impl of RandomAccessIterator - -impl RandomAccessIterator for DoubleEndedCounter { - type Item = D; - - fn iter_len(&self) -> usize { - self.front() - .direction_to_index() - .saturating_sub(self.end().direction_to_index()) - } - - fn increase_front_element_by(&self, advance_by: usize) -> IteratorElement { - let index = match self.front() { - IteratorElement::FirstElement => 0, - IteratorElement::Element(ref element) => element.direction_to_index() + 1, - IteratorElement::LastElement => { - // early return - return IteratorElement::LastElement; - } - }; - - let new_index = index + advance_by; - IteratorElement::index_to_element(new_index, |index| { - Self::Item::direction_from_index(index) - }) - } - - fn decrease_end_element_by(&self, back_by: usize) -> IteratorElement { - let index = match self.end() { - IteratorElement::FirstElement => { - // early return - return IteratorElement::FirstElement; - } - IteratorElement::Element(ref element) => element.direction_to_index() + 1, - IteratorElement::LastElement => D::number_of_directions() + 1, - }; - - let new_index = index.saturating_sub(back_by); - IteratorElement::index_to_element(new_index, |index| { - Self::Item::direction_from_index(index) - }) - } -} - -//--------------------------------------- -// impl of Iterator traits - -/// TODO DOC -impl Iterator for DoubleEndedCounter -where - Self: RandomAccessIterator, - T: Clone, -{ - type Item = T; - - #[inline] - fn next(&mut self) -> Option { - self.nth(0) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let size = self.iter_len(); - (size, Some(size)) - } - - #[inline] - fn count(self) -> usize - where - Self: Sized, - { - self.iter_len() - } - - #[inline] - fn last(mut self) -> Option - where - Self: Sized, - { - self.nth(self.iter_len().saturating_sub(1)) - } - - #[inline] - fn nth(&mut self, n: usize) -> Option { - let len = self.iter_len(); - if len <= n { - if len != 0 { - // we need to change the state of the iterator other wise it could - // produce element we should have otherwise skipped. - *self.front_mut() = self.end().clone(); - } - return None; - } - let next_element = self.increase_front_element_by(n + 1); - *self.front_mut() = next_element.clone(); - next_element.into() - } - - #[inline] - fn max(self) -> Option - where - Self: Sized, - Self::Item: Ord, - { - self.last() - } - - #[inline] - fn min(mut self) -> Option - where - Self: Sized, - Self::Item: Ord, - { - self.next() - } -} - -/// TODO DOC -impl DoubleEndedIterator for DoubleEndedCounter -where - Self: RandomAccessIterator, - T: Clone, -{ - #[inline] - fn next_back(&mut self) -> Option { - self.nth_back(0) - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option { - let len = self.iter_len(); - if len <= n { - if len != 0 { - // we need to change the state of the iterator other wise it could - // produce element we should have otherwise skipped. - *self.end_mut() = self.front().clone(); - } - return None; - } - let previous_element = self.decrease_end_element_by(n + 1); - *self.end_mut() = previous_element.clone(); - previous_element.into() - } -} - -impl FusedIterator for DoubleEndedCounter -where - Self: RandomAccessIterator, - T: Clone, -{ -} - -impl ExactSizeIterator for DoubleEndedCounter -where - Self: RandomAccessIterator, - T: Clone, -{ - #[inline] - fn len(&self) -> usize { - self.iter_len() - } -} - -/// Iterator over a lattice. This is a way to generate fast a ensemble of predetermine -/// element without the need of being allocated for big collection. It is also possible -/// to use a parallel version of the iterator (as explained below). -/// -/// This struct is use for generically implementing [`Iterator`], [`DoubleEndedIterator`] -/// [`ExactSizeIterator`] and [`FusedIterator`]. -/// -/// We can also easily transform to a parallel iterator [`LatticeParIter`] using -/// [`Self::par_iter`], [`Self::as_par_iter`] or [`Self::as_par_iter_mut`]. -/// -/// It is only used -/// for `T` = [`crate::lattice::LatticePoint`] (see [`IteratorLatticePoint`]) and -/// for `T` = [`crate::lattice::LatticeLinkCanonical`] (see [`IteratorLatticeLinkCanonical`]). -/// (Public) constructors only exist for these possibilities. -/// -/// The iterators can be created from [`crate::lattice::LatticeCyclic::get_points`] and -/// [`crate::lattice::LatticeCyclic::get_links`]. -/// -/// # Example -/// TODO -/// ``` -/// use lattice_qcd_rs::lattice::{LatticeCyclic, LatticeIterator, LatticePoint}; -/// use rayon::prelude::*; -/// # use lattice_qcd_rs::error::ImplementationError; -/// -/// # fn main() -> Result<(), Box> { -/// let lattice = LatticeCyclic::<4>::new(1_f64, 10)?; -/// let iter = LatticeIterator::<'_, 4, LatticePoint<4>>::new(&lattice); -/// # let long_op = |p| {}; -/// let vec = iter -/// .par_iter() -/// .map(|point| long_op(point)) -/// .collect::>(); -/// # Ok(()) -/// # } -/// ``` -// TODO bound explanation -#[derive(Sealed, Debug, Clone, PartialEq, Getter)] -pub struct LatticeIterator<'a, const D: usize, T> { - /// Reference to the lattice. - #[get(Const, copy)] - lattice: &'a LatticeCyclic, - - /// Double ended counter using [`IteratorElement`]. - #[get(Const)] - #[get_mut] - counter: DoubleEndedCounter, -} - -impl<'a, const D: usize, T> LatticeIterator<'a, D, T> { - /// create a new iterator with a ref to a given lattice, [`IteratorElement::FirstElement`] - /// as the `front` and [`IteratorElement::LastElement`] as the `end`. - /// - /// This method is implemented only for T = [`crate::lattice::LatticePoint`] - /// or [`crate::lattice::LatticeLinkCanonical`]. - /// - /// # Example - /// TODO - /// ``` - /// use lattice_qcd_rs::lattice::{LatticeCyclic, LatticeIterator, LatticePoint}; - /// use nalgebra::Vector4; - /// - /// # fn main() -> Result<(), Box> { - /// let lattice = LatticeCyclic::<4>::new(1_f64, 3)?; - /// let mut iter = LatticeIterator::new(&lattice); - /// - /// assert_eq!( - /// iter.next(), - /// Some(LatticePoint::new(Vector4::new(0, 0, 0, 0))) - /// ); - /// assert_eq!( - /// iter.next(), - /// Some(LatticePoint::new(Vector4::new(1, 0, 0, 0))) - /// ); - /// assert_eq!( - /// iter.next(), - /// Some(LatticePoint::new(Vector4::new(2, 0, 0, 0))) - /// ); - /// assert_eq!( - /// iter.next(), - /// Some(LatticePoint::new(Vector4::new(0, 1, 0, 0))) - /// ); - /// // nth forward - /// assert_eq!( - /// iter.nth(5), - /// Some(LatticePoint::new(Vector4::new(0, 0, 1, 0))) - /// ); - /// - /// // the iterator is double ended so we can poll back - /// assert_eq!( - /// iter.next_back(), - /// Some(LatticePoint::new(Vector4::new(2, 2, 2, 2))) - /// ); - /// assert_eq!( - /// iter.next_back(), - /// Some(LatticePoint::new(Vector4::new(1, 2, 2, 2))) - /// ); - /// assert_eq!( - /// iter.next_back(), - /// Some(LatticePoint::new(Vector4::new(0, 2, 2, 2))) - /// ); - /// // we can also use `nth_back()` - /// assert_eq!( - /// iter.nth_back(8), - /// Some(LatticePoint::new(Vector4::new(0, 2, 1, 2))) - /// ); - /// # Ok(()) - /// # } - /// ``` - // TODO - #[must_use] - #[inline] - pub const fn new(lattice: &'a LatticeCyclic) -> Self - where - Self: RandomAccessIterator, - T: Clone, - { - Self { - lattice, - counter: DoubleEndedCounter::new(), - } - } - - /// Get the front element tracker. - #[must_use] - #[inline] - const fn front(&self) -> &IteratorElement { - self.counter().front() - } - - /// Get the end element tracker. - #[must_use] - #[inline] - const fn end(&self) -> &IteratorElement { - self.counter().end() - } - - /// Get a mutable reference on the front element tracker. - #[must_use] - #[inline] - fn front_mut(&mut self) -> &mut IteratorElement { - self.counter_mut().front_mut() - } - - /// Get a mutable reference on the end element tracker. - #[must_use] - #[inline] - fn end_mut(&mut self) -> &mut IteratorElement { - self.counter_mut().end_mut() - } - - /// create a new iterator. The first [`LatticeIterator::next()`] will return `first_el`. - /// - /// This method is implemented only for T = [`crate::lattice::LatticePoint`] - /// or [`crate::lattice::LatticeLinkCanonical`]. - /// - /// # Example - /// ``` - /// use lattice_qcd_rs::error::ImplementationError; - /// use lattice_qcd_rs::lattice::{ - /// Direction, DirectionEnum, IteratorLatticeLinkCanonical, IteratorLatticePoint, - /// LatticeCyclic, LatticeLinkCanonical, LatticePoint, - /// }; - /// # - /// # fn main() -> Result<(), Box> { - /// - /// let lattice = LatticeCyclic::new(1_f64, 4)?; - /// let first_el = LatticePoint::from([1, 0, 2, 0]); - /// let mut iter = IteratorLatticePoint::new_with_first_element(&lattice, first_el); - /// assert_eq!( - /// iter.next() - /// .ok_or(ImplementationError::OptionWithUnexpectedNone)?, - /// first_el - /// ); - /// - /// let first_el = LatticeLinkCanonical::<4>::new( - /// LatticePoint::from([1, 0, 2, 0]), - /// DirectionEnum::YPos.into(), - /// ) - /// .ok_or(ImplementationError::OptionWithUnexpectedNone)?; - /// let mut iter = IteratorLatticeLinkCanonical::new_with_first_element(&lattice, first_el); - /// assert_eq!( - /// iter.next() - /// .ok_or(ImplementationError::OptionWithUnexpectedNone)?, - /// first_el - /// ); - /// # Ok(()) - /// # } - /// ``` - #[must_use] - #[inline] - pub fn new_with_first_element(lattice: &'a LatticeCyclic, first_el: T) -> Self - where - Self: RandomAccessIterator, - T: Clone, - { - //TODO / FIXME - - // we can't really decrease the first element so we use some trick. - let mut s = Self { - lattice, - counter: DoubleEndedCounter { - // we define the front and end reversed. - // we will swap both value afterward - front: IteratorElement::LastElement, - end: IteratorElement::Element(first_el), - }, - }; - - // Then we decrease `end`. Also this is fine we don't verify both end of - // the iterator so we don't care that the iter should produce None. - *s.end_mut() = s.decrease_end_element_by(1); - // we then swap the value to get a properly define iterator - mem::swap(&mut s.counter.front, &mut s.counter.end); - s - } - - /// Convert the iterator into an [`IndexedParallelIterator`]. - #[must_use] - #[inline] - pub const fn par_iter(self) -> LatticeParIter<'a, D, T> - where - Self: RandomAccessIterator, - { - LatticeParIter::new(self) - } - - /// Take a reference of self and return a reference to an [`IndexedParallelIterator`]. - /// This might not be very useful. Look instead at [`Self::as_par_iter_mut`]. - #[allow(unsafe_code)] - #[must_use] - #[inline] - pub const fn as_par_iter<'b>(&'b self) -> &'b LatticeParIter<'a, D, T> { - // SAFETY: the representation is transparent and the lifetime is not extended - unsafe { &*(self as *const Self).cast::>() } - } - - /// Take a mutable reference of self and return a mutable reference to an - /// [`IndexedParallelIterator`] - #[allow(unsafe_code)] - #[must_use] - #[inline] - pub fn as_par_iter_mut<'b>(&'b mut self) -> &'b mut LatticeParIter<'a, D, T> { - // SAFETY: the representation is transparent and the lifetime is not extended - unsafe { &mut *(self as *mut Self).cast::>() } - } -} - -// TODO IntoIter trait - -/// Simply display the counter -impl<'a, const D: usize, T: Display> Display for LatticeIterator<'a, D, T> { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.counter()) - } -} - -impl<'a, const D: usize, T> AsRef> for LatticeIterator<'a, D, T> { - #[inline] - fn as_ref(&self) -> &DoubleEndedCounter { - self.counter() - } -} - -impl<'a, const D: usize, T> AsMut> for LatticeIterator<'a, D, T> { - #[inline] - fn as_mut(&mut self) -> &mut DoubleEndedCounter { - self.counter_mut() - } -} - -impl<'a, const D: usize, T> AsRef> for LatticeIterator<'a, D, T> { - #[inline] - fn as_ref(&self) -> &LatticeCyclic { - self.lattice() - } -} - -impl<'a, const D: usize, T> From> for DoubleEndedCounter { - #[inline] - fn from(value: LatticeIterator<'a, D, T>) -> Self { - value.counter - } -} - -impl<'a, const D: usize, T> From<&'a LatticeIterator<'a, D, T>> for &'a LatticeCyclic { - #[inline] - fn from(value: &'a LatticeIterator<'a, D, T>) -> Self { - value.lattice() - } -} - -impl<'a, const D: usize, T> RandomAccessIterator for LatticeIterator<'a, D, T> -where - T: LatticeElementToIndex + NumberOfLatticeElement + IndexToElement, -{ - type Item = T; - - fn iter_len(&self) -> usize { - // we use a saturating sub because the front could go further than the back - // it should not however. - self.front() - .size_position(self.lattice()) - .saturating_sub(self.end().size_position(self.lattice())) - } - - fn increase_front_element_by(&self, advance_by: usize) -> IteratorElement { - let index = match self.front() { - IteratorElement::FirstElement => 0, - IteratorElement::Element(ref element) => element.to_index(self.lattice()) + 1, - IteratorElement::LastElement => { - // early return - return IteratorElement::LastElement; - } - }; - - let new_index = index + advance_by; - IteratorElement::index_to_element(new_index, |index| { - Self::Item::index_to_element(self.lattice(), index) - }) - } - - fn decrease_end_element_by(&self, back_by: usize) -> IteratorElement { - let index = match self.end() { - IteratorElement::FirstElement => { - // early return - return IteratorElement::FirstElement; - } - IteratorElement::Element(ref element) => element.to_index(self.lattice()) + 1, - IteratorElement::LastElement => self.lattice().number_of_points() + 1, - }; - - let new_index = index.saturating_sub(back_by); - IteratorElement::index_to_element(new_index, |index| { - Self::Item::index_to_element(self.lattice(), index) - }) - } -} - -/// TODO DOC -impl<'a, const D: usize, T> Iterator for LatticeIterator<'a, D, T> -where - Self: RandomAccessIterator, - T: Clone, -{ - type Item = T; - - #[inline] - fn next(&mut self) -> Option { - self.nth(0) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let size = self.iter_len(); - (size, Some(size)) - } - - #[inline] - fn count(self) -> usize - where - Self: Sized, - { - self.iter_len() - } - - #[inline] - fn last(mut self) -> Option - where - Self: Sized, - { - self.nth(self.iter_len().saturating_sub(1)) - } - - #[inline] - fn nth(&mut self, n: usize) -> Option { - let len = self.iter_len(); - if len <= n { - if len != 0 { - // we need to change the state of the iterator other wise it could - // produce element we should have otherwise skipped. - *self.front_mut() = self.end().clone(); - } - return None; - } - let next_element = self.increase_front_element_by(n + 1); - *self.front_mut() = next_element.clone(); - next_element.into() - } - - #[inline] - fn max(self) -> Option - where - Self: Sized, - Self::Item: Ord, - { - self.last() - } - - #[inline] - fn min(mut self) -> Option - where - Self: Sized, - Self::Item: Ord, - { - self.next() - } -} - -/// TODO DOC -impl<'a, const D: usize, T> DoubleEndedIterator for LatticeIterator<'a, D, T> -where - Self: RandomAccessIterator, - T: Clone, -{ - #[inline] - fn next_back(&mut self) -> Option { - self.nth_back(0) - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option { - let len = self.iter_len(); - if len <= n { - if len != 0 { - // we need to change the state of the iterator other wise it could - // produce element we should have otherwise skipped. - *self.end_mut() = self.front().clone(); - } - return None; - } - let previous_element = self.decrease_end_element_by(n + 1); - *self.end_mut() = previous_element.clone(); - previous_element.into() - } -} - -impl<'a, const D: usize, T> FusedIterator for LatticeIterator<'a, D, T> -where - Self: RandomAccessIterator, - T: Clone, -{ -} - -impl<'a, const D: usize, T> ExactSizeIterator for LatticeIterator<'a, D, T> -where - Self: RandomAccessIterator, - T: Clone, -{ - #[inline] - fn len(&self) -> usize { - self.iter_len() - } -} - -impl<'a, const D: usize, T> From> for LatticeIterator<'a, D, T> { - #[inline] - fn from(value: LatticeParIter<'a, D, T>) -> Self { - value.into_iterator() - } -} - -impl<'a, const D: usize, T> From> for LatticeIterator<'a, D, T> { - #[inline] - fn from(value: LatticeProducer<'a, D, T>) -> Self { - value.into_iterator() - } -} - -impl<'a, const D: usize, T> IntoParallelIterator for LatticeIterator<'a, D, T> -where - Self: RandomAccessIterator, - T: Clone + Send, -{ - type Iter = LatticeParIter<'a, D, T>; - type Item = ::Item; - - #[inline] - fn into_par_iter(self) -> Self::Iter { - self.par_iter() - } -} - -//--------------------------------------- -// LatticeProducer - -/// [`Producer`] for the [`IndexedParallelIterator`] [`LatticeParIter`] based on -/// the [`DoubleEndedIterator`] [`LatticeIterator`]. -#[repr(transparent)] -#[derive(Debug, Clone, PartialEq)] -struct LatticeProducer<'a, const D: usize, T>(LatticeIterator<'a, D, T>); - -impl<'a, const D: usize, T> LatticeProducer<'a, D, T> { - /// Convert self into a [`LatticeIterator`] - #[inline] - #[must_use] - fn into_iterator(self) -> LatticeIterator<'a, D, T> { - self.0 - } - - /// Convert as a reference of [`LatticeIterator`] - #[inline] - #[must_use] - const fn as_iter(&self) -> &LatticeIterator<'a, D, T> { - &self.0 - } - - /// Convert as a mutable reference of [`LatticeIterator`] - #[inline] - #[must_use] - fn as_iter_mut(&mut self) -> &mut LatticeIterator<'a, D, T> { - &mut self.0 - } -} - -impl<'a, const D: usize, T> From> for LatticeProducer<'a, D, T> { - #[inline] - fn from(value: LatticeIterator<'a, D, T>) -> Self { - Self(value) - } -} - -impl<'a, const D: usize, T> From> for LatticeProducer<'a, D, T> { - #[inline] - fn from(value: LatticeParIter<'a, D, T>) -> Self { - Self(LatticeIterator::from(value)) - } -} - -impl<'a, const D: usize, T> Producer for LatticeProducer<'a, D, T> -where - LatticeIterator<'a, D, T>: RandomAccessIterator, - T: Clone + Send, -{ - type Item = ::Item; - type IntoIter = LatticeIterator<'a, D, T>; - - #[inline] - fn into_iter(self) -> Self::IntoIter { - self.into_iterator() - } - - #[inline] - fn split_at(self, index: usize) -> (Self, Self) { - let splinting = self.as_iter().increase_front_element_by(index); - ( - Self(Self::IntoIter { - lattice: self.0.lattice, - counter: DoubleEndedCounter { - front: self.0.counter.front, - end: splinting.clone(), - }, - }), - Self(Self::IntoIter { - lattice: self.0.lattice, - counter: DoubleEndedCounter { - front: splinting, - end: self.0.counter.end, - }, - }), - ) - } -} - -impl<'a, const D: usize, T> AsRef> for LatticeProducer<'a, D, T> { - #[inline] - fn as_ref(&self) -> &LatticeIterator<'a, D, T> { - self.as_iter() - } -} - -impl<'a, const D: usize, T> AsMut> for LatticeProducer<'a, D, T> { - #[inline] - fn as_mut(&mut self) -> &mut LatticeIterator<'a, D, T> { - self.as_iter_mut() - } -} - -impl<'a, const D: usize, T> IntoIterator for LatticeProducer<'a, D, T> -where - LatticeIterator<'a, D, T>: RandomAccessIterator, - T: Clone, -{ - type Item = ::Item; - type IntoIter = LatticeIterator<'a, D, T>; - - #[inline] - fn into_iter(self) -> Self::IntoIter { - self.into_iterator() - } -} - -//--------------------------------------- -// LatticeParIter - -/// [`rayon::iter::ParallelIterator`] and [`rayon::iter::IndexedParallelIterator`] -/// over a lattice. It is only used -/// for `T` = [`crate::lattice::LatticePoint`] (see [`ParIterLatticePoint`]) and -/// for `T` = [`crate::lattice::LatticeLinkCanonical`] (see [`ParIterLatticeLinkCanonical`]). -/// (Public) constructors only exist for these possibilities using [`LatticeIterator::par_iter`]. -/// -/// It has a transparent representation containing a single field [`LatticeIterator`] allowing -/// transmutation between the two. Though other crate should not rely on this representation. -/// TODO more doc -#[repr(transparent)] -#[derive(Debug, Clone, PartialEq)] -pub struct LatticeParIter<'a, const D: usize, T>(LatticeIterator<'a, D, T>); - -impl<'a, const D: usize, T> LatticeParIter<'a, D, T> { - // where - //LatticeIterator<'a, D, T>: RandomAccessIterator, - //T: Clone + Send, - - /// create a new self with `iter` as the wrapped value - const fn new(iter: LatticeIterator<'a, D, T>) -> Self { - Self(iter) - } - - /// Convert the parallel iterator into an [`Iterator`] - #[must_use] - #[inline] - pub fn into_iterator(self) -> LatticeIterator<'a, D, T> { - self.0 - } - - /// Take a reference of self and return a reference to an [`Iterator`]. - /// This might not be very useful look instead at [`Self::as_iter_mut`] - #[must_use] - #[inline] - pub const fn as_iter(&self) -> &LatticeIterator<'a, D, T> { - &self.0 - } - - /// Take a mutable reference of self and return a mutable reference to an [`Iterator`]. - #[must_use] - #[inline] - pub fn as_iter_mut(&mut self) -> &mut LatticeIterator<'a, D, T> { - &mut self.0 - } -} - -impl<'a, const D: usize, T> ParallelIterator for LatticeParIter<'a, D, T> -where - LatticeIterator<'a, D, T>: RandomAccessIterator, - T: Clone + Send, -{ - type Item = T; - - #[inline] - fn drive_unindexed(self, consumer: C) -> C::Result - where - C: UnindexedConsumer, - { - bridge(self, consumer) - } - - #[inline] - fn opt_len(&self) -> Option { - Some(self.as_ref().iter_len()) - } - - #[inline] - fn count(self) -> usize - where - Self: Sized, - { - self.as_ref().iter_len() - } - - #[inline] - fn max(self) -> Option - where - Self: Sized, - Self::Item: Ord, - { - as Iterator>::max(self.into()) - } - - #[inline] - fn min(self) -> Option - where - Self: Sized, - Self::Item: Ord, - { - as Iterator>::min(self.into()) - } -} - -impl<'a, const D: usize, T> IndexedParallelIterator for LatticeParIter<'a, D, T> -where - LatticeIterator<'a, D, T>: RandomAccessIterator, - T: Clone + Send, -{ - #[inline] - fn len(&self) -> usize { - self.as_ref().iter_len() - } - - #[inline] - fn drive>(self, consumer: C) -> C::Result { - bridge(self, consumer) - } - - #[inline] - fn with_producer>(self, callback: CB) -> CB::Output { - callback.callback(LatticeProducer::from(self)) - } -} - -impl<'a, const D: usize, T> From> for LatticeParIter<'a, D, T> { - #[inline] - fn from(value: LatticeIterator<'a, D, T>) -> Self { - Self::new(value) - } -} - -impl<'a, const D: usize, T> From> for LatticeParIter<'a, D, T> { - #[inline] - fn from(value: LatticeProducer<'a, D, T>) -> Self { - Self(LatticeIterator::from(value)) - } -} - -impl<'a, const D: usize, T> AsRef> for LatticeParIter<'a, D, T> { - #[inline] - fn as_ref(&self) -> &LatticeIterator<'a, D, T> { - self.as_iter() - } -} - -impl<'a, const D: usize, T> AsMut> for LatticeParIter<'a, D, T> { - #[inline] - fn as_mut(&mut self) -> &mut LatticeIterator<'a, D, T> { - self.as_iter_mut() - } -} - -impl<'a, const D: usize, T> AsRef> for LatticeIterator<'a, D, T> { - #[inline] - fn as_ref(&self) -> &LatticeParIter<'a, D, T> { - self.as_par_iter() - } -} - -impl<'a, const D: usize, T> AsMut> for LatticeIterator<'a, D, T> { - #[inline] - fn as_mut(&mut self) -> &mut LatticeParIter<'a, D, T> { - self.as_par_iter_mut() - } -} - -impl<'a, const D: usize, T> IntoIterator for LatticeParIter<'a, D, T> -where - LatticeIterator<'a, D, T>: RandomAccessIterator, - T: Clone, -{ - type Item = ::Item; - type IntoIter = LatticeIterator<'a, D, T>; - - #[inline] - fn into_iter(self) -> Self::IntoIter { - self.into_iterator() - } -} - #[cfg(test)] mod test { use std::error::Error; diff --git a/src/lattice/iterator/parallel_iterator.rs b/src/lattice/iterator/parallel_iterator.rs new file mode 100644 index 00000000..77d049b1 --- /dev/null +++ b/src/lattice/iterator/parallel_iterator.rs @@ -0,0 +1,179 @@ +//--------------------------------------- +// LatticeParIter + +use rayon::iter::{ + plumbing::{bridge, Consumer, ProducerCallback, UnindexedConsumer}, + IndexedParallelIterator, ParallelIterator, +}; + +use super::{producer::LatticeProducer, LatticeIterator, RandomAccessIterator}; + +/// [`rayon::iter::ParallelIterator`] and [`rayon::iter::IndexedParallelIterator`] +/// over a lattice. It is only used +/// for `T` = [`crate::lattice::LatticePoint`] (see [`super::ParIterLatticePoint`]) and +/// for `T` = [`crate::lattice::LatticeLinkCanonical`] (see [`super::ParIterLatticeLinkCanonical`]). +/// (Public) constructors only exist for these possibilities using [`LatticeIterator::par_iter`]. +/// +/// It has a transparent representation containing a single field [`LatticeIterator`] allowing +/// transmutation between the two. Though other crate should not rely on this representation. +/// TODO more doc +#[repr(transparent)] +#[derive(Debug, Clone, PartialEq)] +pub struct ParIter<'a, const D: usize, T>(LatticeIterator<'a, D, T>); + +impl<'a, const D: usize, T> ParIter<'a, D, T> { + // where + //LatticeIterator<'a, D, T>: RandomAccessIterator, + //T: Clone + Send, + + /// create a new self with `iter` as the wrapped value + pub(super) const fn new(iter: LatticeIterator<'a, D, T>) -> Self { + Self(iter) + } + + /// Convert the parallel iterator into an [`Iterator`] + #[must_use] + #[inline] + pub fn into_iterator(self) -> LatticeIterator<'a, D, T> { + self.0 + } + + /// Take a reference of self and return a reference to an [`Iterator`]. + /// This might not be very useful look instead at [`Self::as_iter_mut`] + #[must_use] + #[inline] + pub const fn as_iter(&self) -> &LatticeIterator<'a, D, T> { + &self.0 + } + + /// Take a mutable reference of self and return a mutable reference to an [`Iterator`]. + #[must_use] + #[inline] + pub fn as_iter_mut(&mut self) -> &mut LatticeIterator<'a, D, T> { + &mut self.0 + } +} + +impl<'a, const D: usize, T> ParallelIterator for ParIter<'a, D, T> +where + LatticeIterator<'a, D, T>: RandomAccessIterator, + T: Clone + Send, +{ + type Item = T; + + #[inline] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + bridge(self, consumer) + } + + #[inline] + fn opt_len(&self) -> Option { + Some(self.as_ref().iter_len()) + } + + #[inline] + fn count(self) -> usize + where + Self: Sized, + { + self.as_ref().iter_len() + } + + #[inline] + fn max(self) -> Option + where + Self: Sized, + Self::Item: Ord, + { + as Iterator>::max(self.into()) + } + + #[inline] + fn min(self) -> Option + where + Self: Sized, + Self::Item: Ord, + { + as Iterator>::min(self.into()) + } +} + +impl<'a, const D: usize, T> IndexedParallelIterator for ParIter<'a, D, T> +where + LatticeIterator<'a, D, T>: RandomAccessIterator, + T: Clone + Send, +{ + #[inline] + fn len(&self) -> usize { + self.as_ref().iter_len() + } + + #[inline] + fn drive>(self, consumer: C) -> C::Result { + bridge(self, consumer) + } + + #[inline] + fn with_producer>(self, callback: CB) -> CB::Output { + callback.callback(LatticeProducer::from(self)) + } +} + +impl<'a, const D: usize, T> From> for ParIter<'a, D, T> { + #[inline] + fn from(value: LatticeIterator<'a, D, T>) -> Self { + Self::new(value) + } +} + +impl<'a, const D: usize, T> From> for ParIter<'a, D, T> { + #[inline] + fn from(value: LatticeProducer<'a, D, T>) -> Self { + Self(LatticeIterator::from(value)) + } +} + +impl<'a, const D: usize, T> AsRef> for ParIter<'a, D, T> { + #[inline] + fn as_ref(&self) -> &LatticeIterator<'a, D, T> { + self.as_iter() + } +} + +impl<'a, const D: usize, T> AsMut> for ParIter<'a, D, T> { + #[inline] + fn as_mut(&mut self) -> &mut LatticeIterator<'a, D, T> { + self.as_iter_mut() + } +} + +impl<'a, const D: usize, T> AsRef> for LatticeIterator<'a, D, T> { + #[inline] + fn as_ref(&self) -> &ParIter<'a, D, T> { + self.as_par_iter() + } +} + +impl<'a, const D: usize, T> AsMut> for LatticeIterator<'a, D, T> { + #[inline] + fn as_mut(&mut self) -> &mut ParIter<'a, D, T> { + self.as_par_iter_mut() + } +} + +impl<'a, const D: usize, T> IntoIterator for ParIter<'a, D, T> +where + LatticeIterator<'a, D, T>: RandomAccessIterator, + T: Clone, +{ + type Item = ::Item; + type IntoIter = LatticeIterator<'a, D, T>; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + self.into_iterator() + } +} diff --git a/src/lattice/iterator/point.rs b/src/lattice/iterator/point.rs index 17340983..0d76a0e1 100644 --- a/src/lattice/iterator/point.rs +++ b/src/lattice/iterator/point.rs @@ -2,7 +2,7 @@ //! # Example // TODO -use super::{super::LatticePoint, LatticeIterator, LatticeParIter}; +use super::{super::LatticePoint, LatticeIterator, ParIter}; /// Iterator over [`LatticePoint`] /// # Example @@ -10,7 +10,7 @@ pub type IteratorLatticePoint<'a, const D: usize> = LatticeIterator<'a, D, Latti /// Parallel iterator over [`LatticePoint`] /// # Example -pub type ParIterLatticePoint<'a, const D: usize> = LatticeParIter<'a, D, LatticePoint>; +pub type ParIterLatticePoint<'a, const D: usize> = ParIter<'a, D, LatticePoint>; #[cfg(test)] mod test { diff --git a/src/lattice/iterator/producer.rs b/src/lattice/iterator/producer.rs new file mode 100644 index 00000000..191d20d4 --- /dev/null +++ b/src/lattice/iterator/producer.rs @@ -0,0 +1,116 @@ +//--------------------------------------- +// LatticeProducer + +use rayon::iter::plumbing::Producer; + +use super::{DoubleEndedCounter, LatticeIterator, ParIter, RandomAccessIterator}; + +/// [`Producer`] for the [`rayon::iter::IndexedParallelIterator`] [`super::ParIter`] based on +/// the [`DoubleEndedIterator`] [`LatticeIterator`]. +#[repr(transparent)] +#[derive(Debug, Clone, PartialEq)] +pub struct LatticeProducer<'a, const D: usize, T>(LatticeIterator<'a, D, T>); + +impl<'a, const D: usize, T> LatticeProducer<'a, D, T> { + /// Convert self into a [`LatticeIterator`] + #[inline] + #[must_use] + fn into_iterator(self) -> LatticeIterator<'a, D, T> { + self.0 + } + + /// Convert as a reference of [`LatticeIterator`] + #[inline] + #[must_use] + const fn as_iter(&self) -> &LatticeIterator<'a, D, T> { + &self.0 + } + + /// Convert as a mutable reference of [`LatticeIterator`] + #[inline] + #[must_use] + fn as_iter_mut(&mut self) -> &mut LatticeIterator<'a, D, T> { + &mut self.0 + } +} + +impl<'a, const D: usize, T> From> for LatticeProducer<'a, D, T> { + #[inline] + fn from(value: LatticeIterator<'a, D, T>) -> Self { + Self(value) + } +} + +impl<'a, const D: usize, T> From> for LatticeProducer<'a, D, T> { + #[inline] + fn from(value: ParIter<'a, D, T>) -> Self { + Self(LatticeIterator::from(value)) + } +} + +impl<'a, const D: usize, T> Producer for LatticeProducer<'a, D, T> +where + LatticeIterator<'a, D, T>: RandomAccessIterator, + T: Clone + Send, +{ + type Item = ::Item; + type IntoIter = LatticeIterator<'a, D, T>; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + self.into_iterator() + } + + #[inline] + fn split_at(self, index: usize) -> (Self, Self) { + let splinting = self.as_iter().increase_front_element_by(index); + ( + Self(Self::IntoIter { + lattice: self.0.lattice, + counter: DoubleEndedCounter::new_with_front_end( + self.0.counter.front, + splinting.clone(), + ), + }), + Self(Self::IntoIter { + lattice: self.0.lattice, + counter: DoubleEndedCounter::new_with_front_end(splinting, self.0.counter.end), + }), + ) + } +} + +impl<'a, const D: usize, T> AsRef> for LatticeProducer<'a, D, T> { + #[inline] + fn as_ref(&self) -> &LatticeIterator<'a, D, T> { + self.as_iter() + } +} + +impl<'a, const D: usize, T> AsMut> for LatticeProducer<'a, D, T> { + #[inline] + fn as_mut(&mut self) -> &mut LatticeIterator<'a, D, T> { + self.as_iter_mut() + } +} + +impl<'a, const D: usize, T> IntoIterator for LatticeProducer<'a, D, T> +where + LatticeIterator<'a, D, T>: RandomAccessIterator, + T: Clone, +{ + type Item = ::Item; + type IntoIter = LatticeIterator<'a, D, T>; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + self.into_iterator() + } +} + +impl<'a, const D: usize, T> From> for LatticeIterator<'a, D, T> { + #[inline] + fn from(value: LatticeProducer<'a, D, T>) -> Self { + value.into_iterator() + } +} diff --git a/src/lattice/mod.rs b/src/lattice/mod.rs index 653d70c8..a6dbc870 100644 --- a/src/lattice/mod.rs +++ b/src/lattice/mod.rs @@ -29,7 +29,7 @@ pub use self::direction::{ // TODO remove IteratorElement from public interface ? pub use self::iterator::{ IteratorDirection, IteratorElement, IteratorLatticeLinkCanonical, IteratorLatticePoint, - LatticeIterator, LatticeParIter, ParIterLatticeLinkCanonical, ParIterLatticePoint, + LatticeIterator, ParIter, ParIterLatticeLinkCanonical, ParIterLatticePoint, }; pub use self::lattice_cyclic::LatticeCyclic; use crate::private::Sealed; @@ -729,10 +729,10 @@ mod test { assert_eq!(Direction::<4>::positive_directions().len(), 4); let l = LatticeCyclic::new(1_f64, 4).expect("lattice has an error"); - for dir in Direction::<3>::directions() { + for (index, dir) in Direction::<3>::directions().iter().enumerate() { assert_eq!( as LatticeElementToIndex<3>>::to_index(dir, &l), - dir.index() + index ); } diff --git a/src/lib.rs b/src/lib.rs index a3b5555b..48eddfb0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -121,7 +121,7 @@ //--------------------------------------- // doc lints #![warn(missing_docs)] // doc -// #![warn(clippy::missing_docs_in_private_items)] // doc +#![warn(clippy::missing_docs_in_private_items)] // doc #![deny(rustdoc::broken_intra_doc_links)] // cspell: ignore rustdoc #![deny(rustdoc::private_intra_doc_links)] #![deny(rustdoc::invalid_codeblock_attributes)] @@ -175,6 +175,10 @@ use utils_lib::trait_sealed; //--------------------------------------- // trait + +// doc for sealed trait +// This trait is a super trait of [`Sealed`] which is private meaning that It can't be +// implemented outside of this trait. trait_sealed!(); //---------------------------------------