Test and fix size_hint for slice's [r]split* iterators
Adds extensive test for all the [r]split* iterators. Fixes size_hint upper bound for split_inclusive* iterators which was one higher than necessary for non-empty slices. Fixes size_hint lower bound for [r]splitn* iterators when n==0, which was one too high.
This commit is contained in:
parent
6bed1f0bc3
commit
31e49f0272
2 changed files with 99 additions and 8 deletions
|
@ -993,6 +993,80 @@ fn test_rsplitnator() {
|
||||||
assert!(xs.rsplitn(0, |x| *x % 2 == 0).next().is_none());
|
assert!(xs.rsplitn(0, |x| *x % 2 == 0).next().is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_split_iterators_size_hint() {
|
||||||
|
for len in 0..=2 {
|
||||||
|
let mut v: Vec<u8> = (0..len).collect();
|
||||||
|
fn verify_descending(sequence: &[usize], context: &str) {
|
||||||
|
let len = sequence.len();
|
||||||
|
let target: Vec<usize> = (0..len).rev().collect();
|
||||||
|
assert_eq!(sequence, target, "while testing: {}", context);
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! test_size_hint {
|
||||||
|
($create_iterator:expr) => {{
|
||||||
|
// with a predicate always returning false, the split*-iterators
|
||||||
|
// become maximally short, so the size_hint lower bounds are correct
|
||||||
|
|
||||||
|
macro_rules! p {
|
||||||
|
() => {
|
||||||
|
|_| false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
let mut short_iterator = $create_iterator;
|
||||||
|
let mut lower_bounds = vec![short_iterator.size_hint().0];
|
||||||
|
while let Some(_) = short_iterator.next() {
|
||||||
|
lower_bounds.push(short_iterator.size_hint().0);
|
||||||
|
}
|
||||||
|
verify_descending(&lower_bounds, stringify!($create_iterator));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// with a predicate always returning true, the split*-iterators
|
||||||
|
// become maximally long, so the size_hint upper bounds are correct
|
||||||
|
|
||||||
|
macro_rules! p {
|
||||||
|
() => {
|
||||||
|
|_| true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
let mut long_iterator = $create_iterator;
|
||||||
|
let mut upper_bounds = vec![
|
||||||
|
long_iterator.size_hint().1.expect("split*-methods have known upper bound"),
|
||||||
|
];
|
||||||
|
while let Some(_) = long_iterator.next() {
|
||||||
|
upper_bounds.push(
|
||||||
|
long_iterator.size_hint().1.expect("split*-methods have known upper bound"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
verify_descending(&upper_bounds, stringify!($create_iterator));
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
test_size_hint!(v.split(p!()));
|
||||||
|
test_size_hint!(v.split_mut(p!()));
|
||||||
|
test_size_hint!(v.splitn(0, p!()));
|
||||||
|
test_size_hint!(v.splitn(1, p!()));
|
||||||
|
test_size_hint!(v.splitn(2, p!()));
|
||||||
|
test_size_hint!(v.splitn(3, p!()));
|
||||||
|
test_size_hint!(v.splitn_mut(0, p!()));
|
||||||
|
test_size_hint!(v.splitn_mut(1, p!()));
|
||||||
|
test_size_hint!(v.splitn_mut(2, p!()));
|
||||||
|
test_size_hint!(v.splitn_mut(3, p!()));
|
||||||
|
test_size_hint!(v.split_inclusive(p!()));
|
||||||
|
test_size_hint!(v.split_inclusive_mut(p!()));
|
||||||
|
test_size_hint!(v.rsplit(p!()));
|
||||||
|
test_size_hint!(v.rsplit_mut(p!()));
|
||||||
|
test_size_hint!(v.rsplitn(0, p!()));
|
||||||
|
test_size_hint!(v.rsplitn(1, p!()));
|
||||||
|
test_size_hint!(v.rsplitn(2, p!()));
|
||||||
|
test_size_hint!(v.rsplitn(3, p!()));
|
||||||
|
test_size_hint!(v.rsplitn_mut(0, p!()));
|
||||||
|
test_size_hint!(v.rsplitn_mut(1, p!()));
|
||||||
|
test_size_hint!(v.rsplitn_mut(2, p!()));
|
||||||
|
test_size_hint!(v.rsplitn_mut(3, p!()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_windowsator() {
|
fn test_windowsator() {
|
||||||
let v = &[1, 2, 3, 4];
|
let v = &[1, 2, 3, 4];
|
||||||
|
|
|
@ -400,7 +400,13 @@ where
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
if self.finished { (0, Some(0)) } else { (1, Some(self.v.len() + 1)) }
|
if self.finished {
|
||||||
|
(0, Some(0))
|
||||||
|
} else {
|
||||||
|
// If the predicate doesn't match anything, we yield one slice.
|
||||||
|
// If it matches every element, we yield `len() + 1` empty slices.
|
||||||
|
(1, Some(self.v.len() + 1))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -525,7 +531,14 @@ where
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
if self.finished { (0, Some(0)) } else { (1, Some(self.v.len() + 1)) }
|
if self.finished {
|
||||||
|
(0, Some(0))
|
||||||
|
} else {
|
||||||
|
// If the predicate doesn't match anything, we yield one slice.
|
||||||
|
// If it matches every element, we yield `len()` one-element slices,
|
||||||
|
// or a single empty slice.
|
||||||
|
(1, Some(cmp::max(1, self.v.len())))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -647,8 +660,8 @@ where
|
||||||
if self.finished {
|
if self.finished {
|
||||||
(0, Some(0))
|
(0, Some(0))
|
||||||
} else {
|
} else {
|
||||||
// if the predicate doesn't match anything, we yield one slice
|
// If the predicate doesn't match anything, we yield one slice.
|
||||||
// if it matches every element, we yield len+1 empty slices.
|
// If it matches every element, we yield `len() + 1` empty slices.
|
||||||
(1, Some(self.v.len() + 1))
|
(1, Some(self.v.len() + 1))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -763,9 +776,10 @@ where
|
||||||
if self.finished {
|
if self.finished {
|
||||||
(0, Some(0))
|
(0, Some(0))
|
||||||
} else {
|
} else {
|
||||||
// if the predicate doesn't match anything, we yield one slice
|
// If the predicate doesn't match anything, we yield one slice.
|
||||||
// if it matches every element, we yield len+1 empty slices.
|
// If it matches every element, we yield `len()` one-element slices,
|
||||||
(1, Some(self.v.len() + 1))
|
// or a single empty slice.
|
||||||
|
(1, Some(cmp::max(1, self.v.len())))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1008,7 +1022,10 @@ impl<T, I: SplitIter<Item = T>> Iterator for GenericSplitN<I> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
let (lower, upper_opt) = self.iter.size_hint();
|
let (lower, upper_opt) = self.iter.size_hint();
|
||||||
(lower, upper_opt.map(|upper| cmp::min(self.count, upper)))
|
(
|
||||||
|
cmp::min(self.count, lower),
|
||||||
|
Some(upper_opt.map_or(self.count, |upper| cmp::min(self.count, upper))),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue