Skip to content

Commit 9bba778

Browse files
mendelsshopphimuemue
authored andcommitted
Generisized combinations_with_replacement underlying list type
1 parent e4c0a82 commit 9bba778

File tree

1 file changed

+38
-25
lines changed

1 file changed

+38
-25
lines changed

src/combinations_with_replacement.rs

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,36 @@
11
use alloc::boxed::Box;
2-
use alloc::vec::Vec;
2+
use core::array;
33
use std::fmt;
44
use std::iter::FusedIterator;
55

66
use super::lazy_buffer::LazyBuffer;
77
use crate::adaptors::checked_binomial;
8-
8+
use crate::combinations::PoolIndex;
99
/// An iterator to iterate through all the `n`-length combinations in an iterator, with replacement.
1010
///
1111
/// See [`.combinations_with_replacement()`](crate::Itertools::combinations_with_replacement)
1212
/// for more information.
1313
#[derive(Clone)]
1414
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
15-
pub struct CombinationsWithReplacement<I>
15+
pub struct CombinationsWithReplacementGeneric<I, Idx>
1616
where
1717
I: Iterator,
1818
I::Item: Clone,
1919
{
20-
indices: Box<[usize]>,
20+
indices: Idx,
2121
pool: LazyBuffer<I>,
2222
first: bool,
2323
}
2424

25-
impl<I> fmt::Debug for CombinationsWithReplacement<I>
25+
/// Iterator for `Box<[I]>` valued combinations_with_replacement returned by [`.combinations_with_replacement()`](crate::Itertools::combinations_with_replacement)
26+
pub type CombinationsWithReplacement<I> = CombinationsWithReplacementGeneric<I, Box<[usize]>>;
27+
impl<I, Idx> fmt::Debug for CombinationsWithReplacementGeneric<I, Idx>
2628
where
2729
I: Iterator + fmt::Debug,
2830
I::Item: fmt::Debug + Clone,
31+
Idx: fmt::Debug,
2932
{
30-
debug_fmt_fields!(CombinationsWithReplacement, indices, pool, first);
33+
debug_fmt_fields!(CombinationsWithReplacementGeneric, indices, pool, first);
3134
}
3235

3336
/// Create a new `CombinationsWithReplacement` from a clonable iterator.
@@ -37,16 +40,11 @@ where
3740
I::Item: Clone,
3841
{
3942
let indices = alloc::vec![0; k].into_boxed_slice();
40-
let pool: LazyBuffer<I> = LazyBuffer::new(iter);
4143

42-
CombinationsWithReplacement {
43-
indices,
44-
pool,
45-
first: true,
46-
}
44+
CombinationsWithReplacementGeneric::new(iter, indices)
4745
}
4846

49-
impl<I> CombinationsWithReplacement<I>
47+
impl<I: Iterator, Idx: PoolIndex<I::Item>> CombinationsWithReplacementGeneric<I, Idx>
5048
where
5149
I: Iterator,
5250
I::Item: Clone,
@@ -62,7 +60,8 @@ where
6260

6361
// Work out where we need to update our indices
6462
let mut increment = None;
65-
for (i, indices_int) in self.indices.iter().enumerate().rev() {
63+
let indices: &mut [usize] = self.indices.borrow_mut();
64+
for (i, indices_int) in indices.iter().enumerate().rev() {
6665
if *indices_int < self.pool.len() - 1 {
6766
increment = Some((i, indices_int + 1));
6867
break;
@@ -73,39 +72,52 @@ where
7372
Some((increment_from, increment_value)) => {
7473
// We need to update the rightmost non-max value
7574
// and all those to the right
76-
self.indices[increment_from..].fill(increment_value);
75+
indices[increment_from..].fill(increment_value);
7776
false
7877
}
7978
// Otherwise, we're done
8079
None => true,
8180
}
8281
}
82+
/// Constructor with arguments the inner iterator and the initial state for the indices.
83+
fn new(iter: I, indices: Idx) -> Self {
84+
Self {
85+
indices,
86+
pool: LazyBuffer::new(iter),
87+
first: true,
88+
}
89+
}
8390
}
8491

85-
impl<I> Iterator for CombinationsWithReplacement<I>
92+
impl<I, Idx> Iterator for CombinationsWithReplacementGeneric<I, Idx>
8693
where
8794
I: Iterator,
8895
I::Item: Clone,
96+
Idx: PoolIndex<I::Item>,
8997
{
90-
type Item = Vec<I::Item>;
98+
type Item = Idx::Item;
9199

92100
fn next(&mut self) -> Option<Self::Item> {
93101
if self.first {
94102
// In empty edge cases, stop iterating immediately
95-
if !(self.indices.is_empty() || self.pool.get_next()) {
103+
if !(core::borrow::Borrow::<[usize]>::borrow(&self.indices).is_empty()
104+
|| self.pool.get_next())
105+
{
96106
return None;
97107
}
98108
self.first = false;
99109
} else if self.increment_indices() {
100110
return None;
101111
}
102-
Some(self.pool.get_at(&self.indices))
112+
Some(self.indices.extract_item(&self.pool))
103113
}
104114

105115
fn nth(&mut self, n: usize) -> Option<Self::Item> {
106116
if self.first {
107117
// In empty edge cases, stop iterating immediately
108-
if !(self.indices.is_empty() || self.pool.get_next()) {
118+
if !(core::borrow::Borrow::<[usize]>::borrow(&self.indices).is_empty()
119+
|| self.pool.get_next())
120+
{
109121
return None;
110122
}
111123
self.first = false;
@@ -117,13 +129,13 @@ where
117129
return None;
118130
}
119131
}
120-
Some(self.pool.get_at(&self.indices))
132+
Some(self.indices.extract_item(&self.pool))
121133
}
122134

123135
fn size_hint(&self) -> (usize, Option<usize>) {
124136
let (mut low, mut upp) = self.pool.size_hint();
125-
low = remaining_for(low, self.first, &self.indices).unwrap_or(usize::MAX);
126-
upp = upp.and_then(|upp| remaining_for(upp, self.first, &self.indices));
137+
low = remaining_for(low, self.first, self.indices.borrow()).unwrap_or(usize::MAX);
138+
upp = upp.and_then(|upp| remaining_for(upp, self.first, self.indices.borrow()));
127139
(low, upp)
128140
}
129141

@@ -134,14 +146,15 @@ where
134146
first,
135147
} = self;
136148
let n = pool.count();
137-
remaining_for(n, first, &indices).unwrap()
149+
remaining_for(n, first, indices.borrow()).unwrap()
138150
}
139151
}
140152

141-
impl<I> FusedIterator for CombinationsWithReplacement<I>
153+
impl<I, Idx> FusedIterator for CombinationsWithReplacementGeneric<I, Idx>
142154
where
143155
I: Iterator,
144156
I::Item: Clone,
157+
Idx: PoolIndex<I::Item>,
145158
{
146159
}
147160

0 commit comments

Comments
 (0)