You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
281 lines
7.9 KiB
281 lines
7.9 KiB
use alloc::vec::Vec;
|
|
use std::fmt;
|
|
use std::iter::once;
|
|
|
|
use super::lazy_buffer::LazyBuffer;
|
|
|
|
/// An iterator adaptor that iterates through all the `k`-permutations of the
|
|
/// elements from an iterator.
|
|
///
|
|
/// See [`.permutations()`](../trait.Itertools.html#method.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 {
|
|
StartUnknownLen {
|
|
k: usize,
|
|
},
|
|
OngoingUnknownLen {
|
|
k: usize,
|
|
min_n: usize,
|
|
},
|
|
Complete(CompleteState),
|
|
Empty,
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
enum CompleteState {
|
|
Start {
|
|
n: usize,
|
|
k: usize,
|
|
},
|
|
Ongoing {
|
|
indices: Vec<usize>,
|
|
cycles: Vec<usize>,
|
|
}
|
|
}
|
|
|
|
enum CompleteStateRemaining {
|
|
Known(usize),
|
|
Overflow,
|
|
}
|
|
|
|
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> {
|
|
let mut vals = LazyBuffer::new(iter);
|
|
|
|
if k == 0 {
|
|
// Special case, yields single empty vec; `n` is irrelevant
|
|
let state = PermutationState::Complete(CompleteState::Start { n: 0, k: 0 });
|
|
|
|
return Permutations {
|
|
vals,
|
|
state
|
|
};
|
|
}
|
|
|
|
let mut enough_vals = true;
|
|
|
|
while vals.len() < k {
|
|
if !vals.get_next() {
|
|
enough_vals = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
let state = if enough_vals {
|
|
PermutationState::StartUnknownLen { k }
|
|
} else {
|
|
PermutationState::Empty
|
|
};
|
|
|
|
Permutations {
|
|
vals,
|
|
state
|
|
}
|
|
}
|
|
|
|
impl<I> Iterator for Permutations<I>
|
|
where
|
|
I: Iterator,
|
|
I::Item: Clone
|
|
{
|
|
type Item = Vec<I::Item>;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
self.advance();
|
|
|
|
let &mut Permutations { ref vals, ref state } = self;
|
|
|
|
match *state {
|
|
PermutationState::StartUnknownLen { .. } => panic!("unexpected iterator state"),
|
|
PermutationState::OngoingUnknownLen { k, min_n } => {
|
|
let latest_idx = min_n - 1;
|
|
let indices = (0..(k - 1)).chain(once(latest_idx));
|
|
|
|
Some(indices.map(|i| vals[i].clone()).collect())
|
|
}
|
|
PermutationState::Complete(CompleteState::Start { .. }) => None,
|
|
PermutationState::Complete(CompleteState::Ongoing { ref indices, ref cycles }) => {
|
|
let k = cycles.len();
|
|
|
|
Some(indices[0..k].iter().map(|&i| vals[i].clone()).collect())
|
|
},
|
|
PermutationState::Empty => None
|
|
}
|
|
}
|
|
|
|
fn count(self) -> usize {
|
|
let Permutations { vals, state } = self;
|
|
|
|
fn from_complete(complete_state: CompleteState) -> usize {
|
|
match complete_state.remaining() {
|
|
CompleteStateRemaining::Known(count) => count,
|
|
CompleteStateRemaining::Overflow => {
|
|
panic!("Iterator count greater than usize::MAX");
|
|
}
|
|
}
|
|
}
|
|
|
|
match state {
|
|
PermutationState::StartUnknownLen { k } => {
|
|
let n = vals.len() + vals.it.count();
|
|
let complete_state = CompleteState::Start { n, k };
|
|
|
|
from_complete(complete_state)
|
|
}
|
|
PermutationState::OngoingUnknownLen { k, min_n } => {
|
|
let prev_iteration_count = min_n - k + 1;
|
|
let n = vals.len() + vals.it.count();
|
|
let complete_state = CompleteState::Start { n, k };
|
|
|
|
from_complete(complete_state) - prev_iteration_count
|
|
},
|
|
PermutationState::Complete(state) => from_complete(state),
|
|
PermutationState::Empty => 0
|
|
}
|
|
}
|
|
|
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
|
match self.state {
|
|
PermutationState::StartUnknownLen { .. } |
|
|
PermutationState::OngoingUnknownLen { .. } => (0, None), // TODO can we improve this lower bound?
|
|
PermutationState::Complete(ref state) => match state.remaining() {
|
|
CompleteStateRemaining::Known(count) => (count, Some(count)),
|
|
CompleteStateRemaining::Overflow => (::std::usize::MAX, None)
|
|
}
|
|
PermutationState::Empty => (0, Some(0))
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<I> Permutations<I>
|
|
where
|
|
I: Iterator,
|
|
I::Item: Clone
|
|
{
|
|
fn advance(&mut self) {
|
|
let &mut Permutations { ref mut vals, ref mut state } = self;
|
|
|
|
*state = match *state {
|
|
PermutationState::StartUnknownLen { k } => {
|
|
PermutationState::OngoingUnknownLen { k, min_n: k }
|
|
}
|
|
PermutationState::OngoingUnknownLen { k, min_n } => {
|
|
if vals.get_next() {
|
|
PermutationState::OngoingUnknownLen { k, min_n: min_n + 1 }
|
|
} else {
|
|
let n = min_n;
|
|
let prev_iteration_count = n - k + 1;
|
|
let mut complete_state = CompleteState::Start { n, k };
|
|
|
|
// Advance the complete-state iterator to the correct point
|
|
for _ in 0..(prev_iteration_count + 1) {
|
|
complete_state.advance();
|
|
}
|
|
|
|
PermutationState::Complete(complete_state)
|
|
}
|
|
}
|
|
PermutationState::Complete(ref mut state) => {
|
|
state.advance();
|
|
|
|
return;
|
|
}
|
|
PermutationState::Empty => { return; }
|
|
};
|
|
}
|
|
}
|
|
|
|
impl CompleteState {
|
|
fn advance(&mut self) {
|
|
*self = match *self {
|
|
CompleteState::Start { n, k } => {
|
|
let indices = (0..n).collect();
|
|
let cycles = ((n - k)..n).rev().collect();
|
|
|
|
CompleteState::Ongoing {
|
|
cycles,
|
|
indices
|
|
}
|
|
},
|
|
CompleteState::Ongoing { ref mut indices, ref mut cycles } => {
|
|
let n = indices.len();
|
|
let k = cycles.len();
|
|
|
|
for i in (0..k).rev() {
|
|
if cycles[i] == 0 {
|
|
cycles[i] = n - i - 1;
|
|
|
|
let to_push = indices.remove(i);
|
|
indices.push(to_push);
|
|
} else {
|
|
let swap_index = n - cycles[i];
|
|
indices.swap(i, swap_index);
|
|
|
|
cycles[i] -= 1;
|
|
return;
|
|
}
|
|
}
|
|
|
|
CompleteState::Start { n, k }
|
|
}
|
|
}
|
|
}
|
|
|
|
fn remaining(&self) -> CompleteStateRemaining {
|
|
use self::CompleteStateRemaining::{Known, Overflow};
|
|
|
|
match *self {
|
|
CompleteState::Start { n, k } => {
|
|
if n < k {
|
|
return Known(0);
|
|
}
|
|
|
|
let count: Option<usize> = (n - k + 1..n + 1).fold(Some(1), |acc, i| {
|
|
acc.and_then(|acc| acc.checked_mul(i))
|
|
});
|
|
|
|
match count {
|
|
Some(count) => Known(count),
|
|
None => Overflow
|
|
}
|
|
}
|
|
CompleteState::Ongoing { ref indices, ref cycles } => {
|
|
let mut count: usize = 0;
|
|
|
|
for (i, &c) in cycles.iter().enumerate() {
|
|
let radix = indices.len() - i;
|
|
let next_count = count.checked_mul(radix)
|
|
.and_then(|count| count.checked_add(c));
|
|
|
|
count = match next_count {
|
|
Some(count) => count,
|
|
None => { return Overflow; }
|
|
};
|
|
}
|
|
|
|
Known(count)
|
|
}
|
|
}
|
|
}
|
|
}
|