use crate::ClosedRange;
use crate::Endpoint;
use crate::IntoNormalizedRangeIter;
use crate::NormalizedRangeIter;
use crate::RangeVec;
use std::iter::Peekable;
pub struct LinearIntersectionIterator<T, X, Y>
where
T: Endpoint,
X: Sized + NormalizedRangeIter + Iterator<Item: ClosedRange<EndT = T>>,
Y: Sized + NormalizedRangeIter + Iterator<Item: ClosedRange<EndT = T>>,
{
left: Peekable<X>,
right: Peekable<Y>,
}
impl<T, X, Y> LinearIntersectionIterator<T, X, Y>
where
T: Endpoint,
X: Sized + NormalizedRangeIter + Iterator<Item: ClosedRange<EndT = T>>,
Y: Sized + NormalizedRangeIter + Iterator<Item: ClosedRange<EndT = T>>,
{
pub fn new(left: X, right: Y) -> Self {
Self {
left: left.peekable(),
right: right.peekable(),
}
}
}
impl<T, X, Y> Iterator for LinearIntersectionIterator<T, X, Y>
where
T: Endpoint,
X: Sized + NormalizedRangeIter + Iterator<Item: ClosedRange<EndT = T>>,
Y: Sized + NormalizedRangeIter + Iterator<Item: ClosedRange<EndT = T>>,
{
type Item = (T, T);
fn next(&mut self) -> Option<(T, T)> {
use std::cmp::Ordering; loop {
let (Some(left), Some(right)) = (
self.left.peek().map(|x| x.get()),
self.right.peek().map(|x| x.get()),
) else {
return None;
};
match left.1.cmp_end(right.1) {
Ordering::Less => {
self.left.next();
}
Ordering::Equal => {
self.left.next();
self.right.next();
}
Ordering::Greater => {
self.right.next();
}
}
let start = left.0.top_end(right.0);
let stop = left.1.bot_end(right.1);
if start.cmp_end(stop) <= Ordering::Equal {
return Some((start, stop));
}
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let (_, left_max) = self.left.size_hint();
let (_, right_max) = self.right.size_hint();
if (left_max == Some(0)) | (right_max == Some(0)) {
(0, Some(0))
} else {
(
0,
left_max
.unwrap_or(usize::MAX)
.checked_add(right_max.unwrap_or(usize::MAX)),
)
}
}
}
impl<T, X, Y> crate::private::Sealed for LinearIntersectionIterator<T, X, Y>
where
T: Endpoint,
X: Sized + NormalizedRangeIter + Iterator<Item: ClosedRange<EndT = T>>,
Y: Sized + NormalizedRangeIter + Iterator<Item: ClosedRange<EndT = T>>,
{
}
impl<T, X, Y> NormalizedRangeIter for LinearIntersectionIterator<T, X, Y>
where
T: Endpoint,
X: Sized + NormalizedRangeIter + Iterator<Item: ClosedRange<EndT = T>>,
Y: Sized + NormalizedRangeIter + Iterator<Item: ClosedRange<EndT = T>>,
{
}
impl<T: Endpoint> RangeVec<T> {
#[inline(always)]
pub fn intersect(
&self,
other: impl IntoNormalizedRangeIter<Item: ClosedRange<EndT = T>>,
) -> Self {
#[inline(never)]
fn doit<T: Endpoint>(
this: &RangeVec<T>,
other: impl NormalizedRangeIter<Item: ClosedRange<EndT = T>>,
) -> RangeVec<T> {
let iter = this.iter().intersect(other);
let size_hint = iter.size_hint();
if this.is_empty() {
debug_assert_eq!(size_hint, (0, Some(0)));
}
let ret = iter.collect_range_vec();
debug_assert!(ret.len() >= size_hint.0);
debug_assert!(ret.len() <= size_hint.1.unwrap_or(usize::MAX));
ret
}
doit(self, other.into_iter())
}
}
#[cfg(test)]
#[cfg_attr(coverage_nightly, coverage(off))]
mod test {
use super::*;
#[test]
fn smoke_test() {
let empty: RangeVec<u8> = RangeVec::default();
let other = RangeVec::from_vec(vec![(u8::MIN, u8::MAX)]);
{
let empty_empty = empty.iter().intersect(empty.iter());
assert_eq!(empty_empty.size_hint(), (0, Some(0)));
assert_eq!(&empty_empty.collect_range_vec(), &empty);
}
{
let empty_other = empty.iter().intersect(other.iter());
assert_eq!(empty_other.size_hint(), (0, Some(0)));
assert_eq!(&empty_other.collect_range_vec(), &empty);
}
{
let other_empty = other.iter().intersect(empty.iter());
assert_eq!(other_empty.size_hint(), (0, Some(0)));
assert_eq!(&other_empty.collect_range_vec(), &empty);
}
}
#[cfg(test)]
proptest::proptest! {
#[test]
fn test_intersection_iterator(xs: Vec<(u8, u8)>, ys: Vec<(u8, u8)>)
{
use crate::ranges_to_bits;
let bits = {
let x_bits = ranges_to_bits(&xs);
let y_bits = ranges_to_bits(&ys);
x_bits.into_iter().zip(y_bits.into_iter()).map(|(x, y)| x & y).collect::<Vec<bool>>()
};
{
let out = RangeVec::from_vec(xs.clone()).iter().intersect(
RangeVec::from_vec(ys.clone()).iter()).collect_range_vec();
assert_eq!(&bits, &ranges_to_bits(&out));
}
{
let out = RangeVec::from_vec(ys.clone()).iter().intersect(&RangeVec::from_vec(xs.clone())).collect_range_vec();
assert_eq!(&bits, &ranges_to_bits(&out));
}
}
#[test]
fn test_intersection_identity(xs: Vec<(u8, u8)>, ys: Vec<(u8, u8)>)
{
let xs = RangeVec::from_vec(xs.into_iter().map(|(a, b)| (a.min(b), a.max(b))).collect::<Vec<_>>());
let ys = RangeVec::from_vec(ys.into_iter().map(|(a, b)| (a.min(b), a.max(b))).collect::<Vec<_>>());
{
let not_and = xs.iter().intersect(&ys).complement().collect_range_vec();
let or_not = crate::union_vec(xs.iter().complement().collect_range_vec(),
ys.iter().complement());
assert_eq!(not_and, or_not);
}
{
let and = xs.iter().intersect(&ys).collect_range_vec();
let not_or_not = crate::union_vec(xs.iter().complement().collect_range_vec(),
ys.iter().complement()).iter().complement().collect_range_vec();
assert_eq!(and, not_or_not);
}
}
}
}