Skip to main content

hpo/
utils.rs

1//! Utility structs and methods
2use std::cmp::Ordering::{Equal, Less};
3
4/// Iterator of all one-way pairwise combinations of the inner slice
5///
6/// # Examples
7/// ```no_run
8/// use hpo::utils::Combinations;
9///
10/// let mut c: Combinations<usize> = todo!(); // [1, 2, 3]
11///
12/// assert_eq!(c.next(), Some((&1, &2)));
13/// assert_eq!(c.next(), Some((&1, &3)));
14/// assert_eq!(c.next(), Some((&2, &3)));
15/// assert!(c.next().is_none());
16/// ```
17pub struct Combinations<'a, T> {
18    inner: &'a [Option<T>],
19    idx1: usize,
20    idx2: usize,
21}
22
23impl<'a, T> Combinations<'a, T> {
24    /// Creates a new Combinations iterator
25    pub(crate) fn new(inner: &'a [Option<T>]) -> Self {
26        Self {
27            inner,
28            idx1: 0,
29            idx2: 1,
30        }
31    }
32
33    pub(crate) fn set_to_last(&mut self) {
34        self.idx1 = self.inner.len() - 1;
35        self.idx2 = 0;
36    }
37}
38
39impl<'a, T> Iterator for Combinations<'a, T> {
40    type Item = (&'a T, &'a T);
41    fn next(&mut self) -> Option<Self::Item> {
42        match (
43            self.idx1 < self.inner.len(),
44            self.idx2.cmp(&self.inner.len()),
45        ) {
46            (true, Less) => {
47                self.idx2 += 1;
48                if self.inner[self.idx1].is_none() {
49                    return self.next();
50                }
51                if self.inner[self.idx2 - 1].is_none() {
52                    return self.next();
53                }
54                Some((
55                    self.inner[self.idx1]
56                        .as_ref()
57                        .expect("`None` values are skipped"),
58                    self.inner[self.idx2 - 1]
59                        .as_ref()
60                        .expect("`None` values are skipped"),
61                ))
62            }
63            (true, Equal) => {
64                self.idx1 += 1;
65                self.idx2 = self.idx1 + 1;
66                self.next()
67            }
68            _ => None,
69        }
70    }
71}
72
73#[cfg(test)]
74mod test {
75    use super::*;
76
77    #[test]
78    fn combinations() {
79        let a = vec![Some(1), Some(2), Some(3), Some(4)];
80        let mut c = Combinations::new(&a);
81        assert_eq!(c.next(), Some((&1, &2)));
82        assert_eq!(c.next(), Some((&1, &3)));
83        assert_eq!(c.next(), Some((&1, &4)));
84        assert_eq!(c.next(), Some((&2, &3)));
85        assert_eq!(c.next(), Some((&2, &4)));
86        assert_eq!(c.next(), Some((&3, &4)));
87        assert_eq!(c.next(), None);
88    }
89
90    #[test]
91    fn combinations_empty() {
92        let a: Vec<Option<usize>> = vec![];
93        let mut c = Combinations::new(&a);
94        assert_eq!(c.next(), None);
95    }
96
97    #[test]
98    fn combinations_single() {
99        let a = vec![Some(1)];
100        let mut c = Combinations::new(&a);
101        assert_eq!(c.next(), None);
102    }
103
104    #[test]
105    fn combinations_two() {
106        let a = vec![Some(1), Some(2)];
107        let mut c = Combinations::new(&a);
108        assert_eq!(c.next(), Some((&1, &2)));
109        assert_eq!(c.next(), None);
110    }
111
112    #[test]
113    fn last_row() {
114        let a = vec![Some(1), Some(2), Some(3), Some(4)];
115        let mut c = Combinations::new(&a);
116        c.set_to_last();
117        assert_eq!(c.next(), Some((&4, &1)));
118        assert_eq!(c.next(), Some((&4, &2)));
119        assert_eq!(c.next(), Some((&4, &3)));
120        assert_eq!(c.next(), Some((&4, &4)));
121        assert_eq!(c.next(), None);
122    }
123
124    #[test]
125    fn combinations_with_none() {
126        let a = vec![Some(1), Some(2), None, Some(4)];
127        let mut c = Combinations::new(&a);
128        assert_eq!(c.next(), Some((&1, &2)));
129        assert_eq!(c.next(), Some((&1, &4)));
130        assert_eq!(c.next(), Some((&2, &4)));
131        assert_eq!(c.next(), None);
132    }
133}