| use alloc::boxed::Box; |
| use alloc::vec::Vec; |
| use std::fmt; |
| use std::iter::once; |
| use std::iter::FusedIterator; |
| |
| use super::lazy_buffer::LazyBuffer; |
| use crate::size_hint::{self, SizeHint}; |
| |
| /// An iterator adaptor that iterates through all the `k`-permutations of the |
| /// elements from an iterator. |
| /// |
| /// See [`.permutations()`](crate::Itertools::permutations) for |
| /// more information. |
| #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] |
| pub struct Permutations<I: Iterator> { |
| vals: LazyBuffer<I>, |
| state: PermutationState, |
| } |
| |
| impl<I> Clone for Permutations<I> |
| where |
| I: Clone + Iterator, |
| I::Item: Clone, |
| { |
| clone_fields!(vals, state); |
| } |
| |
| #[derive(Clone, Debug)] |
| enum PermutationState { |
| /// No permutation generated yet. |
| Start { k: usize }, |
| /// Values from the iterator are not fully loaded yet so `n` is still unknown. |
| Buffered { k: usize, min_n: usize }, |
| /// All values from the iterator are known so `n` is known. |
| Loaded { |
| indices: Box<[usize]>, |
| cycles: Box<[usize]>, |
| }, |
| /// No permutation left to generate. |
| End, |
| } |
| |
| impl<I> fmt::Debug for Permutations<I> |
| where |
| I: Iterator + fmt::Debug, |
| I::Item: fmt::Debug, |
| { |
| debug_fmt_fields!(Permutations, vals, state); |
| } |
| |
| pub fn permutations<I: Iterator>(iter: I, k: usize) -> Permutations<I> { |
| Permutations { |
| vals: LazyBuffer::new(iter), |
| state: PermutationState::Start { k }, |
| } |
| } |
| |
| impl<I> Iterator for Permutations<I> |
| where |
| I: Iterator, |
| I::Item: Clone, |
| { |
| type Item = Vec<I::Item>; |
| |
| fn next(&mut self) -> Option<Self::Item> { |
| let Self { vals, state } = self; |
| match state { |
| PermutationState::Start { k: 0 } => { |
| *state = PermutationState::End; |
| Some(Vec::new()) |
| } |
| &mut PermutationState::Start { k } => { |
| vals.prefill(k); |
| if vals.len() != k { |
| *state = PermutationState::End; |
| return None; |
| } |
| *state = PermutationState::Buffered { k, min_n: k }; |
| Some(vals[0..k].to_vec()) |
| } |
| PermutationState::Buffered { ref k, min_n } => { |
| if vals.get_next() { |
| let item = (0..*k - 1) |
| .chain(once(*min_n)) |
| .map(|i| vals[i].clone()) |
| .collect(); |
| *min_n += 1; |
| Some(item) |
| } else { |
| let n = *min_n; |
| let prev_iteration_count = n - *k + 1; |
| let mut indices: Box<[_]> = (0..n).collect(); |
| let mut cycles: Box<[_]> = (n - k..n).rev().collect(); |
| // Advance the state to the correct point. |
| for _ in 0..prev_iteration_count { |
| if advance(&mut indices, &mut cycles) { |
| *state = PermutationState::End; |
| return None; |
| } |
| } |
| let item = vals.get_at(&indices[0..*k]); |
| *state = PermutationState::Loaded { indices, cycles }; |
| Some(item) |
| } |
| } |
| PermutationState::Loaded { indices, cycles } => { |
| if advance(indices, cycles) { |
| *state = PermutationState::End; |
| return None; |
| } |
| let k = cycles.len(); |
| Some(vals.get_at(&indices[0..k])) |
| } |
| PermutationState::End => None, |
| } |
| } |
| |
| fn count(self) -> usize { |
| let Self { vals, state } = self; |
| let n = vals.count(); |
| state.size_hint_for(n).1.unwrap() |
| } |
| |
| fn size_hint(&self) -> SizeHint { |
| let (mut low, mut upp) = self.vals.size_hint(); |
| low = self.state.size_hint_for(low).0; |
| upp = upp.and_then(|n| self.state.size_hint_for(n).1); |
| (low, upp) |
| } |
| } |
| |
| impl<I> FusedIterator for Permutations<I> |
| where |
| I: Iterator, |
| I::Item: Clone, |
| { |
| } |
| |
| fn advance(indices: &mut [usize], cycles: &mut [usize]) -> bool { |
| let n = indices.len(); |
| let k = cycles.len(); |
| // NOTE: if `cycles` are only zeros, then we reached the last permutation. |
| for i in (0..k).rev() { |
| if cycles[i] == 0 { |
| cycles[i] = n - i - 1; |
| indices[i..].rotate_left(1); |
| } else { |
| let swap_index = n - cycles[i]; |
| indices.swap(i, swap_index); |
| cycles[i] -= 1; |
| return false; |
| } |
| } |
| true |
| } |
| |
| impl PermutationState { |
| fn size_hint_for(&self, n: usize) -> SizeHint { |
| // At the beginning, there are `n!/(n-k)!` items to come. |
| let at_start = |n, k| { |
| debug_assert!(n >= k); |
| let total = (n - k + 1..=n).try_fold(1usize, |acc, i| acc.checked_mul(i)); |
| (total.unwrap_or(usize::MAX), total) |
| }; |
| match *self { |
| Self::Start { k } if n < k => (0, Some(0)), |
| Self::Start { k } => at_start(n, k), |
| Self::Buffered { k, min_n } => { |
| // Same as `Start` minus the previously generated items. |
| size_hint::sub_scalar(at_start(n, k), min_n - k + 1) |
| } |
| Self::Loaded { |
| ref indices, |
| ref cycles, |
| } => { |
| let count = cycles.iter().enumerate().try_fold(0usize, |acc, (i, &c)| { |
| acc.checked_mul(indices.len() - i) |
| .and_then(|count| count.checked_add(c)) |
| }); |
| (count.unwrap_or(usize::MAX), count) |
| } |
| Self::End => (0, Some(0)), |
| } |
| } |
| } |