diff --git a/src/lib.rs b/src/lib.rs index 1c9bfeaa..71ec5284 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -65,5 +65,7 @@ pub mod euclid; pub mod function; pub mod generate; pub mod prec; +pub mod sorted_collection; +pub mod sorted_iterator; pub mod statistics; pub mod stats_tests; diff --git a/src/sorted_collection.rs b/src/sorted_collection.rs new file mode 100644 index 00000000..4cae1b0a --- /dev/null +++ b/src/sorted_collection.rs @@ -0,0 +1,76 @@ +use std::cmp::Ordering; + +pub enum SortError { + NotSorted, +} + +#[derive(Clone, Debug)] +pub enum Collection<'a, T> { + Ref(&'a [T]), + Owned(Vec), +} + +#[derive(Clone, Debug)] +pub struct SortedCollection<'a, T> { + sorted: Collection<'a, T>, +} + +impl<'a, T> SortedCollection<'a, T> +where + T: Ord, +{ + pub fn from_slice(coll: &'a [T]) -> Result { + match coll + .windows(2) + .all(|sl| sl[0].cmp(&sl[1]) == Ordering::Less) + { + true => Ok(Self { + sorted: Collection::Ref(coll), + }), + false => Err(SortError::NotSorted), + } + } + pub fn from_mut_vec(mut coll: Vec) -> Self { + coll.sort(); + Self { + sorted: Collection::Owned(coll), + } + } + pub fn iter(&'a self) -> std::slice::Iter<'a, T> { + match self.sorted { + Collection::Ref(items) => items.iter(), + Collection::Owned(ref items) => items.iter(), + } + } +} + +impl<'a, T> TryFrom<&'a [T]> for SortedCollection<'a, T> +where + T: Ord, +{ + type Error = SortError; + + fn try_from(value: &'a [T]) -> Result { + Self::from_slice(value) + } +} + +impl<'a, T> TryFrom<&'a Box<[T]>> for SortedCollection<'a, T> +where + T: Ord, +{ + type Error = SortError; + + fn try_from(value: &'a Box<[T]>) -> Result { + Self::from_slice(value.as_ref()) + } +} + +impl<'a, T> AsRef<[T]> for SortedCollection<'a, T> { + fn as_ref(&self) -> &[T] { + match self.sorted { + Collection::Ref(items) => items, + Collection::Owned(ref items) => items.as_ref(), + } + } +} diff --git a/src/sorted_iterator.rs b/src/sorted_iterator.rs new file mode 100644 index 00000000..6c02270f --- /dev/null +++ b/src/sorted_iterator.rs @@ -0,0 +1,38 @@ +use std::marker::PhantomData; + +use crate::stats_tests::NaNPolicy; + +pub trait SortedIterator { + fn sorted_iter(&self, policy: NaNPolicy) -> Sorted; +} + +impl SortedIterator for Vec { + fn sorted_iter(&self, policy: NaNPolicy) -> Sorted { + Sorted::new(self, policy) + } +} + +/// TODO iron out implementation details later because this is not optimal retrieval of sorted data +pub struct Sorted { + sorted_iter: std::vec::IntoIter, + policy: NaNPolicy, +} + +impl Sorted { + pub fn new(data: &[f64], policy: NaNPolicy) -> Self { + let mut cloned = Vec::from(data); + cloned.sort_by(|a, b| a.total_cmp(b)); + Self { + sorted_iter: cloned.into_iter(), + policy, + } + } +} + +impl Iterator for Sorted { + type Item = f64; + + fn next(&mut self) -> Option { + self.sorted_iter.next() + } +}