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