aboutsummaryrefslogtreecommitdiff
path: root/src/tuple_impl.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/tuple_impl.rs')
-rw-r--r--src/tuple_impl.rs118
1 files changed, 83 insertions, 35 deletions
diff --git a/src/tuple_impl.rs b/src/tuple_impl.rs
index f205f01..1d24b0b 100644
--- a/src/tuple_impl.rs
+++ b/src/tuple_impl.rs
@@ -1,6 +1,9 @@
//! Some iterator that produces tuples
use std::iter::Fuse;
+use std::iter::Take;
+use std::iter::Cycle;
+use std::marker::PhantomData;
// `HomogeneousTuple` is a public facade for `TupleCollect`, allowing
// tuple-related methods to be used by clients in generic contexts, while
@@ -54,12 +57,12 @@ impl<T> Iterator for TupleBuffer<T>
fn size_hint(&self) -> (usize, Option<usize>) {
let buffer = &self.buf.as_ref()[self.cur..];
- let len = if buffer.len() == 0 {
+ let len = if buffer.is_empty() {
0
} else {
buffer.iter()
.position(|x| x.is_none())
- .unwrap_or(buffer.len())
+ .unwrap_or_else(|| buffer.len())
};
(len, Some(len))
}
@@ -100,7 +103,7 @@ impl<I, T> Iterator for Tuples<I, T>
{
type Item = T;
- fn next(&mut self) -> Option<T> {
+ fn next(&mut self) -> Option<Self::Item> {
T::collect_from_iter(&mut self.iter, &mut self.buf)
}
}
@@ -170,7 +173,7 @@ impl<I, T> Iterator for TupleWindows<I, T>
{
type Item = T;
- fn next(&mut self) -> Option<T> {
+ fn next(&mut self) -> Option<Self::Item> {
if T::num_items() == 1 {
return T::collect_from_iter_no_buf(&mut self.iter)
}
@@ -184,6 +187,48 @@ impl<I, T> Iterator for TupleWindows<I, T>
}
}
+/// An iterator over all windows,wrapping back to the first elements when the
+/// window would otherwise exceed the length of the iterator, producing tuples
+/// of a specific size.
+///
+/// See [`.circular_tuple_windows()`](../trait.Itertools.html#method.circular_tuple_windows) for more
+/// information.
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[derive(Debug)]
+pub struct CircularTupleWindows<I, T: Clone>
+ where I: Iterator<Item = T::Item> + Clone,
+ T: TupleCollect + Clone
+{
+ iter: Take<TupleWindows<Cycle<I>, T>>,
+ phantom_data: PhantomData<T>
+}
+
+pub fn circular_tuple_windows<I, T>(iter: I) -> CircularTupleWindows<I, T>
+ where I: Iterator<Item = T::Item> + Clone + ExactSizeIterator,
+ T: TupleCollect + Clone,
+ T::Item: Clone
+{
+ let len = iter.len();
+ let iter = tuple_windows(iter.cycle()).take(len);
+
+ CircularTupleWindows {
+ iter,
+ phantom_data: PhantomData{}
+ }
+}
+
+impl<I, T> Iterator for CircularTupleWindows<I, T>
+ where I: Iterator<Item = T::Item> + Clone,
+ T: TupleCollect + Clone,
+ T::Item: Clone
+{
+ type Item = T;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.iter.next()
+ }
+}
+
pub trait TupleCollect: Sized {
type Item;
type Buffer: Default + AsRef<[Option<Self::Item>]> + AsMut<[Option<Self::Item>]>;
@@ -199,16 +244,32 @@ pub trait TupleCollect: Sized {
fn left_shift_push(&mut self, item: Self::Item);
}
+macro_rules! count_ident{
+ () => {0};
+ ($i0:ident, $($i:ident,)*) => {1 + count_ident!($($i,)*)};
+}
+macro_rules! ignore_ident{
+ ($id:ident, $($t:tt)*) => {$($t)*};
+}
+macro_rules! rev_for_each_ident{
+ ($m:ident, ) => {};
+ ($m:ident, $i0:ident, $($i:ident,)*) => {
+ rev_for_each_ident!($m, $($i,)*);
+ $m!($i0);
+ };
+}
+
macro_rules! impl_tuple_collect {
- () => ();
- ($N:expr; $A:ident ; $($X:ident),* ; $($Y:ident),* ; $($Y_rev:ident),*) => (
- impl<$A> TupleCollect for ($($X),*,) {
- type Item = $A;
- type Buffer = [Option<$A>; $N - 1];
+ ($dummy:ident,) => {}; // stop
+ ($dummy:ident, $($Y:ident,)*) => (
+ impl_tuple_collect!($($Y,)*);
+ impl<A> TupleCollect for ($(ignore_ident!($Y, A),)*) {
+ type Item = A;
+ type Buffer = [Option<A>; count_ident!($($Y,)*) - 1];
#[allow(unused_assignments, unused_mut)]
fn collect_from_iter<I>(iter: I, buf: &mut Self::Buffer) -> Option<Self>
- where I: IntoIterator<Item = $A>
+ where I: IntoIterator<Item = A>
{
let mut iter = iter.into_iter();
$(
@@ -236,44 +297,31 @@ macro_rules! impl_tuple_collect {
return None;
}
- #[allow(unused_assignments)]
fn collect_from_iter_no_buf<I>(iter: I) -> Option<Self>
- where I: IntoIterator<Item = $A>
+ where I: IntoIterator<Item = A>
{
let mut iter = iter.into_iter();
- loop {
- $(
- let $Y = if let Some($Y) = iter.next() {
- $Y
- } else {
- break;
- };
- )*
- return Some(($($Y),*,))
- }
- return None;
+ Some(($(
+ { let $Y = iter.next()?; $Y },
+ )*))
}
fn num_items() -> usize {
- $N
+ count_ident!($($Y,)*)
}
- fn left_shift_push(&mut self, item: $A) {
+ fn left_shift_push(&mut self, mut item: A) {
use std::mem::replace;
let &mut ($(ref mut $Y),*,) = self;
- let tmp = item;
- $(
- let tmp = replace($Y_rev, tmp);
- )*
- drop(tmp);
+ macro_rules! replace_item{($i:ident) => {
+ item = replace($i, item);
+ }};
+ rev_for_each_ident!(replace_item, $($Y,)*);
+ drop(item);
}
}
)
}
-
-impl_tuple_collect!(1; A; A; a; a);
-impl_tuple_collect!(2; A; A, A; a, b; b, a);
-impl_tuple_collect!(3; A; A, A, A; a, b, c; c, b, a);
-impl_tuple_collect!(4; A; A, A, A, A; a, b, c, d; d, c, b, a);
+impl_tuple_collect!(dummy, a, b, c, d, e, f, g, h, i, j, k, l,);