diff --git a/Cargo.toml b/Cargo.toml index 8665fc7fd..b0a5ed74c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,6 @@ test = true num-integer = "0.1.39" num-traits = "0.2" num-complex = "0.2" -itertools = { version = "0.8.0", default-features = false } rayon = { version = "1.0.3", optional = true } diff --git a/src/dimension/dim.rs b/src/dimension/dim.rs index b66863726..0ce989de5 100644 --- a/src/dimension/dim.rs +++ b/src/dimension/dim.rs @@ -6,11 +6,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use itertools::zip; use std::fmt; use super::Dimension; use super::IntoDimension; +use crate::itertools::zip; use crate::Ix; /// Dimension description. diff --git a/src/dimension/dimension_trait.rs b/src/dimension/dimension_trait.rs index d0fc84a6e..4bfe7c0b2 100644 --- a/src/dimension/dimension_trait.rs +++ b/src/dimension/dimension_trait.rs @@ -10,11 +10,10 @@ use std::fmt::Debug; use std::ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign}; use std::ops::{Index, IndexMut}; -use itertools::{enumerate, izip, zip}; - use super::axes_of; use super::conversion::Convert; use super::{stride_offset, stride_offset_checked}; +use crate::itertools::{enumerate, zip}; use crate::Axis; use crate::IntoDimension; use crate::RemoveAxis; diff --git a/src/dimension/mod.rs b/src/dimension/mod.rs index 6b86af653..c5844ccbc 100644 --- a/src/dimension/mod.rs +++ b/src/dimension/mod.rs @@ -8,7 +8,6 @@ use crate::error::{from_kind, ErrorKind, ShapeError}; use crate::{Ix, Ixs, Slice, SliceOrIndex}; -use itertools::izip; use num_integer::div_floor; pub use self::axes::{axes_of, Axes, AxisDescription}; diff --git a/src/dimension/ndindex.rs b/src/dimension/ndindex.rs index c2d872ec4..d9bac1d94 100644 --- a/src/dimension/ndindex.rs +++ b/src/dimension/ndindex.rs @@ -1,8 +1,7 @@ use std::fmt::Debug; -use itertools::zip; - use super::{stride_offset, stride_offset_checked}; +use crate::itertools::zip; use crate::{ Dim, Dimension, IntoDimension, Ix, Ix0, Ix1, Ix2, Ix3, Ix4, Ix5, Ix6, IxDyn, IxDynImpl, }; diff --git a/src/impl_methods.rs b/src/impl_methods.rs index 4fbfcd98a..03dc5efce 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -10,7 +10,6 @@ use std::cmp; use std::ptr as std_ptr; use std::slice; -use itertools::{izip, zip}; use rawpointer::PointerExt; use crate::imp_prelude::*; @@ -22,6 +21,7 @@ use crate::dimension::{ abs_index, axes_of, do_slice, merge_axes, size_of_shape_checked, stride_offset, Axes, }; use crate::error::{self, ErrorKind, ShapeError}; +use crate::itertools::zip; use crate::zip::Zip; use crate::iter::{ diff --git a/src/itertools.rs b/src/itertools.rs new file mode 100644 index 000000000..96732f903 --- /dev/null +++ b/src/itertools.rs @@ -0,0 +1,129 @@ +// Copyright 2014-2019 bluss and ndarray developers +// and MichaƂ Krasnoborski (krdln) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A few iterator-related utilities and tools + +use std::iter; + +/// Iterate `iterable` with a running index. +/// +/// `IntoIterator` enabled version of `.enumerate()`. +/// +/// ``` +/// use itertools::enumerate; +/// +/// for (i, elt) in enumerate(&[1, 2, 3]) { +/// /* loop body */ +/// } +/// ``` +pub(crate) fn enumerate(iterable: I) -> iter::Enumerate +where + I: IntoIterator, +{ + iterable.into_iter().enumerate() +} + +/// Iterate `i` and `j` in lock step. +/// +/// `IntoIterator` enabled version of `i.zip(j)`. +/// +/// ``` +/// use itertools::zip; +/// +/// let data = [1, 2, 3, 4, 5]; +/// for (a, b) in zip(&data, &data[1..]) { +/// /* loop body */ +/// } +/// ``` +pub(crate) fn zip(i: I, j: J) -> iter::Zip +where + I: IntoIterator, + J: IntoIterator, +{ + i.into_iter().zip(j) +} + +/// Create an iterator running multiple iterators in lockstep. +/// +/// The `izip!` iterator yields elements until any subiterator +/// returns `None`. +/// +/// This is a version of the standard ``.zip()`` that's supporting more than +/// two iterators. The iterator element type is a tuple with one element +/// from each of the input iterators. Just like ``.zip()``, the iteration stops +/// when the shortest of the inputs reaches its end. +/// +/// **Note:** The result of this macro is in the general case an iterator +/// composed of repeated `.zip()` and a `.map()`; it has an anonymous type. +/// The special cases of one and two arguments produce the equivalent of +/// `$a.into_iter()` and `$a.into_iter().zip($b)` respectively. +/// +/// Prefer this macro `izip!()` over [`multizip`] for the performance benefits +/// of using the standard library `.zip()`. +/// +/// [`multizip`]: fn.multizip.html +/// +/// ``` +/// #[macro_use] extern crate itertools; +/// # fn main() { +/// +/// // iterate over three sequences side-by-side +/// let mut results = [0, 0, 0, 0]; +/// let inputs = [3, 7, 9, 6]; +/// +/// for (r, index, input) in izip!(&mut results, 0..10, &inputs) { +/// *r = index * 10 + input; +/// } +/// +/// assert_eq!(results, [0 + 3, 10 + 7, 29, 36]); +/// # } +/// ``` +/// +/// **Note:** To enable the macros in this crate, use the `#[macro_use]` +/// attribute when importing the crate: +/// +/// ``` +/// #[macro_use] extern crate itertools; +/// # fn main() { } +/// ``` +macro_rules! izip { + // @closure creates a tuple-flattening closure for .map() call. usage: + // @closure partial_pattern => partial_tuple , rest , of , iterators + // eg. izip!( @closure ((a, b), c) => (a, b, c) , dd , ee ) + ( @closure $p:pat => $tup:expr ) => { + |$p| $tup + }; + + // The "b" identifier is a different identifier on each recursion level thanks to hygiene. + ( @closure $p:pat => ( $($tup:tt)* ) , $_iter:expr $( , $tail:expr )* ) => { + izip!(@closure ($p, b) => ( $($tup)*, b ) $( , $tail )*) + }; + + // unary + ($first:expr $(,)*) => { + IntoIterator::into_iter($first) + }; + + // binary + ($first:expr, $second:expr $(,)*) => { + izip!($first) + .zip($second) + }; + + // n-ary where n > 2 + ( $first:expr $( , $rest:expr )* $(,)* ) => { + izip!($first) + $( + .zip($rest) + )* + .map( + izip!(@closure a => (a) $( , $rest )*) + ) + }; +} diff --git a/src/layout/layoutfmt.rs b/src/layout/layoutfmt.rs index 02afebd1b..cb799ca81 100644 --- a/src/layout/layoutfmt.rs +++ b/src/layout/layoutfmt.rs @@ -8,7 +8,6 @@ use super::Layout; use super::LayoutPriv; -use itertools::Itertools; const LAYOUT_NAMES: &[&str] = &["C", "F"]; @@ -17,20 +16,16 @@ use std::fmt; impl fmt::Debug for Layout { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if self.0 == 0 { - write!(f, "Custom") + write!(f, "Custom")? } else { - write!( - f, - "{}", - (0..32) - .filter(|&i| self.is(1 << i)) - .format_with(" | ", |i, f| if let Some(name) = LAYOUT_NAMES.get(i) { - f(name) - } else { - f(&format_args!("0x{:x}", i)) - }) - ) - }?; + (0..32).filter(|&i| self.is(1 << i)).try_fold((), |_, i| { + if let Some(name) = LAYOUT_NAMES.get(i) { + write!(f, "{}", name) + } else { + write!(f, "{:#x}", i) + } + })?; + }; write!(f, " ({:#x})", self.0) } } diff --git a/src/lib.rs b/src/lib.rs index 9a027aced..1390655c1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -141,6 +141,8 @@ mod macro_utils; #[macro_use] mod private; mod aliases; +#[macro_use] +mod itertools; #[cfg(feature = "approx")] mod array_approx; #[cfg(feature = "serde")] diff --git a/src/numeric/impl_numeric.rs b/src/numeric/impl_numeric.rs index 28ada793c..85f69444d 100644 --- a/src/numeric/impl_numeric.rs +++ b/src/numeric/impl_numeric.rs @@ -6,11 +6,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use itertools::free::enumerate; use num_traits::{self, Float, FromPrimitive, Zero}; use std::ops::{Add, Div, Mul}; use crate::imp_prelude::*; +use crate::itertools::enumerate; use crate::numeric_util; use crate::{FoldWhile, Zip};