1use crate::make_array;
2use alloc::vec::Vec;
3use core::iter::{FusedIterator, Iterator};
4
5#[derive(Clone)]
6pub struct LazyCombinationGenerator<const K: usize> {
7 indices: [usize; K],
8 done: bool,
9}
10
11impl<const K: usize> LazyCombinationGenerator<K> {
12 pub fn new() -> Self {
13 Self {
14 indices: make_array(|i| i),
15 done: false,
16 }
17 }
18
19 pub fn max_index(&self) -> Option<usize> {
20 self.indices.last().copied()
21 }
22
23 pub fn is_done(&self, item_count: usize) -> bool {
24 self.done || self.max_index() >= Some(item_count)
25 }
26
27 pub fn indices(&self) -> &[usize; K] {
28 &self.indices
29 }
30
31 pub fn step(&mut self) {
32 if K == 0 {
33 self.done = true;
34 } else {
35 let mut i = 0;
36 while i + 1 < K && self.indices[i] + 1 == self.indices[i + 1] {
38 self.indices[i] = i;
39 i += 1;
40 }
41 self.indices[i] += 1;
43 }
44 }
45}
46
47#[derive(Clone)]
48struct State<const K: usize> {
49 gen: LazyCombinationGenerator<K>,
50}
51
52impl<const K: usize> State<K> {
53 fn new() -> Self {
54 Self {
55 gen: LazyCombinationGenerator::new(),
56 }
57 }
58
59 fn max_index(&self) -> Option<usize> {
60 self.gen.max_index()
61 }
62
63 fn get_and_step<'a, T, O, F>(&mut self, items: &'a [T], f: F) -> Option<[O; K]>
64 where
65 F: Fn(&'a T) -> O,
66 O: 'a,
67 {
68 if self.gen.is_done(items.len()) {
69 None
70 } else {
71 let indices = self.gen.indices();
72 let res = make_array(|i| f(&items[indices[i]]));
73 self.gen.step();
74 Some(res)
75 }
76 }
77}
78
79#[derive(Clone)]
87#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
88pub struct Combinations<I, const K: usize>
89where
90 I: Iterator,
91{
92 iter: I,
93 items: Vec<I::Item>,
94 state: State<K>,
95}
96
97impl<I, const K: usize> Combinations<I, K>
98where
99 I: Iterator,
100{
101 pub(crate) fn new(iter: I) -> Self {
102 Self {
103 iter,
104 items: Vec::new(),
105 state: State::new(),
106 }
107 }
108}
109
110impl<I, const K: usize> Iterator for Combinations<I, K>
111where
112 I: Iterator,
113 I::Item: Clone,
114{
115 type Item = [I::Item; K];
116
117 fn next(&mut self) -> Option<[I::Item; K]> {
118 if K > 0 {
119 let max_index = self.state.max_index().unwrap();
120 let missing_count = (max_index + 1).saturating_sub(self.items.len());
121 if missing_count > 0 {
122 self.items.extend(self.iter.by_ref().take(missing_count));
124 }
125 }
126 self.state.get_and_step(&self.items, |t| t.clone())
127 }
128}
129
130impl<I, const K: usize> FusedIterator for Combinations<I, K>
131where
132 I: FusedIterator,
133 I::Item: Clone,
134{
135}
136
137#[derive(Clone)]
139#[must_use = "iterator does nothing unless consumed"]
140pub struct SliceCombinations<'a, T, const K: usize> {
141 items: &'a [T],
142 state: State<K>,
143}
144
145impl<'a, T, const K: usize> SliceCombinations<'a, T, K> {
146 pub(crate) fn new(items: &'a [T]) -> Self {
147 Self {
148 items,
149 state: State::new(),
150 }
151 }
152}
153
154impl<'a, T, const K: usize> Iterator for SliceCombinations<'a, T, K> {
155 type Item = [&'a T; K];
156
157 fn next(&mut self) -> Option<[&'a T; K]> {
158 self.state.get_and_step(self.items, |t| t)
159 }
160}
161
162impl<T, const K: usize> FusedIterator for SliceCombinations<'_, T, K> {}
163
164#[cfg(test)]
165mod test {
166 use super::*;
167 use crate::IterExt;
168 use core::sync::atomic::{AtomicUsize, Ordering};
169
170 #[test]
171 fn order() {
172 let mut combinations = (1..6).combinations();
173 assert_eq!(combinations.next(), Some([1, 2, 3]));
174 assert_eq!(combinations.next(), Some([1, 2, 4]));
175 assert_eq!(combinations.next(), Some([1, 3, 4]));
176 assert_eq!(combinations.next(), Some([2, 3, 4]));
177 assert_eq!(combinations.next(), Some([1, 2, 5]));
178 assert_eq!(combinations.next(), Some([1, 3, 5]));
179 assert_eq!(combinations.next(), Some([2, 3, 5]));
180 assert_eq!(combinations.next(), Some([1, 4, 5]));
181 assert_eq!(combinations.next(), Some([2, 4, 5]));
182 assert_eq!(combinations.next(), Some([3, 4, 5]));
183 assert_eq!(combinations.next(), None);
184 assert_eq!(combinations.next(), None);
185 }
186
187 #[test]
188 fn none_on_size_too_big() {
189 let mut combinations = (1..2).combinations::<2>();
190 assert_eq!(combinations.next(), None);
191 assert_eq!(combinations.next(), None);
192 }
193
194 #[test]
195 fn empty_arr_on_n_zero() {
196 let mut combinations = (1..5).combinations();
197 assert_eq!(combinations.next(), Some([]));
198 assert_eq!(combinations.next(), None);
199 assert_eq!(combinations.next(), None);
200 }
201
202 #[test]
203 fn fused_propagation() {
204 let fused = [1, 2, 3].iter().fuse();
205 let combinations = fused.combinations::<2>();
206
207 fn is_fused<T: FusedIterator>(_: T) {}
208 is_fused(combinations);
209 }
210
211 #[test]
212 fn resume_after_none() {
213 struct ResumeIter<'l, 'a, T>
214 where
215 T: Copy,
216 {
217 items: &'a [T],
218 i: usize,
219 len: &'l AtomicUsize,
220 }
221
222 impl<T> Iterator for ResumeIter<'_, '_, T>
223 where
224 T: Copy,
225 {
226 type Item = T;
227 fn next(&mut self) -> Option<T> {
228 if self.i >= self.len.load(Ordering::SeqCst) {
229 None
230 } else {
231 self.i += 1;
232 Some(self.items[self.i - 1])
233 }
234 }
235 }
236
237 let len = AtomicUsize::new(0);
238 let mut combinations = ResumeIter {
239 items: &[1, 2, 3, 4],
240 len: &len,
241 i: 0,
242 }
243 .combinations();
244
245 assert_eq!(combinations.next(), None);
246
247 len.fetch_add(1, Ordering::SeqCst);
248 assert_eq!(combinations.next(), None);
249
250 len.fetch_add(1, Ordering::SeqCst);
251 assert_eq!(combinations.next(), None);
252
253 len.fetch_add(1, Ordering::SeqCst);
254 assert_eq!(combinations.next(), Some([1, 2, 3]));
255 assert_eq!(combinations.next(), None);
256
257 len.fetch_add(1, Ordering::SeqCst);
258 assert_eq!(combinations.next(), Some([1, 2, 4]));
259 assert_eq!(combinations.next(), Some([1, 3, 4]));
260 assert_eq!(combinations.next(), Some([2, 3, 4]));
261 assert_eq!(combinations.next(), None);
262 assert_eq!(combinations.next(), None);
263 }
264}
265
266#[cfg(test)]
267mod slice_test {
268 use crate::SliceExt;
269
270 #[test]
271 fn order() {
272 let mut combinations = [1, 2, 3, 4, 5].combinations();
273 assert_eq!(combinations.next(), Some([&1, &2, &3]));
274 assert_eq!(combinations.next(), Some([&1, &2, &4]));
275 assert_eq!(combinations.next(), Some([&1, &3, &4]));
276 assert_eq!(combinations.next(), Some([&2, &3, &4]));
277 assert_eq!(combinations.next(), Some([&1, &2, &5]));
278 assert_eq!(combinations.next(), Some([&1, &3, &5]));
279 assert_eq!(combinations.next(), Some([&2, &3, &5]));
280 assert_eq!(combinations.next(), Some([&1, &4, &5]));
281 assert_eq!(combinations.next(), Some([&2, &4, &5]));
282 assert_eq!(combinations.next(), Some([&3, &4, &5]));
283 assert_eq!(combinations.next(), None);
284 assert_eq!(combinations.next(), None);
285 }
286
287 #[test]
288 fn none_on_size_too_big() {
289 let mut combinations = [1].combinations::<2>();
290 assert_eq!(combinations.next(), None);
291 assert_eq!(combinations.next(), None);
292 }
293
294 #[test]
295 fn empty_arr_on_n_zero() {
296 let mut combinations = [1, 2, 3, 4].combinations();
297 assert_eq!(combinations.next(), Some([]));
298 assert_eq!(combinations.next(), None);
299 assert_eq!(combinations.next(), None);
300 }
301}