range_set_blaze/
sorted_disjoint.rs

1use alloc::format;
2use alloc::string::String;
3use core::{
4    iter::FusedIterator,
5    ops::{self, RangeInclusive},
6};
7
8use itertools::Itertools;
9
10use crate::{
11    BitAndMerge, BitOrMerge, BitSubMerge, BitXOrTee, Integer, Merge, NotIter, RangeSetBlaze,
12    UnionIter,
13};
14
15/// A trait used to mark iterators that provide ranges sorted by start, but not necessarily by end,
16/// and may overlap.
17pub trait SortedStarts<T: Integer>: Iterator<Item = RangeInclusive<T>> {}
18
19/// The trait used to mark iterators that provide ranges that are sorted by start and disjoint. Set operations on
20/// iterators that implement this trait can be performed in linear time.
21///
22/// # Table of Contents
23/// * [`SortedDisjoint` Constructors](#sorteddisjoint-constructors)
24///   * [Examples](#constructor-examples)
25/// * [`SortedDisjoint` Set and Other Operations](#sorteddisjoint-set-and-other-operations)
26///   * [Performance](#performance)
27///   * [Examples](#examples)
28/// * [How to mark your type as `SortedDisjoint`](#how-to-mark-your-type-as-sorteddisjoint)
29///   * [Example – Find the ordinal weekdays in September 2023](#example--find-the-ordinal-weekdays-in-september-2023)
30///
31/// # `SortedDisjoint` Constructors
32///
33/// You'll usually construct a `SortedDisjoint` iterator from a [`RangeSetBlaze`] or a [`CheckSortedDisjoint`].
34/// Here is a summary table, followed by [examples](#constructor-examples). You can also [define your own
35/// `SortedDisjoint`](#how-to-mark-your-type-as-sorteddisjoint).
36///
37/// | Input type | Method |
38/// |------------|--------|
39/// | [`RangeSetBlaze`] | [`ranges`] |
40/// | [`RangeSetBlaze`] | [`into_ranges`] |
41/// | [`RangeSetBlaze`]'s [`RangesIter`] | [`clone`] |
42/// | sorted & disjoint ranges | [`CheckSortedDisjoint::new`] |
43/// | `SortedDisjoint` iterator | [itertools `tee`] |
44/// | `SortedDisjoint` iterator | [`crate::dyn_sorted_disjoint::DynSortedDisjoint::new`] |
45/// |  *your iterator type* | *[How to mark your type as `SortedDisjoint`][1]* |
46///
47/// [`ranges`]: RangeSetBlaze::ranges
48/// [`into_ranges`]: RangeSetBlaze::into_ranges
49/// [`clone`]: crate::RangesIter::clone
50/// [itertools `tee`]: https://docs.rs/itertools/latest/itertools/trait.Itertools.html#method.tee
51/// [1]: #how-to-mark-your-type-as-sorteddisjoint
52/// [`RangesIter`]: crate::RangesIter
53///
54/// ## Constructor Examples
55///
56/// ```
57/// use range_set_blaze::prelude::*;
58/// use itertools::Itertools;
59///
60/// // RangeSetBlaze's .ranges(), .range().clone() and .into_ranges()
61/// let r = RangeSetBlaze::from_iter([3, 2, 1, 100, 1]);
62/// let a = r.ranges();
63/// let b = a.clone();
64/// assert!(a.to_string() == "1..=3, 100..=100");
65/// assert!(b.to_string() == "1..=3, 100..=100");
66/// //    'into_ranges' takes ownership of the 'RangeSetBlaze'
67/// let a = RangeSetBlaze::from_iter([3, 2, 1, 100, 1]).into_ranges();
68/// assert!(a.to_string() == "1..=3, 100..=100");
69///
70/// // CheckSortedDisjoint -- unsorted or overlapping input ranges will cause a panic.
71/// let a = CheckSortedDisjoint::from([1..=3, 100..=100]);
72/// assert!(a.to_string() == "1..=3, 100..=100");
73///
74/// // tee of a SortedDisjoint iterator
75/// let a = CheckSortedDisjoint::from([1..=3, 100..=100]);
76/// let (a, b) = a.tee();
77/// assert!(a.to_string() == "1..=3, 100..=100");
78/// assert!(b.to_string() == "1..=3, 100..=100");
79///
80/// // DynamicSortedDisjoint of a SortedDisjoint iterator
81/// let a = CheckSortedDisjoint::from([1..=3, 100..=100]);
82/// let b = DynSortedDisjoint::new(a);
83/// assert!(b.to_string() == "1..=3, 100..=100");
84/// ```
85///
86/// # `SortedDisjoint` Set Operations
87///
88/// | Method | Operator | Multiway (same type) | Multiway (different types) |
89/// |--------|----------|----------------------|----------------------------|
90/// | `a.`[`union`]`(b)` | `a` &#124; `b` | `[a, b, c].`[`union`][crate::MultiwaySortedDisjoint::union]`()` | [`crate::MultiwayRangeSetBlaze::union`]`!(a, b, c)` |
91/// | `a.`[`intersection`]`(b)` | `a & b` | `[a, b, c].`[`intersection`][crate::MultiwaySortedDisjoint::intersection]`()` | [`crate::MultiwayRangeSetBlaze::intersection`]`!(a, b, c)` |
92/// | `a.`[`difference`]`(b)` | `a - b` |  |  |
93/// | `a.`[`symmetric_difference`]`(b)` | `a ^ b` |  |  |
94/// | `a.`[`complement`]`()` | `!a` |  |  |
95///
96///
97/// ## Performance
98///
99/// Every operation is implemented as a single pass over the sorted & disjoint ranges, with minimal memory.
100///
101/// This is true even when applying multiple operations. The last example below demonstrates this.
102///
103/// ## Examples
104///
105/// ```
106/// use range_set_blaze::prelude::*;
107///
108/// let a0 = RangeSetBlaze::from_iter([1..=2, 5..=100]);
109/// let b0 = RangeSetBlaze::from_iter([2..=6]);
110/// let c0 = RangeSetBlaze::from_iter([2..=2, 6..=200]);
111///
112/// // 'union' method and 'to_string' method
113/// let (a, b) = (a0.ranges(), b0.ranges());
114/// let result = a.union(b);
115/// assert_eq!(result.to_string(), "1..=100");
116///
117/// // '|' operator and 'equal' method
118/// let (a, b) = (a0.ranges(), b0.ranges());
119/// let result = a | b;
120/// assert!(result.equal(CheckSortedDisjoint::from([1..=100])));
121///
122/// // multiway union of same type
123/// let (a, b, c) = (a0.ranges(), b0.ranges(), c0.ranges());
124/// let result = [a, b, c].union();
125/// assert_eq!(result.to_string(), "1..=200");
126///
127/// // multiway union of different types
128/// let (a, b, c) = (a0.ranges(), b0.ranges(), c0.ranges());
129/// let result = union_dyn!(a, b, !c);
130/// assert_eq!(result.to_string(), "-2147483648..=100, 201..=2147483647");
131///
132/// // Applying multiple operators makes only one pass through the inputs with minimal memory.
133/// let (a, b, c) = (a0.ranges(), b0.ranges(), c0.ranges());
134/// let result = a - (b | c);
135/// assert!(result.to_string() == "1..=1");
136/// ```
137///
138/// # How to mark your type as `SortedDisjoint`
139///
140/// To mark your iterator type as `SortedDisjoint`, you implement the `SortedStarts` and `SortedDisjoint` traits.
141/// This is your promise to the compiler that your iterator will provide inclusive ranges that disjoint and sorted by start.
142///
143/// When you do this, your iterator will get access to the
144/// efficient set operations methods, such as [`intersection`] and [`complement`]. The example below shows this.
145///
146/// > To use operators such as `&` and `!`, you must also implement the [`BitAnd`], [`Not`], etc. traits.
147/// >
148/// > If you want others to use your marked iterator type, reexport:
149/// > `pub use range_set_blaze::{SortedDisjoint, SortedStarts};`
150///
151/// [`BitAnd`]: https://doc.rust-lang.org/std/ops/trait.BitAnd.html
152/// [`Not`]: https://doc.rust-lang.org/std/ops/trait.Not.html
153/// [`intersection`]: SortedDisjoint::intersection
154/// [`complement`]: SortedDisjoint::complement
155/// [`union`]: SortedDisjoint::union
156/// [`symmetric_difference`]: SortedDisjoint::symmetric_difference
157/// [`difference`]: SortedDisjoint::difference
158/// [`to_string`]: SortedDisjoint::to_string
159/// [`equal`]: SortedDisjoint::equal
160/// [multiway_union]: crate::MultiwaySortedDisjoint::union
161/// [multiway_intersection]: crate::MultiwaySortedDisjoint::intersection
162///
163/// ## Example -- Find the ordinal weekdays in September 2023
164/// ```
165/// use core::ops::RangeInclusive;
166/// pub use range_set_blaze::{SortedDisjoint, SortedStarts};
167///
168/// // Ordinal dates count January 1 as day 1, February 1 as day 32, etc.
169/// struct OrdinalWeekends2023 {
170///     next_range: RangeInclusive<i32>,
171/// }
172///
173/// // We promise the compiler that our iterator will provide
174/// // ranges that are sorted and disjoint.
175/// impl SortedStarts<i32> for OrdinalWeekends2023 {}
176/// impl SortedDisjoint<i32> for OrdinalWeekends2023 {}
177///
178/// impl OrdinalWeekends2023 {
179///     fn new() -> Self {
180///         Self { next_range: 0..=1 }
181///     }
182/// }
183/// impl Iterator for OrdinalWeekends2023 {
184///     type Item = RangeInclusive<i32>;
185///     fn next(&mut self) -> Option<Self::Item> {
186///         let (start, end) = self.next_range.clone().into_inner();
187///         if start > 365 {
188///             None
189///         } else {
190///             self.next_range = (start + 7)..=(end + 7);
191///             Some(start.max(1)..=end.min(365))
192///         }
193///     }
194/// }
195///
196/// use range_set_blaze::prelude::*;
197///
198/// let weekends = OrdinalWeekends2023::new();
199/// let september = CheckSortedDisjoint::from([244..=273]);
200/// let september_weekdays = september.intersection(weekends.complement());
201/// assert_eq!(
202///     september_weekdays.to_string(),
203///     "244..=244, 247..=251, 254..=258, 261..=265, 268..=272"
204/// );
205/// ```
206pub trait SortedDisjoint<T: Integer>: SortedStarts<T> {
207    // I think this is 'Sized' because will sometimes want to create a struct (e.g. BitOrIter) that contains a field of this type
208
209    /// Given two [`SortedDisjoint`] iterators, efficiently returns a [`SortedDisjoint`] iterator of their union.
210    ///
211    /// # Examples
212    ///
213    /// ```
214    /// use range_set_blaze::prelude::*;
215    ///
216    /// let a = CheckSortedDisjoint::from([1..=1]);
217    /// let b = RangeSetBlaze::from_iter([2..=2]).into_ranges();
218    /// let union = a.union(b);
219    /// assert_eq!(union.to_string(), "1..=2");
220    ///
221    /// // Alternatively, we can use "|" because CheckSortedDisjoint defines
222    /// // ops::bitor as SortedDisjoint::union.
223    /// let a = CheckSortedDisjoint::from([1..=1]);
224    /// let b = RangeSetBlaze::from_iter([2..=2]).into_ranges();
225    /// let union = a | b;
226    /// assert_eq!(union.to_string(), "1..=2");
227    /// ```
228    #[inline]
229    fn union<R>(self, other: R) -> BitOrMerge<T, Self, R::IntoIter>
230    where
231        R: IntoIterator<Item = Self::Item>,
232        R::IntoIter: SortedDisjoint<T>,
233        Self: Sized,
234    {
235        UnionIter::new(Merge::new(self, other.into_iter()))
236    }
237
238    /// Given two [`SortedDisjoint`] iterators, efficiently returns a [`SortedDisjoint`] iterator of their intersection.
239    ///
240    /// # Examples
241    ///
242    /// ```
243    /// use range_set_blaze::prelude::*;
244    ///
245    /// let a = CheckSortedDisjoint::from([1..=2]);
246    /// let b = RangeSetBlaze::from_iter([2..=3]).into_ranges();
247    /// let intersection = a.intersection(b);
248    /// assert_eq!(intersection.to_string(), "2..=2");
249    ///
250    /// // Alternatively, we can use "&" because CheckSortedDisjoint defines
251    /// // ops::bitand as SortedDisjoint::intersection.
252    /// let a = CheckSortedDisjoint::from([1..=2]);
253    /// let b = RangeSetBlaze::from_iter([2..=3]).into_ranges();
254    /// let intersection = a & b;
255    /// assert_eq!(intersection.to_string(), "2..=2");
256    /// ```
257    #[inline]
258    fn intersection<R>(self, other: R) -> BitAndMerge<T, Self, R::IntoIter>
259    where
260        R: IntoIterator<Item = Self::Item>,
261        R::IntoIter: SortedDisjoint<T>,
262        Self: Sized,
263    {
264        !(self.complement() | other.into_iter().complement())
265    }
266
267    /// Given two [`SortedDisjoint`] iterators, efficiently returns a [`SortedDisjoint`] iterator of their set difference.
268    ///
269    /// # Examples
270    ///
271    /// ```
272    /// use range_set_blaze::prelude::*;
273    ///
274    /// let a = CheckSortedDisjoint::from([1..=2]);
275    /// let b = RangeSetBlaze::from_iter([2..=3]).into_ranges();
276    /// let difference = a.difference(b);
277    /// assert_eq!(difference.to_string(), "1..=1");
278    ///
279    /// // Alternatively, we can use "-" because CheckSortedDisjoint defines
280    /// // ops::sub as SortedDisjoint::difference.
281    /// let a = CheckSortedDisjoint::from([1..=2]);
282    /// let b = RangeSetBlaze::from_iter([2..=3]).into_ranges();
283    /// let difference = a - b;
284    /// assert_eq!(difference.to_string(), "1..=1");
285    /// ```
286    #[inline]
287    fn difference<R>(self, other: R) -> BitSubMerge<T, Self, R::IntoIter>
288    where
289        R: IntoIterator<Item = Self::Item>,
290        R::IntoIter: SortedDisjoint<T>,
291        Self: Sized,
292    {
293        !(self.complement() | other.into_iter())
294    }
295
296    /// Given a [`SortedDisjoint`] iterator, efficiently returns a [`SortedDisjoint`] iterator of its complement.
297    ///
298    /// # Examples
299    ///
300    /// ```
301    /// use range_set_blaze::prelude::*;
302    ///
303    /// let a = CheckSortedDisjoint::from([-10i16..=0, 1000..=2000]);
304    /// let complement = a.complement();
305    /// assert_eq!(complement.to_string(), "-32768..=-11, 1..=999, 2001..=32767");
306    ///
307    /// // Alternatively, we can use "!" because CheckSortedDisjoint defines
308    /// // ops::not as SortedDisjoint::complement.
309    /// let a = CheckSortedDisjoint::from([-10i16..=0, 1000..=2000]);
310    /// let complement = !a;
311    /// assert_eq!(complement.to_string(), "-32768..=-11, 1..=999, 2001..=32767");
312    /// ```
313    #[inline]
314    fn complement(self) -> NotIter<T, Self>
315    where
316        Self: Sized,
317    {
318        NotIter::new(self)
319    }
320
321    /// Given two [`SortedDisjoint`] iterators, efficiently returns a [`SortedDisjoint`] iterator
322    /// of their symmetric difference.
323    ///
324    /// # Examples
325    ///
326    /// ```
327    /// use range_set_blaze::prelude::*;
328    ///
329    /// let a = CheckSortedDisjoint::from([1..=2]);
330    /// let b = RangeSetBlaze::from_iter([2..=3]).into_ranges();
331    /// let symmetric_difference = a.symmetric_difference(b);
332    /// assert_eq!(symmetric_difference.to_string(), "1..=1, 3..=3");
333    ///
334    /// // Alternatively, we can use "^" because CheckSortedDisjoint defines
335    /// // ops::bitxor as SortedDisjoint::symmetric_difference.
336    /// let a = CheckSortedDisjoint::from([1..=2]);
337    /// let b = RangeSetBlaze::from_iter([2..=3]).into_ranges();
338    /// let symmetric_difference = a ^ b;
339    /// assert_eq!(symmetric_difference.to_string(), "1..=1, 3..=3");
340    /// ```
341    #[inline]
342    fn symmetric_difference<R>(self, other: R) -> BitXOrTee<T, Self, R::IntoIter>
343    where
344        R: IntoIterator<Item = Self::Item>,
345        R::IntoIter: SortedDisjoint<T>,
346        Self: Sized,
347    {
348        let (lhs0, lhs1) = self.tee();
349        let (rhs0, rhs1) = other.into_iter().tee();
350        lhs0.difference(rhs0) | rhs1.difference(lhs1)
351    }
352
353    /// Given two [`SortedDisjoint`] iterators, efficiently tells if they are equal. Unlike most equality testing in Rust,
354    /// this method takes ownership of the iterators and consumes them.
355    ///
356    /// # Examples
357    ///
358    /// ```
359    /// use range_set_blaze::prelude::*;
360    ///
361    /// let a = CheckSortedDisjoint::from([1..=2]);
362    /// let b = RangeSetBlaze::from_iter([1..=2]).into_ranges();
363    /// assert!(a.equal(b));
364    /// ```
365    fn equal<R>(self, other: R) -> bool
366    where
367        R: IntoIterator<Item = Self::Item>,
368        R::IntoIter: SortedDisjoint<T>,
369        Self: Sized,
370    {
371        itertools::equal(self, other)
372    }
373
374    /// Given a [`SortedDisjoint`] iterators, produces a string version. Unlike most `to_string` and `fmt` in Rust,
375    /// this method takes ownership of the iterator and consumes it.
376    ///
377    /// # Examples
378    ///
379    /// ```
380    /// use range_set_blaze::prelude::*;
381    ///
382    /// let a = CheckSortedDisjoint::from([1..=2]);
383    /// assert_eq!(a.to_string(), "1..=2");
384    /// ```
385    fn to_string(self) -> String
386    where
387        Self: Sized,
388    {
389        self.map(|range| format!("{range:?}")).join(", ")
390    }
391
392    /// Returns `true` if the set contains no elements.
393    ///
394    /// # Examples
395    ///
396    /// ```
397    /// use range_set_blaze::RangeSetBlaze;
398    ///
399    /// let mut v = RangeSetBlaze::new();
400    /// assert!(v.is_empty());
401    /// v.insert(1);
402    /// assert!(!v.is_empty());
403    /// ```
404    #[inline]
405    #[allow(clippy::wrong_self_convention)]
406    fn is_empty(mut self) -> bool
407    where
408        Self: Sized,
409    {
410        self.next().is_none()
411    }
412
413    /// Returns `true` if the set is a subset of another,
414    /// i.e., `other` contains at least all the elements in `self`.
415    ///
416    /// # Examples
417    ///
418    /// ```
419    /// use range_set_blaze::prelude::*;
420    ///
421    /// let sup = CheckSortedDisjoint::from([1..=3]);
422    /// let set: CheckSortedDisjoint<i32, _> = [].into();
423    /// assert_eq!(set.is_subset(sup), true);
424    ///
425    /// let sup = CheckSortedDisjoint::from([1..=3]);
426    /// let set = CheckSortedDisjoint::from([2..=2]);
427    /// assert_eq!(set.is_subset(sup), true);
428    ///
429    /// let sup = CheckSortedDisjoint::from([1..=3]);
430    /// let set = CheckSortedDisjoint::from([2..=2, 4..=4]);
431    /// assert_eq!(set.is_subset(sup), false);
432    /// ```
433    #[must_use]
434    #[inline]
435    #[allow(clippy::wrong_self_convention)]
436    fn is_subset<R>(self, other: R) -> bool
437    where
438        R: IntoIterator<Item = Self::Item>,
439        R::IntoIter: SortedDisjoint<T>,
440        Self: Sized,
441    {
442        self.difference(other).is_empty()
443    }
444
445    /// Returns `true` if the set is a superset of another,
446    /// i.e., `self` contains at least all the elements in `other`.
447    ///
448    /// # Examples
449    ///
450    /// ```
451    /// use range_set_blaze::RangeSetBlaze;
452    ///
453    /// let sub = RangeSetBlaze::from_iter([1, 2]);
454    /// let mut set = RangeSetBlaze::new();
455    ///
456    /// assert_eq!(set.is_superset(&sub), false);
457    ///
458    /// set.insert(0);
459    /// set.insert(1);
460    /// assert_eq!(set.is_superset(&sub), false);
461    ///
462    /// set.insert(2);
463    /// assert_eq!(set.is_superset(&sub), true);
464    /// ```
465    #[inline]
466    #[must_use]
467    #[allow(clippy::wrong_self_convention)]
468    fn is_superset<R>(self, other: R) -> bool
469    where
470        R: IntoIterator<Item = Self::Item>,
471        R::IntoIter: SortedDisjoint<T>,
472        Self: Sized,
473    {
474        other.into_iter().is_subset(self)
475    }
476
477    /// Returns `true` if `self` has no elements in common with `other`.
478    /// This is equivalent to checking for an empty intersection.
479    ///
480    /// # Examples
481    ///
482    /// ```
483    /// use range_set_blaze::RangeSetBlaze;
484    ///
485    /// let a = RangeSetBlaze::from_iter([1..=3]);
486    /// let mut b = RangeSetBlaze::new();
487    ///
488    /// assert_eq!(a.is_disjoint(&b), true);
489    /// b.insert(4);
490    /// assert_eq!(a.is_disjoint(&b), true);
491    /// b.insert(1);
492    /// assert_eq!(a.is_disjoint(&b), false);
493    /// ```
494    #[must_use]
495    #[inline]
496    #[allow(clippy::wrong_self_convention)]
497    fn is_disjoint<R>(self, other: R) -> bool
498    where
499        R: IntoIterator<Item = Self::Item>,
500        R::IntoIter: SortedDisjoint<T>,
501        Self: Sized,
502    {
503        self.intersection(other).is_empty()
504    }
505
506    /// Create a [`RangeSetBlaze`] from a [`SortedDisjoint`] iterator.
507    ///
508    /// *For more about constructors and performance, see [`RangeSetBlaze` Constructors](struct.RangeSetBlaze.html#constructors).*
509    ///
510    /// # Examples
511    ///
512    /// ```
513    /// use range_set_blaze::prelude::*;
514    ///
515    /// let a0 = RangeSetBlaze::from_sorted_disjoint(CheckSortedDisjoint::from([-10..=-5, 1..=2]));
516    /// let a1: RangeSetBlaze<i32> = CheckSortedDisjoint::from([-10..=-5, 1..=2]).into_range_set_blaze();
517    /// assert!(a0 == a1 && a0.to_string() == "-10..=-5, 1..=2");
518    /// ```
519    fn into_range_set_blaze(self) -> RangeSetBlaze<T>
520    where
521        Self: Sized,
522    {
523        RangeSetBlaze::from_sorted_disjoint(self)
524    }
525}
526
527/// Gives the [`SortedDisjoint`] trait to any iterator of ranges. The iterator will panic
528/// if/when it finds that the ranges are not actually sorted and disjoint.
529///
530/// # Performance
531///
532/// All checking is done at runtime, but it should still be fast.
533///
534/// # Example
535///
536/// ```
537/// use range_set_blaze::prelude::*;
538///
539/// let a = CheckSortedDisjoint::new(vec![1..=2, 5..=100]);
540/// let b = CheckSortedDisjoint::from([2..=6]);
541/// let union = a | b;
542/// assert_eq!(union.to_string(), "1..=100");
543/// ```
544///
545/// Here the ranges are not sorted and disjoint, so the iterator will panic.
546///```should_panic
547/// use range_set_blaze::prelude::*;
548///
549/// let a = CheckSortedDisjoint::new(vec![1..=2, 5..=100]);
550/// let b = CheckSortedDisjoint::from([2..=6,-10..=-5]);
551/// let union = a | b;
552/// assert_eq!(union.to_string(), "1..=100");
553/// ```
554#[derive(Debug, Clone)]
555#[must_use = "iterators are lazy and do nothing unless consumed"]
556pub struct CheckSortedDisjoint<T, I>
557where
558    T: Integer,
559    I: Iterator<Item = RangeInclusive<T>>,
560{
561    pub(crate) iter: I,
562    prev_end: Option<T>,
563    seen_none: bool,
564}
565
566impl<T: Integer, I> SortedDisjoint<T> for CheckSortedDisjoint<T, I> where
567    I: Iterator<Item = RangeInclusive<T>>
568{
569}
570impl<T: Integer, I> SortedStarts<T> for CheckSortedDisjoint<T, I> where
571    I: Iterator<Item = RangeInclusive<T>>
572{
573}
574
575impl<T, I> CheckSortedDisjoint<T, I>
576where
577    T: Integer,
578    I: Iterator<Item = RangeInclusive<T>>,
579{
580    /// Creates a new [`CheckSortedDisjoint`] from an iterator of ranges. See [`CheckSortedDisjoint`] for details and examples.
581    pub fn new<J: IntoIterator<IntoIter = I>>(iter: J) -> Self {
582        CheckSortedDisjoint {
583            iter: iter.into_iter(),
584            prev_end: None,
585            seen_none: false,
586        }
587    }
588}
589
590impl<T> Default for CheckSortedDisjoint<T, core::array::IntoIter<RangeInclusive<T>, 0>>
591where
592    T: Integer,
593{
594    // Default is an empty iterator.
595    fn default() -> Self {
596        Self::new([])
597    }
598}
599
600impl<T, I> FusedIterator for CheckSortedDisjoint<T, I>
601where
602    T: Integer,
603    I: Iterator<Item = RangeInclusive<T>> + FusedIterator,
604{
605}
606
607impl<T, I> Iterator for CheckSortedDisjoint<T, I>
608where
609    T: Integer,
610    I: Iterator<Item = RangeInclusive<T>>,
611{
612    type Item = RangeInclusive<T>;
613
614    fn next(&mut self) -> Option<Self::Item> {
615        let next = self.iter.next();
616
617        let Some(range) = next.as_ref() else {
618            self.seen_none = true;
619            return next;
620        };
621
622        assert!(
623            !self.seen_none,
624            "iterator cannot return Some after returning None"
625        );
626        let (start, end) = range.clone().into_inner();
627        assert!(start <= end, "start must be less or equal to end");
628        assert!(
629            end <= T::safe_max_value(),
630            "end must be less than or equal to safe_max_value"
631        );
632        if let Some(prev_end) = self.prev_end {
633            assert!(
634                prev_end < T::safe_max_value() && prev_end + T::one() < start,
635                "ranges must be disjoint"
636            );
637        }
638        self.prev_end = Some(end);
639
640        next
641    }
642
643    fn size_hint(&self) -> (usize, Option<usize>) {
644        self.iter.size_hint()
645    }
646}
647
648impl<T: Integer, const N: usize> From<[RangeInclusive<T>; N]>
649    for CheckSortedDisjoint<T, core::array::IntoIter<RangeInclusive<T>, N>>
650{
651    /// You may create a [`CheckSortedDisjoint`] from an array of integers.
652    ///
653    /// # Examples
654    ///
655    /// ```
656    /// use range_set_blaze::prelude::*;
657    ///
658    /// let a0 = CheckSortedDisjoint::from([1..=3, 100..=100]);
659    /// let a1: CheckSortedDisjoint<_,_> = [1..=3, 100..=100].into();
660    /// assert_eq!(a0.to_string(), "1..=3, 100..=100");
661    /// assert_eq!(a1.to_string(), "1..=3, 100..=100");
662    /// ```
663    fn from(arr: [RangeInclusive<T>; N]) -> Self {
664        let iter = arr.into_iter();
665        Self::new(iter)
666    }
667}
668
669impl<T: Integer, I> ops::Not for CheckSortedDisjoint<T, I>
670where
671    I: Iterator<Item = RangeInclusive<T>>,
672{
673    type Output = NotIter<T, Self>;
674
675    fn not(self) -> Self::Output {
676        self.complement()
677    }
678}
679
680impl<T: Integer, R, L> ops::BitOr<R> for CheckSortedDisjoint<T, L>
681where
682    L: Iterator<Item = RangeInclusive<T>>,
683    R: SortedDisjoint<T>,
684{
685    type Output = BitOrMerge<T, Self, R>;
686
687    fn bitor(self, other: R) -> Self::Output {
688        SortedDisjoint::union(self, other)
689    }
690}
691
692impl<T: Integer, R, L> ops::BitAnd<R> for CheckSortedDisjoint<T, L>
693where
694    L: Iterator<Item = RangeInclusive<T>>,
695    R: SortedDisjoint<T>,
696{
697    type Output = BitAndMerge<T, Self, R>;
698
699    fn bitand(self, other: R) -> Self::Output {
700        SortedDisjoint::intersection(self, other)
701    }
702}
703
704impl<T: Integer, R, L> ops::Sub<R> for CheckSortedDisjoint<T, L>
705where
706    L: Iterator<Item = RangeInclusive<T>>,
707    R: SortedDisjoint<T>,
708{
709    type Output = BitSubMerge<T, Self, R>;
710
711    fn sub(self, other: R) -> Self::Output {
712        SortedDisjoint::difference(self, other)
713    }
714}
715
716impl<T: Integer, R, L> ops::BitXor<R> for CheckSortedDisjoint<T, L>
717where
718    L: Iterator<Item = RangeInclusive<T>>,
719    R: SortedDisjoint<T>,
720{
721    type Output = BitXOrTee<T, Self, R>;
722
723    fn bitxor(self, other: R) -> Self::Output {
724        SortedDisjoint::symmetric_difference(self, other)
725    }
726}