use crate::RangeSetBlaze;
use crate::map::ValueRef;
use crate::range_values::{MapIntoRangesIter, MapRangesIter, RangeValuesToRangesIter};
use crate::ranges_iter::RangesIter;
use crate::sorted_disjoint_map::IntoString;
use crate::{IntoRangesIter, UnionIter, UnionMerge};
use alloc::string::String;
use core::array;
use core::{
iter::FusedIterator,
ops::{self, RangeInclusive},
};
use crate::SortedDisjointMap;
use crate::{
DifferenceMerge, DynSortedDisjoint, Integer, IntersectionMerge, NotIter, SymDiffIter,
SymDiffMerge,
};
pub trait SortedStarts<T: Integer>: Iterator<Item = RangeInclusive<T>> + FusedIterator {}
pub trait SortedDisjoint<T: Integer>: SortedStarts<T> {
#[inline]
fn union<R>(self, other: R) -> UnionMerge<T, Self, R::IntoIter>
where
R: IntoIterator<Item = Self::Item>,
R::IntoIter: SortedDisjoint<T>,
Self: Sized,
{
UnionMerge::new2(self, other.into_iter())
}
#[inline]
fn intersection<R>(self, other: R) -> IntersectionMerge<T, Self, R::IntoIter>
where
R: IntoIterator<Item = Self::Item>,
R::IntoIter: SortedDisjoint<T>,
Self: Sized,
{
!(self.complement() | other.into_iter().complement())
}
#[inline]
fn difference<R>(self, other: R) -> DifferenceMerge<T, Self, R::IntoIter>
where
R: IntoIterator<Item = Self::Item>,
R::IntoIter: SortedDisjoint<T>,
Self: Sized,
{
!(self.complement() | other.into_iter())
}
#[inline]
fn complement(self) -> NotIter<T, Self>
where
Self: Sized,
{
NotIter::new(self)
}
#[inline]
fn symmetric_difference<R>(self, other: R) -> SymDiffMerge<T, Self, R::IntoIter>
where
R: IntoIterator<Item = Self::Item>,
R::IntoIter: SortedDisjoint<T>,
<R as IntoIterator>::IntoIter:,
Self: Sized,
{
let result: SymDiffIter<T, crate::Merge<T, Self, <R as IntoIterator>::IntoIter>> =
SymDiffIter::new2(self, other.into_iter());
result
}
fn equal<R>(self, other: R) -> bool
where
R: IntoIterator<Item = Self::Item>,
R::IntoIter: SortedDisjoint<T>,
Self: Sized,
{
itertools::equal(self, other)
}
#[deprecated(since = "0.2.0", note = "Use `into_string` instead")]
fn to_string(self) -> String
where
Self: Sized,
{
self.into_string()
}
#[inline]
#[allow(clippy::wrong_self_convention)]
fn is_empty(mut self) -> bool
where
Self: Sized,
{
self.next().is_none()
}
#[inline]
#[allow(clippy::wrong_self_convention)]
fn is_universal(mut self) -> bool
where
Self: Sized,
{
self.next().is_some_and(|range| {
let (start, end) = range.into_inner();
start == T::min_value() && end == T::max_value()
})
}
#[must_use]
#[inline]
#[allow(clippy::wrong_self_convention)]
fn is_subset<R>(self, other: R) -> bool
where
R: IntoIterator<Item = Self::Item>,
R::IntoIter: SortedDisjoint<T>,
Self: Sized,
{
self.difference(other).is_empty()
}
#[inline]
#[must_use]
#[allow(clippy::wrong_self_convention)]
fn is_superset<R>(self, other: R) -> bool
where
R: IntoIterator<Item = Self::Item>,
R::IntoIter: SortedDisjoint<T>,
Self: Sized,
{
other.into_iter().is_subset(self)
}
#[must_use]
#[inline]
#[allow(clippy::wrong_self_convention)]
fn is_disjoint<R>(self, other: R) -> bool
where
R: IntoIterator<Item = Self::Item>,
R::IntoIter: SortedDisjoint<T>,
Self: Sized,
{
self.intersection(other).is_empty()
}
fn into_range_set_blaze(self) -> RangeSetBlaze<T>
where
Self: Sized,
{
RangeSetBlaze::from_sorted_disjoint(self)
}
}
#[derive(Debug, Clone)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[allow(clippy::module_name_repetitions)]
pub struct CheckSortedDisjoint<T, I> {
pub(crate) iter: I,
prev_end: Option<T>,
seen_none: bool,
}
impl<T, I> CheckSortedDisjoint<T, I>
where
T: Integer,
I: Iterator<Item = RangeInclusive<T>> + FusedIterator,
{
#[inline]
pub fn new<J: IntoIterator<IntoIter = I>>(iter: J) -> Self {
Self {
iter: iter.into_iter(),
prev_end: None,
seen_none: false,
}
}
}
impl<T: Integer> Default for CheckSortedDisjoint<T, array::IntoIter<RangeInclusive<T>, 0>> {
fn default() -> Self {
Self::new([])
}
}
impl<T, I> FusedIterator for CheckSortedDisjoint<T, I>
where
T: Integer,
I: Iterator<Item = RangeInclusive<T>> + FusedIterator,
{
}
impl<T, I> Iterator for CheckSortedDisjoint<T, I>
where
T: Integer,
I: Iterator<Item = RangeInclusive<T>> + FusedIterator,
{
type Item = RangeInclusive<T>;
fn next(&mut self) -> Option<Self::Item> {
let next = self.iter.next();
let Some(range) = next.as_ref() else {
self.seen_none = true;
return next;
};
assert!(
!self.seen_none,
"iterator cannot return Some after returning None"
);
let (start, end) = range.clone().into_inner();
assert!(start <= end, "start must be less or equal to end");
if let Some(prev_end) = self.prev_end {
assert!(
prev_end < T::max_value() && prev_end.add_one() < start,
"ranges must be disjoint"
);
}
self.prev_end = Some(end);
next
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl<T: Integer, const N: usize> From<[RangeInclusive<T>; N]>
for CheckSortedDisjoint<T, array::IntoIter<RangeInclusive<T>, N>>
{
fn from(arr: [RangeInclusive<T>; N]) -> Self {
Self::new(arr)
}
}
pub trait AnythingGoes<T: Integer>: Iterator<Item = RangeInclusive<T>> + FusedIterator {}
impl<T: Integer, I> AnythingGoes<T> for I where I: Iterator<Item = RangeInclusive<T>> + FusedIterator
{}
pub struct RangeOnce<T>(core::option::IntoIter<RangeInclusive<T>>);
impl<T: Integer> RangeOnce<T> {
pub fn new(range: RangeInclusive<T>) -> Self {
Self((!range.is_empty()).then_some(range).into_iter())
}
}
impl<T: Integer> From<RangeInclusive<T>> for RangeOnce<T> {
#[inline]
fn from(value: RangeInclusive<T>) -> Self {
Self::new(value)
}
}
impl<T: Integer> Iterator for RangeOnce<T> {
type Item = RangeInclusive<T>;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl<T: Integer> DoubleEndedIterator for RangeOnce<T> {
fn next_back(&mut self) -> Option<Self::Item> {
self.0.next_back()
}
}
impl<T: Integer> ExactSizeIterator for RangeOnce<T> {
fn len(&self) -> usize {
self.0.len()
}
}
impl<T: Integer> FusedIterator for RangeOnce<T> {}
macro_rules! impl_sorted_traits_and_ops {
($IterType:ty, $($more_generics:tt)*) => {
#[allow(single_use_lifetimes)]
impl<$($more_generics)*, T: Integer> SortedStarts<T> for $IterType {}
#[allow(single_use_lifetimes)]
impl<$($more_generics)*, T: Integer> SortedDisjoint<T> for $IterType {}
#[allow(single_use_lifetimes)]
impl<$($more_generics)*, T: Integer> ops::Not for $IterType
{
type Output = NotIter<T, Self>;
fn not(self) -> Self::Output {
self.complement()
}
}
#[allow(single_use_lifetimes)]
impl<$($more_generics)*, T: Integer, R> ops::BitOr<R> for $IterType
where
R: SortedDisjoint<T>,
{
type Output = UnionMerge<T, Self, R>;
fn bitor(self, other: R) -> Self::Output {
SortedDisjoint::union(self, other)
}
}
#[allow(single_use_lifetimes)]
impl<$($more_generics)*, T: Integer, R> ops::Sub<R> for $IterType
where
R: SortedDisjoint<T>,
{
type Output = DifferenceMerge<T, Self, R>;
fn sub(self, other: R) -> Self::Output {
SortedDisjoint::difference(self, other)
}
}
#[allow(single_use_lifetimes)]
impl<$($more_generics)*, T: Integer, R> ops::BitXor<R> for $IterType
where
R: SortedDisjoint<T>,
{
type Output = SymDiffMerge<T, Self, R>;
#[allow(clippy::suspicious_arithmetic_impl)]
fn bitxor(self, other: R) -> Self::Output {
SortedDisjoint::symmetric_difference(self, other)
}
}
#[allow(single_use_lifetimes)]
impl<$($more_generics)*, T: Integer, R> ops::BitAnd<R> for $IterType
where
R: SortedDisjoint<T>,
{
type Output = IntersectionMerge<T, Self, R>;
fn bitand(self, other: R) -> Self::Output {
SortedDisjoint::intersection(self, other)
}
}
};
}
impl_sorted_traits_and_ops!(CheckSortedDisjoint<T, I>, I: AnythingGoes<T>);
impl_sorted_traits_and_ops!(DynSortedDisjoint<'a, T>, 'a);
impl_sorted_traits_and_ops!(IntoRangesIter<T>, 'ignore);
impl_sorted_traits_and_ops!(MapIntoRangesIter<T, V>, V: Eq + Clone);
impl_sorted_traits_and_ops!(MapRangesIter<'a, T, V>, 'a, V: Eq + Clone);
impl_sorted_traits_and_ops!(NotIter<T, I>, I: SortedDisjoint<T>);
impl_sorted_traits_and_ops!(RangesIter<'a, T>, 'a);
impl_sorted_traits_and_ops!(RangeValuesToRangesIter<T, VR, I>, VR: ValueRef, I: SortedDisjointMap<T, VR>);
impl_sorted_traits_and_ops!(SymDiffIter<T, I>, I: SortedStarts<T>);
impl_sorted_traits_and_ops!(UnionIter<T, I>, I: SortedStarts<T>);
impl_sorted_traits_and_ops!(RangeOnce<T>, 'ignore);