Skip to content

Commit a916d37

Browse files
committed
some simplifications and refactors
1 parent 98b79de commit a916d37

File tree

3 files changed

+157
-117
lines changed

3 files changed

+157
-117
lines changed

src/combinations.rs

Lines changed: 5 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
use core::array;
2-
use core::borrow::BorrowMut;
31
use std::fmt;
42
use std::iter::FusedIterator;
53

6-
use super::lazy_buffer::LazyBuffer;
4+
use super::lazy_buffer::{ConstUsize, LazyBuffer, MaybeConstUsize as _, PoolIndex};
75
use alloc::vec::Vec;
86

97
use crate::adaptors::checked_binomial;
@@ -18,15 +16,15 @@ pub fn combinations<I: Iterator>(iter: I, k: usize) -> Combinations<I>
1816
where
1917
I::Item: Clone,
2018
{
21-
Combinations::new(iter, (0..k).collect())
19+
Combinations::new(iter, PoolIndex::start(k))
2220
}
2321

2422
/// Create a new `ArrayCombinations` from a clonable iterator.
2523
pub fn array_combinations<I: Iterator, const K: usize>(iter: I) -> ArrayCombinations<I, K>
2624
where
2725
I::Item: Clone,
2826
{
29-
ArrayCombinations::new(iter, array::from_fn(|i| i))
27+
ArrayCombinations::new(iter, PoolIndex::start(ConstUsize))
3028
}
3129

3230
/// An iterator to iterate through all the `k`-length combinations in an iterator.
@@ -39,79 +37,6 @@ pub struct CombinationsGeneric<I: Iterator, Idx> {
3937
first: bool,
4038
}
4139

42-
pub trait MaybeConstUsize : Clone + Copy + std::fmt::Debug {
43-
/*TODO const*/fn value(self) -> usize;
44-
}
45-
46-
#[derive(Clone, Copy, Debug)]
47-
pub struct ConstUsize<const N: usize>;
48-
impl<const N: usize> MaybeConstUsize for ConstUsize<N> {
49-
fn value(self) -> usize {
50-
N
51-
}
52-
}
53-
54-
impl MaybeConstUsize for usize {
55-
fn value(self) -> usize {
56-
self
57-
}
58-
}
59-
60-
/// A type holding indices of elements in a pool or buffer of items from an inner iterator
61-
/// and used to pick out different combinations in a generic way.
62-
pub trait PoolIndex: BorrowMut<[usize]> {
63-
type Item<T>;
64-
type Length: MaybeConstUsize;
65-
66-
fn extract_item<I: Iterator>(&self, pool: &LazyBuffer<I>) -> Self::Item<I::Item>
67-
where
68-
I::Item: Clone;
69-
70-
fn from_fn<T, F: Fn(usize)->T>(k: Self::Length, f: F) -> Self::Item<T>;
71-
72-
fn len(&self) -> Self::Length;
73-
}
74-
75-
impl PoolIndex for Vec<usize> {
76-
type Item<T> = Vec<T>;
77-
type Length = usize;
78-
79-
fn extract_item<I: Iterator>(&self, pool: &LazyBuffer<I>) -> Self::Item<I::Item>
80-
where
81-
I::Item: Clone
82-
{
83-
pool.get_at(self)
84-
}
85-
86-
fn from_fn<T, F: Fn(usize)->T>(k: Self::Length, f: F) -> Self::Item<T> {
87-
(0..k).map(f).collect()
88-
}
89-
90-
fn len(&self) -> Self::Length {
91-
self.len()
92-
}
93-
}
94-
95-
impl<const K: usize> PoolIndex for [usize; K] {
96-
type Item<T> = [T; K];
97-
type Length = ConstUsize<K>;
98-
99-
fn extract_item<I: Iterator>(&self, pool: &LazyBuffer<I>) -> Self::Item<I::Item>
100-
where
101-
I::Item: Clone
102-
{
103-
pool.get_array(*self)
104-
}
105-
106-
fn from_fn<T, F: Fn(usize)->T>(_k: Self::Length, f: F) -> Self::Item<T> {
107-
std::array::from_fn(f)
108-
}
109-
110-
fn len(&self) -> Self::Length {
111-
ConstUsize::<K>
112-
}
113-
}
114-
11540
impl<I, Idx> Clone for CombinationsGeneric<I, Idx>
11641
where
11742
I: Iterator + Clone,
@@ -142,8 +67,8 @@ impl<I: Iterator, Idx: PoolIndex> CombinationsGeneric<I, Idx> {
14267

14368
/// Returns the length of a combination produced by this iterator.
14469
#[inline]
145-
pub fn k(&self) -> Idx::Length {
146-
self.indices.len()
70+
pub fn k(&self) -> usize {
71+
self.indices.len().value()
14772
}
14873

14974
/// Returns the (current) length of the pool from which combination elements are

src/lazy_buffer.rs

Lines changed: 118 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
use alloc::vec::Vec;
2+
use core::borrow::BorrowMut;
3+
use core::ops::Deref;
24
use std::iter::Fuse;
35
use std::ops::Index;
46

@@ -60,7 +62,7 @@ where
6062
indices.iter().map(|i| self.buffer[*i].clone()).collect()
6163
}
6264

63-
pub fn get_array<const K: usize>(&self, indices: [usize; K]) -> [I::Item; K] {
65+
pub fn get_array<const K: usize>(&self, indices: &[usize; K]) -> [I::Item; K] {
6466
indices.map(|i| self.buffer[i].clone())
6567
}
6668
}
@@ -77,3 +79,118 @@ where
7779
self.buffer.index(index)
7880
}
7981
}
82+
83+
pub trait MaybeConstUsize: Clone + Copy + std::fmt::Debug {
84+
/*TODO const*/
85+
fn value(self) -> usize;
86+
}
87+
88+
#[derive(Clone, Copy, Debug)]
89+
pub struct ConstUsize<const N: usize>;
90+
impl<const N: usize> MaybeConstUsize for ConstUsize<N> {
91+
fn value(self) -> usize {
92+
N
93+
}
94+
}
95+
96+
impl MaybeConstUsize for usize {
97+
fn value(self) -> usize {
98+
self
99+
}
100+
}
101+
102+
/// A type holding indices of elements in a pool or buffer of items from an inner iterator
103+
/// and used to pick out different combinations in a generic way.
104+
pub trait PoolIndex: BorrowMut<[usize]> {
105+
type Item<T>;
106+
type Length: MaybeConstUsize;
107+
108+
fn extract_item<I: Iterator>(&self, pool: &LazyBuffer<I>) -> Self::Item<I::Item>
109+
where
110+
I::Item: Clone;
111+
112+
fn from_fn<F: Fn(usize) -> usize>(k: Self::Length, f: F) -> Self;
113+
114+
fn item_from_fn<T, F: Fn(usize) -> T>(k: Self::Length, f: F) -> Self::Item<T>;
115+
116+
fn len(&self) -> Self::Length;
117+
118+
fn start(len: Self::Length) -> Self
119+
where
120+
Self: Sized,
121+
{
122+
Self::from_fn(len, |i| i)
123+
}
124+
}
125+
126+
impl PoolIndex for Vec<usize> {
127+
type Item<T> = Vec<T>;
128+
type Length = usize;
129+
130+
fn extract_item<I: Iterator>(&self, pool: &LazyBuffer<I>) -> Self::Item<I::Item>
131+
where
132+
I::Item: Clone,
133+
{
134+
pool.get_at(self)
135+
}
136+
137+
fn from_fn<F: Fn(usize) -> usize>(k: Self::Length, f: F) -> Self {
138+
(0..k).map(f).collect()
139+
}
140+
141+
fn item_from_fn<T, F: Fn(usize) -> T>(k: Self::Length, f: F) -> Self::Item<T> {
142+
(0..k).map(f).collect()
143+
}
144+
145+
fn len(&self) -> Self::Length {
146+
self.len()
147+
}
148+
}
149+
150+
impl PoolIndex for Box<[usize]> {
151+
type Item<T> = Vec<T>;
152+
type Length = usize;
153+
154+
fn extract_item<I: Iterator>(&self, pool: &LazyBuffer<I>) -> Self::Item<I::Item>
155+
where
156+
I::Item: Clone,
157+
{
158+
pool.get_at(self)
159+
}
160+
161+
fn from_fn<F: Fn(usize) -> usize>(k: Self::Length, f: F) -> Self {
162+
(0..k).map(f).collect()
163+
}
164+
165+
fn item_from_fn<T, F: Fn(usize) -> T>(k: Self::Length, f: F) -> Self::Item<T> {
166+
(0..k).map(f).collect()
167+
}
168+
169+
fn len(&self) -> Self::Length {
170+
self.deref().len()
171+
}
172+
}
173+
174+
impl<const K: usize> PoolIndex for [usize; K] {
175+
type Item<T> = [T; K];
176+
type Length = ConstUsize<K>;
177+
178+
fn extract_item<I: Iterator>(&self, pool: &LazyBuffer<I>) -> Self::Item<I::Item>
179+
where
180+
I::Item: Clone,
181+
{
182+
pool.get_array(self)
183+
}
184+
185+
fn from_fn<F: Fn(usize) -> usize>(_k: Self::Length, f: F) -> Self {
186+
core::array::from_fn(f)
187+
}
188+
189+
fn item_from_fn<T, F: Fn(usize) -> T>(_k: Self::Length, f: F) -> Self::Item<T> {
190+
core::array::from_fn(f)
191+
}
192+
193+
fn len(&self) -> Self::Length {
194+
ConstUsize
195+
}
196+
}

src/permutations.rs

Lines changed: 34 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
use alloc::boxed::Box;
2-
use alloc::vec::Vec;
32
use std::fmt;
43
use std::iter::FusedIterator;
54

6-
use super::lazy_buffer::LazyBuffer;
5+
use super::lazy_buffer::{LazyBuffer, MaybeConstUsize, PoolIndex};
76
use crate::size_hint::{self, SizeHint};
8-
use crate::combinations::{MaybeConstUsize, PoolIndex};
97

108
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
119
pub struct PermutationsGeneric<I: Iterator, Idx: PoolIndex> {
@@ -18,7 +16,7 @@ pub struct PermutationsGeneric<I: Iterator, Idx: PoolIndex> {
1816
///
1917
/// See [`.permutations()`](crate::Itertools::permutations) for
2018
/// more information.
21-
pub type Permutations<I> = PermutationsGeneric<I, Vec<usize>>;
19+
pub type Permutations<I> = PermutationsGeneric<I, Box<[usize]>>;
2220

2321
impl<I, Idx> Clone for PermutationsGeneric<I, Idx>
2422
where
@@ -34,13 +32,9 @@ enum PermutationState<Idx: PoolIndex> {
3432
/// No permutation generated yet.
3533
Start { k: Idx::Length },
3634
/// Values from the iterator are not fully loaded yet so `n` is still unknown.
37-
Buffered { k: Idx::Length, min_n: usize },
35+
Buffered { indices: Idx, min_n: usize },
3836
/// All values from the iterator are known so `n` is known.
39-
Loaded {
40-
indices: Box<[usize]>,
41-
cycles: Box<[usize]>, // TODO Should be Idx::Item<usize>
42-
k: Idx::Length, // TODO Should be inferred from cycles
43-
},
37+
Loaded { indices: Box<[usize]>, cycles: Idx },
4438
/// No permutation left to generate.
4539
End,
4640
}
@@ -61,10 +55,11 @@ pub fn permutations<I: Iterator>(iter: I, k: usize) -> Permutations<I> {
6155
}
6256
}
6357

64-
impl<I, Idx: PoolIndex> Iterator for PermutationsGeneric<I, Idx>
58+
impl<I, Idx> Iterator for PermutationsGeneric<I, Idx>
6559
where
6660
I: Iterator,
6761
I::Item: Clone,
62+
Idx: PoolIndex,
6863
{
6964
type Item = Idx::Item<I::Item>;
7065

@@ -80,45 +75,44 @@ where
8075
*state = PermutationState::End;
8176
return None;
8277
}
83-
*state = PermutationState::Buffered { k, min_n: k.value() };
78+
*state = PermutationState::Buffered {
79+
indices: Idx::start(k),
80+
min_n: k.value(),
81+
};
8482
}
85-
Some(Idx::from_fn(k, |i| vals[i].clone()))
83+
Some(Idx::start(k).extract_item(vals))
8684
}
87-
PermutationState::Buffered { k, min_n } => {
85+
PermutationState::Buffered { indices, min_n } => {
86+
let k = indices.len();
8887
if vals.get_next() {
89-
// TODO This is ugly. Maybe working on indices is better?
90-
let item = Idx::from_fn(*k, |i| {
91-
vals[if i==k.value()-1 {
92-
*min_n
93-
} else {
94-
i
95-
}].clone()
96-
});
88+
indices.borrow_mut()[k.value() - 1] += 1;
9789
*min_n += 1;
98-
Some(item)
90+
Some(indices.extract_item(vals))
9991
} else {
10092
let n = *min_n;
10193
let prev_iteration_count = n - k.value() + 1;
10294
let mut indices: Box<[_]> = (0..n).collect();
103-
let mut cycles: Box<[_]> = (n - k.value()..n).rev().collect();
95+
let mut cycles = Idx::from_fn(k, |i| n - 1 - i);
10496
// Advance the state to the correct point.
10597
for _ in 0..prev_iteration_count {
106-
if advance(&mut indices, &mut cycles) {
98+
if advance(&mut indices, cycles.borrow_mut()) {
10799
*state = PermutationState::End;
108100
return None;
109101
}
110102
}
111-
let item = Idx::from_fn(*k, |i| vals[indices[i]].clone());
112-
*state = PermutationState::Loaded { indices, cycles, k:*k };
103+
let item = Idx::item_from_fn(k, |i| vals[indices[i]].clone());
104+
*state = PermutationState::Loaded { indices, cycles };
113105
Some(item)
114106
}
115107
}
116-
PermutationState::Loaded { indices, cycles, k} => {
117-
if advance(indices, cycles) {
108+
PermutationState::Loaded { indices, cycles } => {
109+
if advance(indices, cycles.borrow_mut()) {
118110
*state = PermutationState::End;
119111
return None;
120112
}
121-
Some(Idx::from_fn(*k, |i| vals[indices[i]].clone()))
113+
Some(Idx::item_from_fn(cycles.len(), |i| {
114+
vals[indices[i]].clone()
115+
}))
122116
}
123117
PermutationState::End => None,
124118
}
@@ -174,19 +168,23 @@ impl<Idx: PoolIndex> PermutationState<Idx> {
174168
match *self {
175169
Self::Start { k } if n < k.value() => (0, Some(0)),
176170
Self::Start { k } => at_start(n, k),
177-
Self::Buffered { k, min_n } => {
171+
Self::Buffered { ref indices, min_n } => {
172+
let k = indices.len();
178173
// Same as `Start` minus the previously generated items.
179174
size_hint::sub_scalar(at_start(n, k), min_n - k.value() + 1)
180175
}
181176
Self::Loaded {
182177
ref indices,
183178
ref cycles,
184-
k: _,
185179
} => {
186-
let count = cycles.iter().enumerate().try_fold(0usize, |acc, (i, &c)| {
187-
acc.checked_mul(indices.len() - i)
188-
.and_then(|count| count.checked_add(c))
189-
});
180+
let count = cycles
181+
.borrow()
182+
.iter()
183+
.enumerate()
184+
.try_fold(0usize, |acc, (i, &c)| {
185+
acc.checked_mul(indices.len() - i)
186+
.and_then(|count| count.checked_add(c))
187+
});
190188
(count.unwrap_or(usize::MAX), count)
191189
}
192190
Self::End => (0, Some(0)),

0 commit comments

Comments
 (0)