Skip to content

Commit 360f14b

Browse files
committed
🚀 Rebase, document: ready for review!
1 parent aa75f69 commit 360f14b

File tree

3 files changed

+647
-40
lines changed

3 files changed

+647
-40
lines changed

src/cartesian_power.rs

+97-21
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,49 @@
11
use alloc::vec::Vec;
22
use std::fmt;
33

4-
/// Pseudo-iterator owned by [`CartesianPower`],
5-
/// yielding underlying indices by references to itself,
6-
/// the [streaming iterator](https://docs.rs/streaming-iterator/latest/streaming_iterator/) way.
4+
/// Yield all indices combinations of size `pow` from `0..base`.
5+
/// This "lending" iterator only allocates once,
6+
/// and yields references to its internal owned slice of updated indices.
7+
/// See [streaming iterator](https://docs.rs/streaming-iterator/latest/streaming_iterator/).
8+
///
9+
/// The resulting iterator is "cycling",
10+
/// meaning that, after the last `.next()` call has yielded `None`,
11+
/// you can call `.next()` again to resume iteration from the start,
12+
/// as many times as needed.
13+
///
14+
/// This is the iterator internally used by [`CartesianPower`],
15+
/// ```
16+
/// use itertools::CartesianPowerIndices;
17+
///
18+
/// let mut it = CartesianPowerIndices::new(3, 2);
19+
/// assert_eq!(it.next(), Some(&[0, 0][..]));
20+
/// assert_eq!(it.next(), Some(&[0, 1][..]));
21+
/// assert_eq!(it.next(), Some(&[0, 2][..]));
22+
/// assert_eq!(it.next(), Some(&[1, 0][..]));
23+
/// assert_eq!(it.next(), Some(&[1, 1][..]));
24+
/// assert_eq!(it.next(), Some(&[1, 2][..]));
25+
/// assert_eq!(it.next(), Some(&[2, 0][..]));
26+
/// assert_eq!(it.next(), Some(&[2, 1][..]));
27+
/// assert_eq!(it.next(), Some(&[2, 2][..]));
28+
/// assert_eq!(it.next(), None); // End of iteration.
29+
/// assert_eq!(it.next(), Some(&[0, 0][..])); // Cycle: start over, forever.
30+
/// assert_eq!(it.next(), Some(&[0, 1][..]));
31+
/// // ...
32+
///
33+
/// let mut it = CartesianPowerIndices::new(2, 3);
34+
/// assert_eq!(it.next(), Some(&[0, 0, 0][..]));
35+
/// assert_eq!(it.next(), Some(&[0, 0, 1][..]));
36+
/// assert_eq!(it.next(), Some(&[0, 1, 0][..]));
37+
/// assert_eq!(it.next(), Some(&[0, 1, 1][..]));
38+
/// assert_eq!(it.next(), Some(&[1, 0, 0][..]));
39+
/// assert_eq!(it.next(), Some(&[1, 0, 1][..]));
40+
/// assert_eq!(it.next(), Some(&[1, 1, 0][..]));
41+
/// assert_eq!(it.next(), Some(&[1, 1, 1][..]));
42+
/// assert_eq!(it.next(), None);
43+
/// assert_eq!(it.next(), Some(&[0, 0, 0][..]));
44+
/// assert_eq!(it.next(), Some(&[0, 0, 1][..]));
45+
/// // ...
46+
/// ```
747
#[derive(Debug, Clone)]
848
pub struct Indices {
949
// May be incremented by owner on first pass as long as exact value is unknown.
@@ -21,13 +61,18 @@ pub struct Indices {
2161
}
2262

2363
impl Indices {
64+
/// Create a new `base^pow` lending iterator.
2465
pub fn new(base: usize, pow: u32) -> Self {
2566
Self {
2667
base,
2768
pow,
2869
values: None,
2970
}
3071
}
72+
73+
/// Step the iterator, yielding a reference to internal updated indices,
74+
/// or `None` if the iteration is exhausted.
75+
#[allow(clippy::should_implement_trait)] // <- Intended `.next` name "like Iterator::next".
3176
pub fn next(&mut self) -> Option<&[usize]> {
3277
let Self { base, pow, values } = self;
3378

@@ -67,6 +112,25 @@ impl Indices {
67112
}
68113
}
69114

115+
/// Same as [`next`][crate::CartesianPowerIndices::next],
116+
/// but skip `n` steps.
117+
/// Return `None` if this would lead to iterator exhaustion.
118+
/// Saturates in case of overflow:
119+
/// the iterator is cycling,
120+
/// but if you skip past the last iteration,
121+
/// you'll obtain `None` no matter how far you skip.
122+
/// Iteration will only resume on further calls to `.next()` and `.nth()`.
123+
///
124+
/// ```
125+
/// use itertools::CartesianPowerIndices;
126+
///
127+
/// let mut it = CartesianPowerIndices::new(3, 2);
128+
/// assert_eq!(it.nth(0), Some(&[0, 0][..]));
129+
/// assert_eq!(it.nth(1), Some(&[0, 2][..]));
130+
/// assert_eq!(it.nth(2), Some(&[1, 2][..]));
131+
/// assert_eq!(it.nth(9), None); // Overshoot, but don't resume cycling yet.
132+
/// assert_eq!(it.nth(2), Some(&[0, 2][..])); // Only resume cycling now.
133+
/// ```
70134
pub fn nth(&mut self, n: usize) -> Option<&[usize]> {
71135
let Self { base, pow, values } = self;
72136
match (base, pow, values, n) {
@@ -110,7 +174,8 @@ impl Indices {
110174
}
111175
}
112176

113-
fn size_hint(&self) -> (usize, Option<usize>) {
177+
/// Akin to [`Iterator::size_hint`].
178+
pub fn size_hint(&self) -> (usize, Option<usize>) {
114179
self.size_hint_with_base(self.base)
115180
}
116181

@@ -195,11 +260,12 @@ fn inbounds_increment_by(n: usize, indices: &mut [usize], base: usize) -> bool {
195260
false
196261
}
197262

198-
/// An adaptor iterating through all the ordered `n`-length lists of items
199-
/// yielded by the underlying iterator, including repetitions.
200-
/// Works by cloning the items into a fresh Vector on every `.next()`.
201-
/// If this is too much allocation for you,
202-
/// consider using the underlying lending [`Indices`] iterator instead.
263+
/// The adaptor adaptor yielded by
264+
/// [`.cartesian_power()`](crate::Itertools::cartesian_power).
265+
///
266+
/// This iterator is *cycling*,
267+
/// meaning that, once consumed after `.next()` returns `None`,
268+
/// you can call `.next()` again to resume iteration from the start.
203269
///
204270
/// See [`.cartesian_power()`](crate::Itertools::cartesian_power)
205271
/// for more information.
@@ -217,24 +283,19 @@ where
217283
indices: Indices,
218284
}
219285

220-
/// Create a new `CartesianPower` from an iterator of clonables.
221-
pub fn cartesian_power<I>(iter: I, pow: u32) -> CartesianPower<I>
286+
impl<I> CartesianPower<I>
222287
where
223288
I: Iterator,
224289
I::Item: Clone,
225290
{
226-
CartesianPower {
227-
iter: Some(iter),
228-
items: None,
229-
indices: Indices::new(0, pow),
291+
pub(crate) fn new(iter: I, pow: u32) -> CartesianPower<I> {
292+
CartesianPower {
293+
iter: Some(iter),
294+
items: None,
295+
indices: Indices::new(0, pow),
296+
}
230297
}
231-
}
232298

233-
impl<I> CartesianPower<I>
234-
where
235-
I: Iterator,
236-
I::Item: Clone,
237-
{
238299
/// Increments internal indices to advance to the next list to be yielded.
239300
/// This collects new items from the underlying iterator
240301
/// if they were not all already collected.
@@ -849,4 +910,19 @@ mod tests {
849910
check!("abc", 3 => 27 o 27 o 27 o 27 o);
850911
check!("abc", 3 => 28 o 28 o 28 o 28 o);
851912
}
913+
914+
#[test]
915+
fn f() {
916+
use crate::CartesianPowerIndices;
917+
let mut it = CartesianPowerIndices::new(3, 2);
918+
while let Some(indices) = it.next() {
919+
println!("&{indices:?}");
920+
}
921+
922+
let mut it = CartesianPowerIndices::new(2, 3);
923+
while let Some(indices) = it.next() {
924+
println!("&{indices:?}");
925+
}
926+
panic!("STOP HERE");
927+
}
852928
}

src/lib.rs

+64-19
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ extern crate alloc;
6060
#[cfg(feature = "use_alloc")]
6161
use alloc::{collections::VecDeque, string::String, vec::Vec};
6262

63-
use cartesian_power::CartesianPower;
6463
pub use either::Either;
6564

6665
use core::borrow::Borrow;
@@ -91,7 +90,10 @@ pub use std::iter as __std_iter;
9190
/// The concrete iterator types.
9291
pub mod structs {
9392
#[cfg(feature = "use_alloc")]
94-
pub use crate::adaptors::MultiProduct;
93+
pub use crate::{
94+
cartesian_power::{CartesianPower, Indices as CartesianPowerIndices},
95+
adaptors::MultiProduct
96+
};
9597
pub use crate::adaptors::{
9698
Batching, Coalesce, Dedup, DedupBy, DedupByWithCount, DedupWithCount, FilterMapOk,
9799
FilterOk, Interleave, InterleaveShortest, MapInto, MapOk, Positions, Product, PutBack,
@@ -1215,6 +1217,66 @@ pub trait Itertools: Iterator {
12151217
adaptors::cartesian_product(self, other.into_iter())
12161218
}
12171219

1220+
/// Return an iterator adaptor that iterates over the given cartesian power of
1221+
/// the element yielded by `self`.
1222+
///
1223+
/// Iterator element type is a collection `Vec<Self::Item>` of size `pow`.
1224+
/// The collection is a fresh vector
1225+
/// allocated on every `.next()` call
1226+
/// and populated with `Self::Item::clone`
1227+
/// until the cartesian power is exhausted.
1228+
/// The underlying iterator is only consumed once,
1229+
/// and all its yielded items are stored within the adaptor for future cloning.
1230+
///
1231+
/// If this is too much allocation for you,
1232+
/// you may try the underlying streaming
1233+
/// [`CartesianPowerIndices`] instead.
1234+
///
1235+
/// The resulting iterator is "cycling",
1236+
/// meaning that, after the last `.next()` call has yielded `None`,
1237+
/// you can call `.next()` again to resume iteration from the start,
1238+
/// as many times as needed.
1239+
///
1240+
/// ```
1241+
/// use itertools::Itertools;
1242+
///
1243+
/// let mut it = "abc".chars().cartesian_power(2);
1244+
/// assert_eq!(it.next(), Some(vec!['a', 'a']));
1245+
/// assert_eq!(it.next(), Some(vec!['a', 'b']));
1246+
/// assert_eq!(it.next(), Some(vec!['a', 'c'])); // Underlying a"abc".chars()` consumed.
1247+
/// assert_eq!(it.next(), Some(vec!['b', 'a']));
1248+
/// assert_eq!(it.next(), Some(vec!['b', 'b']));
1249+
/// assert_eq!(it.next(), Some(vec!['b', 'c']));
1250+
/// assert_eq!(it.next(), Some(vec!['c', 'a']));
1251+
/// assert_eq!(it.next(), Some(vec!['c', 'b']));
1252+
/// assert_eq!(it.next(), Some(vec!['c', 'c']));
1253+
/// assert_eq!(it.next(), None); // Cartesian product exhausted.
1254+
/// assert_eq!(it.next(), Some(vec!['a', 'a'])); // Cycle: start over, *ad libitum*.
1255+
/// assert_eq!(it.next(), Some(vec!['a', 'b']));
1256+
/// // ...
1257+
///
1258+
/// let mut it = "ab".chars().cartesian_power(3);
1259+
/// assert_eq!(it.next(), Some(vec!['a', 'a', 'a']));
1260+
/// assert_eq!(it.next(), Some(vec!['a', 'a', 'b']));
1261+
/// assert_eq!(it.next(), Some(vec!['a', 'b', 'a']));
1262+
/// assert_eq!(it.next(), Some(vec!['a', 'b', 'b']));
1263+
/// assert_eq!(it.next(), Some(vec!['b', 'a', 'a']));
1264+
/// assert_eq!(it.next(), Some(vec!['b', 'a', 'b']));
1265+
/// assert_eq!(it.next(), Some(vec!['b', 'b', 'a']));
1266+
/// assert_eq!(it.next(), Some(vec!['b', 'b', 'b']));
1267+
/// assert_eq!(it.next(), None);
1268+
/// assert_eq!(it.next(), Some(vec!['a', 'a', 'a']));
1269+
/// assert_eq!(it.next(), Some(vec!['a', 'a', 'b']));
1270+
/// // ...
1271+
/// ```
1272+
fn cartesian_power(self, pow: u32) -> CartesianPower<Self>
1273+
where
1274+
Self: Sized,
1275+
Self::Item: Clone,
1276+
{
1277+
CartesianPower::new(self, pow)
1278+
}
1279+
12181280
/// Return an iterator adaptor that iterates over the cartesian product of
12191281
/// all subiterators returned by meta-iterator `self`.
12201282
///
@@ -1795,23 +1857,6 @@ pub trait Itertools: Iterator {
17951857
combinations_with_replacement::combinations_with_replacement(self, k)
17961858
}
17971859

1798-
/// Returns an iterator yielding the successive elements
1799-
/// of the cartesian power of the set described by the original iterator.
1800-
///
1801-
/// ```
1802-
/// use itertools::Itertools;
1803-
///
1804-
/// TODO: illustrative example.
1805-
/// ```
1806-
#[cfg(feature = "use_alloc")]
1807-
fn cartesian_power(self, pow: u32) -> CartesianPower<Self>
1808-
where
1809-
Self: Sized,
1810-
Self::Item: Clone,
1811-
{
1812-
cartesian_power::cartesian_power(self, pow)
1813-
}
1814-
18151860
/// Return an iterator adaptor that iterates over all k-permutations of the
18161861
/// elements from an iterator.
18171862
///

0 commit comments

Comments
 (0)