use std::collections::btree_map::Range as BTreeMapRange;
use std::collections::btree_set::Range as BTreeSetRange;
use std::collections::BTreeMap;
use std::collections::BTreeSet;
use std::iter::Copied;
use std::iter::Map;
use std::ops::Bound;
use std::ops::Bound::Excluded;
use std::ops::Bound::Included;
use std::ops::Bound::Unbounded;
use std::ops::RangeBounds;
use crate::bounds::bounds;
use crate::bounds::end_lt_end;
use crate::bounds::start_le_end;
use crate::bounds::start_le_start;
use crate::bounds::start_lt_start;
use crate::Inc;
#[derive(Clone, Debug)]
pub struct GapIter<I, T> {
iter: Option<I>,
start: Bound<T>,
end: Bound<T>,
#[cfg(debug_assertions)]
last: Option<T>,
}
impl<I, T> GapIter<I, T>
where
I: Iterator<Item = T>,
T: Copy + Ord + Inc,
{
pub fn new(iter: I, start: Bound<T>, end: Bound<T>) -> Self {
Self {
iter: Some(iter),
start,
end,
#[cfg(debug_assertions)]
last: None,
}
}
}
impl<I, T> Iterator for GapIter<I, T>
where
I: Iterator<Item = T>,
T: Copy + Ord + Inc,
{
type Item = (Bound<T>, Bound<T>);
fn next(&mut self) -> Option<Self::Item> {
loop {
match self.iter.as_mut() {
Some(iter) => {
let (start, end) = if let Some(this) = iter.next() {
#[cfg(debug_assertions)]
{
debug_assert!(
self.last.unwrap_or(this) <= this,
"sequence is not ascending"
);
self.last = Some(this);
}
let end = Excluded(this);
if self.start != Unbounded && start_le_start(&Included(this), &self.start) {
if !start_lt_start(&Included(this), &self.start) {
self.start = end;
}
continue
}
let start = self.start;
self.start = end;
if !end_lt_end(&end, &self.end) {
self.iter = None;
(start, self.end)
} else {
if !start_le_end(&self.start, &self.end) {
self.iter = None;
}
(start, end)
}
} else {
self.iter = None;
(self.start, self.end)
};
if start_le_end(&start, &end) {
break Some((start, end))
}
},
None => break None,
}
}
}
}
pub trait Gappable<I, T> {
fn gaps<R>(self, range: R) -> GapIter<I, T>
where
R: RangeBounds<T>;
}
impl<I, T> Gappable<I, T> for I
where
I: Iterator<Item = T>,
T: Copy + Ord + Inc,
{
fn gaps<R>(self, range: R) -> GapIter<I, T>
where
R: RangeBounds<T>,
{
let (start, end) = bounds(&range);
GapIter::new(self, start, end)
}
}
pub trait RangeGappable<'s, T> {
type Iter;
fn gaps<R>(&'s self, range: R) -> GapIter<Self::Iter, T>
where
R: RangeBounds<T>;
}
impl<'s, V> RangeGappable<'s, V> for BTreeSet<V>
where
V: Copy + Ord + Inc + 's,
{
type Iter = Copied<BTreeSetRange<'s, V>>;
fn gaps<R>(&'s self, range: R) -> GapIter<Self::Iter, V>
where
R: RangeBounds<V>,
{
let (start, end) = bounds(&range);
let range = self.range(range).copied();
GapIter::new(range, start, end)
}
}
impl<'s, K, V> RangeGappable<'s, K> for BTreeMap<K, V>
where
K: Copy + Ord + Inc + 's,
V: 's,
{
#[allow(clippy::type_complexity)]
type Iter = Map<BTreeMapRange<'s, K, V>, fn((&'_ K, &'_ V)) -> K>;
fn gaps<R>(&'s self, range: R) -> GapIter<Self::Iter, K>
where
R: RangeBounds<K>,
{
fn map<I, J>(x: (&I, &J)) -> I
where
I: Copy,
{
*x.0
}
let (start, end) = bounds(&range);
let range = self.range(range).map(map as _);
GapIter::new(range, start, end)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[cfg(debug_assertions)]
#[should_panic(expected = "sequence is not ascending")]
fn panic_when_non_ascending() {
vec![1, 2, 1, 4, 5]
.iter()
.copied()
.gaps(..)
.for_each(|_| ());
}
}