Skip to content

Commit

Permalink
move iterator into separate module
Browse files Browse the repository at this point in the history
  • Loading branch information
ABouttefeux committed Jan 6, 2024
1 parent e8adb9b commit b292374
Show file tree
Hide file tree
Showing 15 changed files with 1,494 additions and 1,202 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ approx = "0.5.1"
num-traits = "0.2.17"
rand = "0.8.5"
rand_distr = "0.4.3"
crossbeam = "0.8.2"
crossbeam = "0.8.3"
rayon = "1.8"
serde = { version = "1.0", features = ["derive"], optional = true }
lattice_qcd_rs-procedural_macro = { path = "procedural_macro", version = "0.3.0" }
Expand Down
6 changes: 4 additions & 2 deletions makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion src/lattice/direction/direction_enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

//---------------------------------------
Expand Down
35 changes: 18 additions & 17 deletions src/lattice/direction/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,21 +285,6 @@ impl<const D: usize> Display for Direction<D> {
}
}

// /// TODO impl doc
// impl<const D: usize> NumberOfLatticeElement<D> for Direction<D> {
// #[inline]
// fn number_of_elements(_lattice: &LatticeCyclic<D>) -> usize {
// D
// }
// }

// // TODO impl doc
// impl<const D: usize> IndexToElement<D> for Direction<D> {
// fn index_to_element(_lattice: &LatticeCyclic<D>, index: usize) -> Option<Self> {
// 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.
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -590,12 +591,12 @@ impl<const D: usize> DirectionTrait for Direction<D> {}
impl<const D: usize> DirectionIndexing for Direction<D> {
#[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> {
Self::new((index.saturating_sub(1)) / 2, index % 2 == 1)
Self::new((index.saturating_sub(1)) / 2, index % 2 == 0)
}

#[inline]
Expand Down
3 changes: 1 addition & 2 deletions src/lattice/iterator/direction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
279 changes: 279 additions & 0 deletions src/lattice/iterator/double_ended_counter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,279 @@
//! 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, Split};
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, Hash, PartialOrd, Ord)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[derive(Getter)]
pub struct DoubleEndedCounter<T> {
/// 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<T>,
/// 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<T>,
}

impl<T> DoubleEndedCounter<T> {
/// 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<T>,
end: IteratorElement<T>,
) -> Self {
Self { front, end }
}

// possible with_first, with_last
}

//---------------------------------------
// common traits

/// It is [`Self::new`],
impl<T> Default for DoubleEndedCounter<T> {
#[inline]
fn default() -> Self {
Self::new()
}
}

impl<T: Display> Display for DoubleEndedCounter<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "front: {}, end: {}", self.front(), self.end())
}
}

//---------------------------------------
// conversion

impl<T> From<DoubleEndedCounter<T>> for [IteratorElement<T>; 2] {
#[inline]
fn from(value: DoubleEndedCounter<T>) -> Self {
[value.front, value.end]
}
}

impl<T> From<DoubleEndedCounter<T>> for (IteratorElement<T>, IteratorElement<T>) {
#[inline]
fn from(value: DoubleEndedCounter<T>) -> Self {
(value.front, value.end)
}
}

//---------------------------------------
// impl of RandomAccessIterator

impl<D: DirectionIndexing> RandomAccessIterator for DoubleEndedCounter<D> {
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<Self::Item> {
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<Self::Item> {
let index = match self.end() {
IteratorElement::FirstElement => {
// early return
return IteratorElement::FirstElement;
}
IteratorElement::Element(ref element) => element.direction_to_index() + 1,
IteratorElement::LastElement => Self::Item::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<I> Split for DoubleEndedCounter<I>
where
Self: RandomAccessIterator<Item = I>,
I: Clone,
{
#[inline]
fn split_at(self, index: usize) -> (Self, Self) {
let splinting = self.increase_front_element_by(index);
(
Self::new_with_front_end(self.front, splinting.clone()),
Self::new_with_front_end(splinting, self.end),
)
}
}

//---------------------------------------
// impl of Iterator traits

/// TODO DOC
impl<T> Iterator for DoubleEndedCounter<T>
where
Self: RandomAccessIterator<Item = T>,
T: Clone,
{
type Item = T;

#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.nth(0)
}

#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
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<Self::Item>
where
Self: Sized,
{
self.nth(self.iter_len().saturating_sub(1))
}

#[inline]
fn nth(&mut self, n: usize) -> Option<Self::Item> {
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.clone();
next_element.into()
}

#[inline]
fn max(self) -> Option<Self::Item>
where
Self: Sized,
Self::Item: Ord,
{
self.last()
}

#[inline]
fn min(mut self) -> Option<Self::Item>
where
Self: Sized,
Self::Item: Ord,
{
self.next()
}
}

/// TODO DOC
impl<T> DoubleEndedIterator for DoubleEndedCounter<T>
where
Self: RandomAccessIterator<Item = T>,
T: Clone,
{
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
self.nth_back(0)
}

#[inline]
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
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.clone();
previous_element.into()
}
}

impl<T> FusedIterator for DoubleEndedCounter<T> where Self: RandomAccessIterator + Iterator {}

impl<T> ExactSizeIterator for DoubleEndedCounter<T>
where
Self: RandomAccessIterator + Iterator,
{
#[inline]
fn len(&self) -> usize {
self.iter_len()
}
}
Loading

0 comments on commit b292374

Please sign in to comment.