#![cfg_attr(not(any(test, feature = "std")), no_std)]
#[cfg(doc)]
use core::iter::{Product, Sum};
use core::{
cell::RefCell,
iter::FusedIterator,
ops::{Add, Mul},
};
use num_traits::{One, Zero};
pub trait IteratorILP: Iterator + Sized + TrustedLowerBound {
#[inline]
fn any_ilp<const STREAMS: usize>(self, mut predicate: impl FnMut(Self::Item) -> bool) -> bool {
assert_ne!(STREAMS, 0, "Need at least one stream to make progress");
self.find_map_ilp::<STREAMS, _>(|item| predicate(item).then_some(true))
.unwrap_or(false)
}
#[inline]
fn all_ilp<const STREAMS: usize>(self, mut predicate: impl FnMut(Self::Item) -> bool) -> bool {
assert_ne!(STREAMS, 0, "Need at least one stream to make progress");
self.find_map_ilp::<STREAMS, _>(|item| (!predicate(item)).then_some(false))
.unwrap_or(true)
}
#[inline]
fn find_ilp<const STREAMS: usize>(
self,
mut predicate: impl FnMut(&Self::Item) -> bool,
) -> Option<Self::Item> {
assert_ne!(STREAMS, 0, "Need at least one stream to make progress");
let mut iter = self.map(|item| predicate(&item).then_some(item));
let stream_len = iter.size_hint().0 / STREAMS;
for _ in 0..stream_len {
let item_opts: [Option<Self::Item>; STREAMS] =
core::array::from_fn(|_| unsafe { iter.next().unwrap_unchecked() });
if let Some(item) = item_opts.into_iter().flatten().next() {
return Some(item);
}
}
iter.flatten().next()
}
#[inline]
fn find_map_ilp<const STREAMS: usize, Res>(
self,
f: impl FnMut(Self::Item) -> Option<Res>,
) -> Option<Res> {
assert_ne!(STREAMS, 0, "Need at least one stream to make progress");
self.map(f)
.find_ilp::<STREAMS>(|res| res.is_some())
.flatten()
}
#[inline]
fn position_ilp<const STREAMS: usize>(
self,
mut predicate: impl FnMut(Self::Item) -> bool,
) -> Option<usize> {
assert_ne!(STREAMS, 0, "Need at least one stream to make progress");
self.enumerate()
.find_map_ilp::<STREAMS, _>(|(idx, elem)| predicate(elem).then_some(idx))
}
#[inline]
fn rposition_ilp<const STREAMS: usize>(
self,
mut predicate: impl FnMut(Self::Item) -> bool,
) -> Option<usize>
where
Self: DoubleEndedIterator + ExactSizeIterator,
{
assert_ne!(STREAMS, 0, "Need at least one stream to make progress");
self.enumerate()
.rev()
.find_map_ilp::<STREAMS, _>(|(idx, elem)| predicate(elem).then_some(idx))
}
#[inline]
fn fold_ilp<const STREAMS: usize, Acc>(
mut self,
mut neutral: impl FnMut() -> Acc,
mut accumulate: impl FnMut(Acc, Self::Item) -> Acc,
mut merge: impl FnMut(Acc, Acc) -> Acc,
) -> Acc {
assert_ne!(STREAMS, 0, "Need at least one stream to make progress");
let mut accumulators: [Option<Acc>; STREAMS] = core::array::from_fn(|_| Some(neutral()));
let mut accumulate_opt = |accumulator: &mut Option<Acc>, item| {
if let Some(prev_acc) = accumulator.take() {
*accumulator = Some(accumulate(prev_acc, item));
}
};
let stream_len = self.size_hint().0 / STREAMS;
for _ in 0..stream_len {
for acc in &mut accumulators {
accumulate_opt(acc, unsafe { self.next().unwrap_unchecked() });
}
}
let mut stride = if STREAMS.is_power_of_two() {
STREAMS
} else {
STREAMS.next_power_of_two()
};
while stride > 1 {
stride /= 2;
for i in 0..stride.min(STREAMS - stride) {
accumulators[i] = Some(merge(
accumulators[i].take().unwrap(),
accumulators[i + stride].take().unwrap(),
));
}
}
let ilp_result = accumulators[0].take().unwrap();
merge(ilp_result, self.fold(neutral(), accumulate))
}
#[inline]
fn reduce_ilp<const STREAMS: usize>(
self,
reduce: impl FnMut(Self::Item, Self::Item) -> Self::Item,
) -> Option<Self::Item> {
assert_ne!(STREAMS, 0, "Need at least one stream to make progress");
let reduce = RefCell::new(reduce);
self.fold_ilp::<STREAMS, _>(
|| None,
|acc_opt, item| {
Some(if let Some(acc) = acc_opt {
reduce.borrow_mut()(acc, item)
} else {
item
})
},
|acc_opt_1, acc_opt_2| match (acc_opt_1, acc_opt_2) {
(Some(a), Some(b)) => Some(reduce.borrow_mut()(a, b)),
(Some(a), _) | (_, Some(a)) => Some(a),
(None, None) => None,
},
)
}
#[inline(always)]
fn sum_ilp<const STREAMS: usize, S: Add<Self::Item, Output = S> + Add<S> + Zero>(self) -> S {
assert_ne!(STREAMS, 0, "Need at least one stream to make progress");
self.fold_ilp::<STREAMS, _>(|| S::zero(), |acc, it| acc + it, |acc1, acc2| acc1 + acc2)
}
#[inline]
fn product_ilp<const STREAMS: usize, P: Mul<Self::Item, Output = P> + Mul<P> + One>(self) -> P {
assert_ne!(STREAMS, 0, "Need at least one stream to make progress");
self.fold_ilp::<STREAMS, _>(|| P::one(), |acc, it| acc * it, |acc1, acc2| acc1 * acc2)
}
}
impl<I: Iterator + Sized + TrustedLowerBound> IteratorILP for I {}
pub unsafe trait TrustedLowerBound: Iterator {}
mod core_iters {
use crate::TrustedLowerBound;
use core::{
iter::{
Chain, Cloned, Copied, Cycle, Empty, Enumerate, Filter, FilterMap, FlatMap, Flatten,
FromFn, Fuse, Inspect, Map, MapWhile, Once, OnceWith, Peekable, Repeat, RepeatWith,
Rev, Scan, Skip, SkipWhile, StepBy, Successors, Take, TakeWhile, Zip,
},
ops::{Range, RangeFrom, RangeInclusive},
str::{CharIndices, Chars, EncodeUtf16, SplitAsciiWhitespace, SplitWhitespace},
};
unsafe impl<I> TrustedLowerBound for &mut I where I: TrustedLowerBound + ?Sized {}
unsafe impl<A, B> TrustedLowerBound for Chain<A, B>
where
A: TrustedLowerBound,
B: TrustedLowerBound<Item = <A as Iterator>::Item>,
{
}
unsafe impl TrustedLowerBound for CharIndices<'_> {}
unsafe impl TrustedLowerBound for Chars<'_> {}
unsafe impl<'a, I, T> TrustedLowerBound for Cloned<I>
where
I: TrustedLowerBound<Item = &'a T>,
T: 'a + Clone,
{
}
unsafe impl<'a, I, T> TrustedLowerBound for Copied<I>
where
I: TrustedLowerBound<Item = &'a T>,
T: 'a + Copy,
{
}
unsafe impl<I> TrustedLowerBound for Cycle<I> where I: TrustedLowerBound + Clone {}
unsafe impl<T> TrustedLowerBound for Empty<T> {}
unsafe impl TrustedLowerBound for EncodeUtf16<'_> {}
unsafe impl<I> TrustedLowerBound for Enumerate<I> where I: TrustedLowerBound {}
unsafe impl<I, P> TrustedLowerBound for Filter<I, P>
where
I: TrustedLowerBound,
P: FnMut(&<I as Iterator>::Item) -> bool,
{
}
unsafe impl<B, I, F> TrustedLowerBound for FilterMap<I, F>
where
F: FnMut(<I as Iterator>::Item) -> Option<B>,
I: TrustedLowerBound,
{
}
unsafe impl<I, U> TrustedLowerBound for Flatten<I>
where
I: TrustedLowerBound,
<I as Iterator>::Item: IntoIterator<IntoIter = U, Item = <U as Iterator>::Item>,
U: TrustedLowerBound,
{
}
unsafe impl<I, U, F> TrustedLowerBound for FlatMap<I, U, F>
where
I: TrustedLowerBound,
U: IntoIterator,
<U as IntoIterator>::IntoIter: TrustedLowerBound,
F: FnMut(<I as Iterator>::Item) -> U,
{
}
unsafe impl<T, F> TrustedLowerBound for FromFn<F> where F: FnMut() -> Option<T> {}
unsafe impl<I> TrustedLowerBound for Fuse<I> where I: TrustedLowerBound {}
unsafe impl<I, F> TrustedLowerBound for Inspect<I, F>
where
I: TrustedLowerBound,
F: FnMut(&<I as Iterator>::Item),
{
}
unsafe impl<B, I, F> TrustedLowerBound for Map<I, F>
where
F: FnMut(<I as Iterator>::Item) -> B,
I: TrustedLowerBound,
{
}
unsafe impl<B, I, F> TrustedLowerBound for MapWhile<I, F>
where
F: FnMut(<I as Iterator>::Item) -> Option<B>,
I: TrustedLowerBound,
{
}
unsafe impl<T> TrustedLowerBound for Once<T> {}
unsafe impl<A, F> TrustedLowerBound for OnceWith<F> where F: FnOnce() -> A {}
unsafe impl<I> TrustedLowerBound for Peekable<I> where I: TrustedLowerBound {}
unsafe impl TrustedLowerBound for Range<usize> {}
unsafe impl TrustedLowerBound for Range<isize> {}
unsafe impl TrustedLowerBound for Range<u8> {}
unsafe impl TrustedLowerBound for Range<i8> {}
unsafe impl TrustedLowerBound for Range<u16> {}
unsafe impl TrustedLowerBound for Range<i16> {}
unsafe impl TrustedLowerBound for Range<u32> {}
unsafe impl TrustedLowerBound for Range<i32> {}
unsafe impl TrustedLowerBound for Range<i64> {}
unsafe impl TrustedLowerBound for Range<u64> {}
unsafe impl TrustedLowerBound for RangeFrom<usize> {}
unsafe impl TrustedLowerBound for RangeFrom<isize> {}
unsafe impl TrustedLowerBound for RangeFrom<u8> {}
unsafe impl TrustedLowerBound for RangeFrom<i8> {}
unsafe impl TrustedLowerBound for RangeFrom<u16> {}
unsafe impl TrustedLowerBound for RangeFrom<i16> {}
unsafe impl TrustedLowerBound for RangeFrom<u32> {}
unsafe impl TrustedLowerBound for RangeFrom<i32> {}
unsafe impl TrustedLowerBound for RangeFrom<i64> {}
unsafe impl TrustedLowerBound for RangeFrom<u64> {}
unsafe impl TrustedLowerBound for RangeInclusive<usize> {}
unsafe impl TrustedLowerBound for RangeInclusive<isize> {}
unsafe impl TrustedLowerBound for RangeInclusive<u8> {}
unsafe impl TrustedLowerBound for RangeInclusive<i8> {}
unsafe impl TrustedLowerBound for RangeInclusive<u16> {}
unsafe impl TrustedLowerBound for RangeInclusive<i16> {}
unsafe impl TrustedLowerBound for RangeInclusive<u32> {}
unsafe impl TrustedLowerBound for RangeInclusive<i32> {}
unsafe impl TrustedLowerBound for RangeInclusive<i64> {}
unsafe impl TrustedLowerBound for RangeInclusive<u64> {}
unsafe impl<A: Clone> TrustedLowerBound for Repeat<A> {}
unsafe impl<A, F> TrustedLowerBound for RepeatWith<F> where F: FnMut() -> A {}
unsafe impl<I> TrustedLowerBound for Rev<I> where I: TrustedLowerBound + DoubleEndedIterator {}
unsafe impl<B, I, St, F> TrustedLowerBound for Scan<I, St, F>
where
F: FnMut(&mut St, <I as Iterator>::Item) -> Option<B>,
I: TrustedLowerBound,
{
}
unsafe impl<I> TrustedLowerBound for Skip<I> where I: TrustedLowerBound {}
unsafe impl<I, P> TrustedLowerBound for SkipWhile<I, P>
where
I: TrustedLowerBound,
P: FnMut(&<I as Iterator>::Item) -> bool,
{
}
unsafe impl TrustedLowerBound for SplitAsciiWhitespace<'_> {}
unsafe impl TrustedLowerBound for SplitWhitespace<'_> {}
unsafe impl<I> TrustedLowerBound for StepBy<I> where I: TrustedLowerBound {}
unsafe impl<T, F> TrustedLowerBound for Successors<T, F> where F: FnMut(&T) -> Option<T> {}
unsafe impl<I> TrustedLowerBound for Take<I> where I: TrustedLowerBound {}
unsafe impl<I, P> TrustedLowerBound for TakeWhile<I, P>
where
I: TrustedLowerBound,
P: FnMut(&<I as Iterator>::Item) -> bool,
{
}
unsafe impl<A, B> TrustedLowerBound for Zip<A, B>
where
A: TrustedLowerBound,
B: TrustedLowerBound,
{
}
unsafe impl<T, const N: usize> TrustedLowerBound for core::array::IntoIter<T, N> {}
unsafe impl TrustedLowerBound for core::ascii::EscapeDefault {}
unsafe impl<I> TrustedLowerBound for core::char::DecodeUtf16<I> where
I: TrustedLowerBound<Item = u16>
{
}
unsafe impl TrustedLowerBound for core::char::EscapeDebug {}
unsafe impl TrustedLowerBound for core::char::EscapeDefault {}
unsafe impl TrustedLowerBound for core::char::EscapeUnicode {}
unsafe impl TrustedLowerBound for core::char::ToLowercase {}
unsafe impl TrustedLowerBound for core::char::ToUppercase {}
unsafe impl<A> TrustedLowerBound for core::option::Iter<'_, A> {}
unsafe impl<A> TrustedLowerBound for core::option::IterMut<'_, A> {}
unsafe impl<A> TrustedLowerBound for core::option::IntoIter<A> {}
unsafe impl<A> TrustedLowerBound for core::result::Iter<'_, A> {}
unsafe impl<A> TrustedLowerBound for core::result::IterMut<'_, A> {}
unsafe impl<A> TrustedLowerBound for core::result::IntoIter<A> {}
unsafe impl<T> TrustedLowerBound for core::slice::Chunks<'_, T> {}
unsafe impl<T> TrustedLowerBound for core::slice::ChunksExact<'_, T> {}
unsafe impl<T> TrustedLowerBound for core::slice::ChunksExactMut<'_, T> {}
unsafe impl<T> TrustedLowerBound for core::slice::ChunksMut<'_, T> {}
unsafe impl TrustedLowerBound for core::slice::EscapeAscii<'_> {}
unsafe impl<T> TrustedLowerBound for core::slice::Iter<'_, T> {}
unsafe impl<T> TrustedLowerBound for core::slice::IterMut<'_, T> {}
unsafe impl<T> TrustedLowerBound for core::slice::RChunks<'_, T> {}
unsafe impl<T> TrustedLowerBound for core::slice::RChunksExact<'_, T> {}
unsafe impl<T> TrustedLowerBound for core::slice::RChunksExactMut<'_, T> {}
unsafe impl<T> TrustedLowerBound for core::slice::RChunksMut<'_, T> {}
unsafe impl<T, P> TrustedLowerBound for core::slice::RSplit<'_, T, P> where P: FnMut(&T) -> bool {}
unsafe impl<T, P> TrustedLowerBound for core::slice::RSplitMut<'_, T, P> where P: FnMut(&T) -> bool {}
unsafe impl<T, P> TrustedLowerBound for core::slice::RSplitN<'_, T, P> where P: FnMut(&T) -> bool {}
unsafe impl<T, P> TrustedLowerBound for core::slice::RSplitNMut<'_, T, P> where P: FnMut(&T) -> bool {}
unsafe impl<T, P> TrustedLowerBound for core::slice::Split<'_, T, P> where P: FnMut(&T) -> bool {}
unsafe impl<T, P> TrustedLowerBound for core::slice::SplitInclusive<'_, T, P> where
P: FnMut(&T) -> bool
{
}
unsafe impl<T, P> TrustedLowerBound for core::slice::SplitInclusiveMut<'_, T, P> where
P: FnMut(&T) -> bool
{
}
unsafe impl<T, P> TrustedLowerBound for core::slice::SplitMut<'_, T, P> where P: FnMut(&T) -> bool {}
unsafe impl<T, P> TrustedLowerBound for core::slice::SplitN<'_, T, P> where P: FnMut(&T) -> bool {}
unsafe impl<T, P> TrustedLowerBound for core::slice::SplitNMut<'_, T, P> where P: FnMut(&T) -> bool {}
unsafe impl<T> TrustedLowerBound for core::slice::Windows<'_, T> {}
unsafe impl TrustedLowerBound for core::str::Bytes<'_> {}
unsafe impl TrustedLowerBound for core::str::EscapeDebug<'_> {}
unsafe impl TrustedLowerBound for core::str::EscapeDefault<'_> {}
unsafe impl TrustedLowerBound for core::str::EscapeUnicode<'_> {}
unsafe impl TrustedLowerBound for core::str::Lines<'_> {}
#[cfg(feature = "std")]
mod std {
use crate::TrustedLowerBound;
use core::hash::{BuildHasher, Hash};
use std::{
env::{Args, ArgsOs, SplitPaths, Vars, VarsOs},
fs::ReadDir,
io::{BufRead, Read},
path::{Ancestors, Components},
process::{CommandArgs, CommandEnvs},
sync::mpsc::TryIter,
vec::Splice,
};
unsafe impl TrustedLowerBound for Ancestors<'_> {}
unsafe impl TrustedLowerBound for Args {}
unsafe impl TrustedLowerBound for ArgsOs {}
unsafe impl<I> TrustedLowerBound for Box<I> where I: TrustedLowerBound {}
unsafe impl TrustedLowerBound for CommandArgs<'_> {}
unsafe impl TrustedLowerBound for CommandEnvs<'_> {}
unsafe impl TrustedLowerBound for Components<'_> {}
unsafe impl TrustedLowerBound for ReadDir {}
unsafe impl<I> TrustedLowerBound for Splice<'_, I> where I: TrustedLowerBound {}
unsafe impl TrustedLowerBound for SplitPaths<'_> {}
unsafe impl<T> TrustedLowerBound for TryIter<'_, T> {}
unsafe impl TrustedLowerBound for Vars {}
unsafe impl TrustedLowerBound for VarsOs {}
unsafe impl<T> TrustedLowerBound for std::collections::binary_heap::Drain<'_, T> {}
unsafe impl<T> TrustedLowerBound for std::collections::binary_heap::Iter<'_, T> {}
unsafe impl<T> TrustedLowerBound for std::collections::binary_heap::IntoIter<T> {}
unsafe impl<K, V> TrustedLowerBound for std::collections::btree_map::IntoIter<K, V> {}
unsafe impl<K, V> TrustedLowerBound for std::collections::btree_map::IntoKeys<K, V> {}
unsafe impl<K, V> TrustedLowerBound for std::collections::btree_map::IntoValues<K, V> {}
unsafe impl<K, V> TrustedLowerBound for std::collections::btree_map::Iter<'_, K, V> {}
unsafe impl<K, V> TrustedLowerBound for std::collections::btree_map::IterMut<'_, K, V> {}
unsafe impl<K, V> TrustedLowerBound for std::collections::btree_map::Keys<'_, K, V> {}
unsafe impl<K, V> TrustedLowerBound for std::collections::btree_map::Range<'_, K, V> {}
unsafe impl<K, V> TrustedLowerBound for std::collections::btree_map::RangeMut<'_, K, V> {}
unsafe impl<K, V> TrustedLowerBound for std::collections::btree_map::Values<'_, K, V> {}
unsafe impl<K, V> TrustedLowerBound for std::collections::btree_map::ValuesMut<'_, K, V> {}
unsafe impl<T> TrustedLowerBound for std::collections::btree_set::IntoIter<T> {}
unsafe impl<T> TrustedLowerBound for std::collections::btree_set::Iter<'_, T> {}
unsafe impl<T> TrustedLowerBound for std::collections::btree_set::Range<'_, T> {}
unsafe impl<T: Ord> TrustedLowerBound for std::collections::btree_set::SymmetricDifference<'_, T> {}
unsafe impl<T: Ord> TrustedLowerBound for std::collections::btree_set::Union<'_, T> {}
unsafe impl<K, V> TrustedLowerBound for std::collections::hash_map::Drain<'_, K, V> {}
unsafe impl<K, V> TrustedLowerBound for std::collections::hash_map::IntoIter<K, V> {}
unsafe impl<K, V> TrustedLowerBound for std::collections::hash_map::IntoKeys<K, V> {}
unsafe impl<K, V> TrustedLowerBound for std::collections::hash_map::IntoValues<K, V> {}
unsafe impl<K, V> TrustedLowerBound for std::collections::hash_map::Iter<'_, K, V> {}
unsafe impl<K, V> TrustedLowerBound for std::collections::hash_map::IterMut<'_, K, V> {}
unsafe impl<K, V> TrustedLowerBound for std::collections::hash_map::Keys<'_, K, V> {}
unsafe impl<K, V> TrustedLowerBound for std::collections::hash_map::Values<'_, K, V> {}
unsafe impl<K, V> TrustedLowerBound for std::collections::hash_map::ValuesMut<'_, K, V> {}
unsafe impl<T, S> TrustedLowerBound for std::collections::hash_set::Difference<'_, T, S>
where
T: Eq + Hash,
S: BuildHasher,
{
}
unsafe impl<T, S> TrustedLowerBound for std::collections::hash_set::Intersection<'_, T, S>
where
T: Eq + Hash,
S: BuildHasher,
{
}
unsafe impl<T, S> TrustedLowerBound for std::collections::hash_set::SymmetricDifference<'_, T, S>
where
T: Eq + Hash,
S: BuildHasher,
{
}
unsafe impl<T, S> TrustedLowerBound for std::collections::hash_set::Union<'_, T, S>
where
T: Eq + Hash,
S: BuildHasher,
{
}
unsafe impl<K> TrustedLowerBound for std::collections::hash_set::Drain<'_, K> {}
unsafe impl<K> TrustedLowerBound for std::collections::hash_set::IntoIter<K> {}
unsafe impl<K> TrustedLowerBound for std::collections::hash_set::Iter<'_, K> {}
unsafe impl<T> TrustedLowerBound for std::collections::linked_list::IntoIter<T> {}
unsafe impl<T> TrustedLowerBound for std::collections::linked_list::Iter<'_, T> {}
unsafe impl<T> TrustedLowerBound for std::collections::linked_list::IterMut<'_, T> {}
unsafe impl<T> TrustedLowerBound for std::collections::vec_deque::Drain<'_, T> {}
unsafe impl<T> TrustedLowerBound for std::collections::vec_deque::IntoIter<T> {}
unsafe impl<T> TrustedLowerBound for std::collections::vec_deque::Iter<'_, T> {}
unsafe impl<T> TrustedLowerBound for std::collections::vec_deque::IterMut<'_, T> {}
unsafe impl<R: Read> TrustedLowerBound for std::io::Bytes<R> {}
unsafe impl<B: BufRead> TrustedLowerBound for std::io::Lines<B> {}
unsafe impl<B: BufRead> TrustedLowerBound for std::io::Split<B> {}
unsafe impl TrustedLowerBound for std::string::Drain<'_> {}
unsafe impl TrustedLowerBound for std::net::Incoming<'_> {}
unsafe impl TrustedLowerBound for std::path::Iter<'_> {}
unsafe impl<T> TrustedLowerBound for std::sync::mpsc::IntoIter<T> {}
unsafe impl<T> TrustedLowerBound for std::sync::mpsc::Iter<'_, T> {}
unsafe impl<T> TrustedLowerBound for std::vec::Drain<'_, T> {}
unsafe impl<T> TrustedLowerBound for std::vec::IntoIter<T> {}
#[cfg(target_os = "windows")]
mod windows {
use crate::TrustedLowerBound;
use std::os::windows::ffi::EncodeWide;
unsafe impl TrustedLowerBound for EncodeWide<'_> {}
}
}
}
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct AssertLowerBoundOk<I: Iterator>(I);
impl<I: Iterator> AssertLowerBoundOk<I> {
#[inline]
pub unsafe fn new(inner: I) -> Self {
Self(inner)
}
}
impl<I: DoubleEndedIterator> DoubleEndedIterator for AssertLowerBoundOk<I> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
self.0.next_back()
}
#[inline]
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
self.0.nth_back(n)
}
}
impl<I: ExactSizeIterator> ExactSizeIterator for AssertLowerBoundOk<I> {
#[inline]
fn len(&self) -> usize {
self.0.len()
}
}
impl<I: FusedIterator> FusedIterator for AssertLowerBoundOk<I> {}
impl<I: Iterator> Iterator for AssertLowerBoundOk<I> {
type Item = I::Item;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
#[inline]
fn count(self) -> usize
where
I: Sized,
{
self.0.count()
}
#[inline]
fn last(self) -> Option<Self::Item>
where
I: Sized,
{
self.0.last()
}
#[inline]
fn nth(&mut self, n: usize) -> Option<Self::Item> {
self.0.nth(n)
}
}
unsafe impl<I: Iterator> TrustedLowerBound for AssertLowerBoundOk<I> {}
#[cfg(test)]
mod tests {
use super::*;
use proptest::prelude::*;
use static_assertions::assert_impl_all;
assert_impl_all!(
std::slice::Iter<'static, u32>: FusedIterator, TrustedLowerBound
);
proptest! {
#[test]
fn assert_lower_bound_basic(data: Vec<u8>) {
let raw = data.iter();
let iter = unsafe { AssertLowerBoundOk::new(raw.clone()) };
assert_eq!(iter.size_hint(), raw.size_hint());
assert_eq!(iter.len(), raw.len());
assert_eq!(iter.clone().count(), raw.clone().count());
assert_eq!(iter.clone().next(), raw.clone().next());
assert_eq!(iter.clone().next_back(), raw.clone().next_back());
assert_eq!(iter.clone().last(), raw.clone().last());
}
#[test]
fn assert_lower_bound_strided(data: Vec<u8>, stride: usize) {
let raw = data.iter();
let iter = unsafe { AssertLowerBoundOk::new(raw.clone()) };
assert_eq!(iter.clone().nth(stride), raw.clone().nth(stride));
assert_eq!(iter.clone().nth_back(stride), raw.clone().nth_back(stride));
}
#[test]
fn any(dataset: Vec<u8>, needle: u8) {
let predicate = |&item| item == needle;
let expected = dataset.iter().any(predicate);
prop_assert_eq!(dataset.iter().any_ilp::<1>(predicate), expected);
prop_assert_eq!(dataset.iter().any_ilp::<2>(predicate), expected);
prop_assert_eq!(dataset.iter().any_ilp::<3>(predicate), expected);
prop_assert_eq!(dataset.iter().any_ilp::<4>(predicate), expected);
prop_assert_eq!(dataset.iter().any_ilp::<5>(predicate), expected);
prop_assert_eq!(dataset.iter().any_ilp::<6>(predicate), expected);
}
#[test]
fn all(dataset: Vec<u8>, needle: u8) {
let predicate = |&item| item == needle;
let expected = dataset.iter().all(predicate);
prop_assert_eq!(dataset.iter().all_ilp::<1>(predicate), expected);
prop_assert_eq!(dataset.iter().all_ilp::<2>(predicate), expected);
prop_assert_eq!(dataset.iter().all_ilp::<3>(predicate), expected);
prop_assert_eq!(dataset.iter().all_ilp::<4>(predicate), expected);
prop_assert_eq!(dataset.iter().all_ilp::<5>(predicate), expected);
prop_assert_eq!(dataset.iter().all_ilp::<6>(predicate), expected);
}
#[test]
fn find(dataset: Vec<u8>, needle: u8) {
let predicate = |item: &&u8| **item == needle;
let expected = dataset.iter().find(predicate);
prop_assert_eq!(dataset.iter().find_ilp::<1>(predicate), expected);
prop_assert_eq!(dataset.iter().find_ilp::<2>(predicate), expected);
prop_assert_eq!(dataset.iter().find_ilp::<3>(predicate), expected);
prop_assert_eq!(dataset.iter().find_ilp::<4>(predicate), expected);
prop_assert_eq!(dataset.iter().find_ilp::<5>(predicate), expected);
prop_assert_eq!(dataset.iter().find_ilp::<6>(predicate), expected);
}
#[test]
fn find_map(dataset: Vec<u8>, needle: u8) {
let find_map = |item: &u8| (*item == needle).then_some(42);
let expected = dataset.iter().find_map(find_map);
prop_assert_eq!(dataset.iter().find_map_ilp::<1, _>(find_map), expected);
prop_assert_eq!(dataset.iter().find_map_ilp::<2, _>(find_map), expected);
prop_assert_eq!(dataset.iter().find_map_ilp::<3, _>(find_map), expected);
prop_assert_eq!(dataset.iter().find_map_ilp::<4, _>(find_map), expected);
prop_assert_eq!(dataset.iter().find_map_ilp::<5, _>(find_map), expected);
prop_assert_eq!(dataset.iter().find_map_ilp::<6, _>(find_map), expected);
}
#[test]
fn position(dataset: Vec<u8>, needle: u8) {
let predicate = |item: &u8| *item == needle;
let expected = dataset.iter().position(predicate);
prop_assert_eq!(dataset.iter().position_ilp::<1>(predicate), expected);
prop_assert_eq!(dataset.iter().position_ilp::<2>(predicate), expected);
prop_assert_eq!(dataset.iter().position_ilp::<3>(predicate), expected);
prop_assert_eq!(dataset.iter().position_ilp::<4>(predicate), expected);
prop_assert_eq!(dataset.iter().position_ilp::<5>(predicate), expected);
prop_assert_eq!(dataset.iter().position_ilp::<6>(predicate), expected);
}
#[test]
fn rposition(dataset: Vec<u8>, needle: u8) {
let predicate = |item: &u8| *item == needle;
let expected = dataset.iter().rposition(predicate);
prop_assert_eq!(dataset.iter().rposition_ilp::<1>(predicate), expected);
prop_assert_eq!(dataset.iter().rposition_ilp::<2>(predicate), expected);
prop_assert_eq!(dataset.iter().rposition_ilp::<3>(predicate), expected);
prop_assert_eq!(dataset.iter().rposition_ilp::<4>(predicate), expected);
prop_assert_eq!(dataset.iter().rposition_ilp::<5>(predicate), expected);
prop_assert_eq!(dataset.iter().rposition_ilp::<6>(predicate), expected);
}
#[test]
fn fold(dataset: Vec<u8>) {
let zero = || 0;
let accumulate = |a, &b| a + b as u64;
let merge = |a, b| a + b;
let expected = dataset.iter().fold(zero(), accumulate);
prop_assert_eq!(
dataset.iter().fold_ilp::<1, _>(zero, accumulate, merge),
expected
);
prop_assert_eq!(
dataset.iter().fold_ilp::<2, _>(zero, accumulate, merge),
expected
);
prop_assert_eq!(
dataset.iter().fold_ilp::<3, _>(zero, accumulate, merge),
expected
);
prop_assert_eq!(
dataset.iter().fold_ilp::<4, _>(zero, accumulate, merge),
expected
);
prop_assert_eq!(
dataset.iter().fold_ilp::<5, _>(zero, accumulate, merge),
expected
);
prop_assert_eq!(
dataset.iter().fold_ilp::<6, _>(zero, accumulate, merge),
expected
);
}
#[test]
fn reduce(dataset: Vec<u64>) {
let reduce = |a: u64, b| a.wrapping_add(b);
let expected = dataset.iter().copied().reduce(reduce);
prop_assert_eq!(dataset.iter().copied().reduce_ilp::<1>(reduce), expected);
prop_assert_eq!(dataset.iter().copied().reduce_ilp::<2>(reduce), expected);
prop_assert_eq!(dataset.iter().copied().reduce_ilp::<3>(reduce), expected);
prop_assert_eq!(dataset.iter().copied().reduce_ilp::<4>(reduce), expected);
prop_assert_eq!(dataset.iter().copied().reduce_ilp::<5>(reduce), expected);
prop_assert_eq!(dataset.iter().copied().reduce_ilp::<6>(reduce), expected);
}
#[test]
fn sum(dataset: Vec<u8>) {
let dataset = dataset.into_iter().map(|i| i as u64).collect::<Vec<_>>();
let expected = dataset.iter().copied().sum::<u64>();
prop_assert_eq!(dataset.iter().copied().sum_ilp::<1, u64>(), expected);
prop_assert_eq!(dataset.iter().copied().sum_ilp::<2, u64>(), expected);
prop_assert_eq!(dataset.iter().copied().sum_ilp::<3, u64>(), expected);
prop_assert_eq!(dataset.iter().copied().sum_ilp::<4, u64>(), expected);
prop_assert_eq!(dataset.iter().copied().sum_ilp::<5, u64>(), expected);
prop_assert_eq!(dataset.iter().copied().sum_ilp::<6, u64>(), expected);
}
#[test]
fn product(dataset: Vec<u8>) {
let dataset = dataset
.into_iter()
.map(|i| (i as f64 / 256.0) + 0.5)
.collect::<Vec<_>>();
let expected = dataset.iter().copied().product::<f64>();
let assert_close = |result: f64| {
prop_assert!((result - expected).abs() < 1e-6 * expected.abs());
Ok(())
};
assert_close(dataset.iter().copied().product_ilp::<1, f64>())?;
assert_close(dataset.iter().copied().product_ilp::<2, f64>())?;
assert_close(dataset.iter().copied().product_ilp::<3, f64>())?;
assert_close(dataset.iter().copied().product_ilp::<4, f64>())?;
assert_close(dataset.iter().copied().product_ilp::<5, f64>())?;
assert_close(dataset.iter().copied().product_ilp::<6, f64>())?;
}
}
}