range_set_blaze/sorted_disjoint.rs
1use crate::RangeSetBlaze;
2use crate::map::ValueRef;
3use crate::range_values::{MapIntoRangesIter, MapRangesIter, RangeValuesToRangesIter};
4use crate::ranges_iter::RangesIter;
5use crate::sorted_disjoint_map::IntoString;
6use crate::{IntoRangesIter, UnionIter, UnionMerge};
7use alloc::string::String;
8use core::{
9 array,
10 iter::{
11 Empty, Filter, FlatMap, Flatten, Fuse, FusedIterator, Once, Peekable, Skip, SkipWhile,
12 Take, TakeWhile,
13 },
14 ops::{self, RangeInclusive},
15 option,
16};
17
18use crate::SortedDisjointMap;
19
20use crate::{
21 DifferenceMerge, DynSortedDisjoint, Integer, IntersectionMerge, Merge, NotIter, SymDiffIter,
22 SymDiffMerge,
23};
24
25/// Used internally. Marks iterators that provide ranges sorted by start, but
26/// that are not necessarily disjoint. The ranges are non-empty.
27pub trait SortedStarts<T: Integer>: Iterator<Item = RangeInclusive<T>> + FusedIterator {}
28
29impl<T: Integer, I, P> SortedStarts<T> for Filter<I, P>
30where
31 I: SortedStarts<T>,
32 P: FnMut(&I::Item) -> bool,
33{
34}
35
36impl<T: Integer, I, P> SortedDisjoint<T> for Filter<I, P>
37where
38 I: SortedDisjoint<T>,
39 P: FnMut(&I::Item) -> bool,
40{
41}
42
43impl<T: Integer, I, P> SortedStarts<T> for TakeWhile<I, P>
44where
45 I: SortedStarts<T>,
46 P: FnMut(&I::Item) -> bool,
47{
48}
49
50impl<T: Integer, I, P> SortedDisjoint<T> for TakeWhile<I, P>
51where
52 I: SortedDisjoint<T>,
53 P: FnMut(&I::Item) -> bool,
54{
55}
56
57impl<T: Integer, I, P> SortedStarts<T> for SkipWhile<I, P>
58where
59 I: SortedStarts<T>,
60 P: FnMut(&I::Item) -> bool,
61{
62}
63
64impl<T: Integer, I, P> SortedDisjoint<T> for SkipWhile<I, P>
65where
66 I: SortedDisjoint<T>,
67 P: FnMut(&I::Item) -> bool,
68{
69}
70
71impl<T, I> SortedStarts<T> for Flatten<option::IntoIter<I>>
72where
73 T: Integer,
74 I: SortedStarts<T>,
75{
76}
77
78impl<T, I> SortedDisjoint<T> for Flatten<option::IntoIter<I>>
79where
80 T: Integer,
81 I: SortedDisjoint<T>,
82{
83}
84impl<T, I, IInner, TMap> SortedStarts<T> for FlatMap<option::IntoIter<I>, IInner, TMap>
85where
86 T: Integer,
87 IInner: SortedStarts<T>,
88 I: SortedStarts<T>,
89 TMap: FnMut(I) -> IInner,
90{
91}
92
93impl<T, I, IInner, TMap> SortedDisjoint<T> for FlatMap<option::IntoIter<I>, IInner, TMap>
94where
95 T: Integer,
96 IInner: SortedDisjoint<T>,
97 I: SortedDisjoint<T>,
98 TMap: FnMut(I) -> IInner,
99{
100}
101
102// Potential future support for core::iter::StepBy once it implements FusedIterator:
103// https://internals.rust-lang.org/t/implement-fusediterator-for-core-stepby/24074
104//
105// Check if core::iter::StepBy implements FusedIterator if it's inner is. Seems like it could be upstreamed
106// https://internals.rust-lang.org/t/implement-fusediterator-for-core-stepby/24074
107// impl<T: Integer, I> SortedStarts<T> for core::iter::Fuse<core::iter::StepBy<I>> where
108// I: SortedStarts<T>
109// {
110// }
111// impl<T: Integer, I> SortedDisjoint<T> for core::iter::Fuse<core::iter::StepBy<I>> where
112// I: SortedDisjoint<T>
113// {
114// }
115
116impl<T: Integer, I> SortedStarts<T> for Fuse<I> where I: SortedStarts<T> {}
117impl<T: Integer, I> SortedDisjoint<T> for Fuse<I> where I: SortedDisjoint<T> {}
118
119impl<T: Integer, I> SortedStarts<T> for Skip<I> where I: SortedStarts<T> {}
120impl<T: Integer, I> SortedDisjoint<T> for Skip<I> where I: SortedDisjoint<T> {}
121
122impl<T: Integer, I> SortedStarts<T> for Take<I> where I: SortedStarts<T> {}
123impl<T: Integer, I> SortedDisjoint<T> for Take<I> where I: SortedDisjoint<T> {}
124
125impl<T: Integer, I> SortedStarts<T> for Peekable<I> where I: SortedStarts<T> {}
126impl<T: Integer, I> SortedDisjoint<T> for Peekable<I> where I: SortedDisjoint<T> {}
127
128impl<T: Integer> SortedStarts<T> for Empty<RangeInclusive<T>> {}
129impl<T: Integer> SortedDisjoint<T> for Empty<RangeInclusive<T>> {}
130
131impl<T: Integer> SortedStarts<T> for Once<RangeInclusive<T>> {}
132impl<T: Integer> SortedDisjoint<T> for Once<RangeInclusive<T>> {}
133
134/// Marks iterators that provide ranges that are sorted by start and disjoint. Set operations on
135/// iterators that implement this trait can be performed in linear time.
136///
137/// # Table of Contents
138/// * [`SortedDisjoint` Constructors](#sorteddisjoint-constructors)
139/// * [Examples](#constructor-examples)
140/// * [`SortedDisjoint` Set Operations](#sorteddisjoint-set-operations)
141/// * [Performance](#performance)
142/// * [Examples](#examples)
143/// * [How to mark your type as `SortedDisjoint`](#how-to-mark-your-type-as-sorteddisjoint)
144/// * [Example – Find the ordinal weekdays in September 2023](#example--find-the-ordinal-weekdays-in-september-2023)
145///
146/// # `SortedDisjoint` Constructors
147///
148/// You'll usually construct a `SortedDisjoint` iterator from a [`RangeSetBlaze`] or a [`CheckSortedDisjoint`].
149/// Here is a summary table, followed by [examples](#constructor-examples). You can also [define your own
150/// `SortedDisjoint`](#how-to-mark-your-type-as-sorteddisjoint).
151///
152/// | Input type | Method |
153/// |------------|--------|
154/// | [`RangeSetBlaze`] | [`ranges`] |
155/// | [`RangeSetBlaze`] | [`into_ranges`] |
156/// | sorted & disjoint ranges | [`CheckSortedDisjoint::new`] |
157/// | [`RangeInclusive`] | [`RangeOnce::new`] |
158/// | *your iterator type* | *[How to mark your type as `SortedDisjoint`][1]* |
159///
160/// [`ranges`]: RangeSetBlaze::ranges
161/// [`into_ranges`]: RangeSetBlaze::into_ranges
162/// [1]: #how-to-mark-your-type-as-sorteddisjoint
163/// [`RangesIter`]: crate::RangesIter
164/// [SortedDisjoint]: crate::SortedDisjoint.html#table-of-contents
165///
166/// ## Constructor Examples
167/// ```
168/// use range_set_blaze::prelude::*;
169///
170/// // RangeSetBlaze's .ranges() and .into_ranges()
171/// let r = RangeSetBlaze::from_iter([3, 2, 1, 100, 1]);
172/// let a = r.ranges();
173/// assert!(a.into_string() == "1..=3, 100..=100");
174/// // 'into_ranges' takes ownership of the 'RangeSetBlaze'
175/// let a = RangeSetBlaze::from_iter([3, 2, 1, 100, 1]).into_ranges();
176/// assert!(a.into_string() == "1..=3, 100..=100");
177///
178/// // CheckSortedDisjoint -- unsorted or overlapping input ranges will cause a panic.
179/// let a = CheckSortedDisjoint::new([1..=3, 100..=100]);
180/// assert!(a.into_string() == "1..=3, 100..=100");
181/// ```
182///
183/// # `SortedDisjoint` Set Operations
184///
185/// You can perform set operations on `SortedDisjoint`s using operators.
186///
187/// | Set Operators | Operator | Multiway (same type) | Multiway (different types) |
188/// |------------------------------------|-------------|---------------------------------------------------|--------------------------------------|
189/// | [`union`] | [`a` | `b`] | <code>[a, b, c].[union][multiway_union]() </code> | <code>[union_dyn!][union_dyn_macro](a, b, c)</code> |
190/// | [`intersection`] | [`a & b`] | <code>[a, b, c].[intersection][multiway_intersection]() </code> | <code>[intersection_dyn!][intersection_dyn_macro](a, b, c)</code>|
191/// | [`difference`] | [`a - b`] | *n/a* | *n/a* |
192/// | [`symmetric_difference`] | [`a ^ b`] | <code>[a, b, c].[symmetric_difference][multiway_symmetric_difference]() </code> | <code>[symmetric_difference_dyn!][symmetric_difference_dyn_macro](a, b, c)</code> |
193/// | [`complement`] | [`!a`] | *n/a* | *n/a* |
194///
195/// [`a` | `b`]: trait.SortedDisjoint.html#method.union
196/// [`a & b`]: trait.SortedDisjoint.html#method.intersection
197/// [`a - b`]: trait.SortedDisjoint.html#method.difference
198/// [`a ^ b`]: trait.SortedDisjoint.html#method.symmetric_difference
199/// [`!a`]: trait.SortedDisjoint.html#method.complement
200/// [multiway_union]: trait.MultiwaySortedDisjoint.html#method.union
201/// [multiway_intersection]: trait.MultiwaySortedDisjoint.html#method.intersection
202/// [multiway_symmetric_difference]: trait.MultiwaySortedDisjoint.html#method.symmetric_difference
203/// [union_dyn_macro]: macro@crate::union_dyn
204/// [intersection_dyn_macro]: macro@crate::intersection_dyn
205/// [symmetric_difference_dyn_macro]: macro@crate::symmetric_difference_dyn
206/// ## Performance
207///
208/// Every operation is implemented as a single pass over the sorted & disjoint ranges, with minimal memory.
209///
210/// This is true even when applying multiple operations. The last example below demonstrates this.
211///
212/// ## Standard Iterators
213///
214/// Many `core::iter` adapters preserve this marker trait when the inner iterator already
215/// implements it, including `filter`, `take_while`, `skip_while`, `fuse`, `skip`, `take`,
216/// and `peekable`. `empty`/`once` iterators and `Option`-based `flatten`/`flat_map` are also
217/// supported.
218///
219/// ## Examples
220///
221/// ```
222/// use range_set_blaze::prelude::*;
223///
224/// let a0 = RangeSetBlaze::from_iter([1..=2, 5..=100]);
225/// let b0 = RangeSetBlaze::from_iter([2..=6]);
226///
227/// // 'union' method and 'to_string' method
228/// let (a, b) = (a0.ranges(), b0.ranges());
229/// let result = a.union(b);
230/// assert_eq!(result.into_string(), "1..=100");
231///
232/// // '|' operator and 'equal' method
233/// let (a, b) = (a0.ranges(), b0.ranges());
234/// let result = a | b;
235/// assert!(result.equal(CheckSortedDisjoint::new([1..=100])));
236///
237/// // multiway union of same type
238/// let c0 = RangeSetBlaze::from_iter([2..=2, 6..=200]);
239/// let (a, b, c) = (a0.ranges(), b0.ranges(), c0.ranges());
240/// let result = [a, b, c].union();
241/// assert_eq!(result.into_string(), "1..=200");
242///
243/// // multiway union of different types
244/// let (a, b, c) = (a0.ranges(), b0.ranges(), c0.ranges());
245/// let result = union_dyn!(a, b, !c);
246/// assert_eq!(result.into_string(), "-2147483648..=100, 201..=2147483647");
247///
248/// // Applying multiple operators makes only one pass through the inputs with minimal memory.
249/// let (a, b, c) = (a0.ranges(), b0.ranges(), c0.ranges());
250/// let result = a - (b | c);
251/// assert!(result.into_string() == "1..=1");
252/// ```
253///
254/// # How to mark your type as `SortedDisjoint`
255///
256/// To mark your iterator type as `SortedDisjoint`, you implement the `SortedStarts` and `SortedDisjoint` traits.
257/// This is your promise to the compiler that your iterator will provide inclusive ranges that are
258/// disjoint and sorted by start.
259///
260/// When you do this, your iterator will get access to the
261/// efficient set operations methods, such as [`intersection`] and [`complement`]. The example below shows this.
262///
263/// > To use operators such as `&` and `!`, you must also implement the [`BitAnd`], [`Not`], etc. traits.
264/// >
265/// > If you want others to use your marked iterator type, reexport:
266/// > `pub use range_set_blaze::{SortedDisjoint, SortedStarts};`
267///
268/// [`BitAnd`]: core::ops::BitAnd
269/// [`Not`]: core::ops::Not
270/// [`intersection`]: SortedDisjoint::intersection
271/// [`complement`]: SortedDisjoint::complement
272/// [`union`]: SortedDisjoint::union
273/// [`symmetric_difference`]: SortedDisjoint::symmetric_difference
274/// [`difference`]: SortedDisjoint::difference
275/// [`to_string`]: SortedDisjoint::to_string
276/// [`equal`]: SortedDisjoint::equal
277/// [multiway_union]: crate::MultiwaySortedDisjoint::union
278/// [multiway_intersection]: crate::MultiwaySortedDisjoint::intersection
279///
280/// ## Example -- Find the ordinal weekdays in September 2023
281/// ```
282/// use core::ops::RangeInclusive;
283/// use core::iter::FusedIterator;
284/// pub use range_set_blaze::{SortedDisjoint, SortedStarts};
285///
286/// // Ordinal dates count January 1 as day 1, February 1 as day 32, etc.
287/// struct OrdinalWeekends2023 {
288/// next_range: RangeInclusive<i32>,
289/// }
290///
291/// // We promise the compiler that our iterator will provide
292/// // ranges that are sorted and disjoint.
293/// impl FusedIterator for OrdinalWeekends2023 {}
294/// impl SortedStarts<i32> for OrdinalWeekends2023 {}
295/// impl SortedDisjoint<i32> for OrdinalWeekends2023 {}
296///
297/// impl OrdinalWeekends2023 {
298/// fn new() -> Self {
299/// Self { next_range: 0..=1 }
300/// }
301/// }
302/// impl Iterator for OrdinalWeekends2023 {
303/// type Item = RangeInclusive<i32>;
304/// fn next(&mut self) -> Option<Self::Item> {
305/// let (start, end) = self.next_range.clone().into_inner();
306/// if start > 365 {
307/// None
308/// } else {
309/// self.next_range = (start + 7)..=(end + 7);
310/// Some(start.max(1)..=end.min(365))
311/// }
312/// }
313/// }
314///
315/// use range_set_blaze::prelude::*;
316///
317/// let weekends = OrdinalWeekends2023::new();
318/// let september = CheckSortedDisjoint::new([244..=273]);
319/// let september_weekdays = september.intersection(weekends.complement());
320/// assert_eq!(
321/// september_weekdays.into_string(),
322/// "244..=244, 247..=251, 254..=258, 261..=265, 268..=272"
323/// );
324/// ```
325pub trait SortedDisjoint<T: Integer>: SortedStarts<T> {
326 // I think this is 'Sized' because will sometimes want to create a struct (e.g. BitOrIter) that contains a field of this type
327
328 /// Given two [`SortedDisjoint`] iterators, efficiently returns a [`SortedDisjoint`] iterator of their union.
329 ///
330 /// [SortedDisjoint]: crate::SortedDisjoint.html#table-of-contents
331 ///
332 /// # Examples
333 ///
334 /// ```
335 /// use range_set_blaze::prelude::*;
336 ///
337 /// let a = CheckSortedDisjoint::new([1..=1]);
338 /// let b = RangeSetBlaze::from_iter([2..=2]).into_ranges();
339 /// let union = a.union(b);
340 /// assert_eq!(union.into_string(), "1..=2");
341 ///
342 /// // Alternatively, we can use "|" because CheckSortedDisjoint defines
343 /// // ops::bitor as SortedDisjoint::union.
344 /// let a = CheckSortedDisjoint::new([1..=1]);
345 /// let b = RangeSetBlaze::from_iter([2..=2]).into_ranges();
346 /// let union = a | b;
347 /// assert_eq!(union.into_string(), "1..=2");
348 /// ```
349 #[inline]
350 fn union<R>(self, other: R) -> UnionMerge<T, Self, R::IntoIter>
351 where
352 R: IntoIterator<Item = Self::Item>,
353 R::IntoIter: SortedDisjoint<T>,
354 Self: Sized,
355 {
356 UnionMerge::new2(self, other.into_iter())
357 }
358
359 /// Given two [`SortedDisjoint`] iterators, efficiently returns a [`SortedDisjoint`] iterator of their intersection.
360 ///
361 /// [SortedDisjoint]: crate::SortedDisjoint.html#table-of-contents
362 ///
363 /// # Examples
364 ///
365 /// ```
366 /// use range_set_blaze::prelude::*;
367 ///
368 /// let a = CheckSortedDisjoint::new([1..=2]);
369 /// let b = RangeSetBlaze::from_iter([2..=3]).into_ranges();
370 /// let intersection = a.intersection(b);
371 /// assert_eq!(intersection.into_string(), "2..=2");
372 ///
373 /// // Alternatively, we can use "&" because CheckSortedDisjoint defines
374 /// // ops::bitand as SortedDisjoint::intersection.
375 /// let a = CheckSortedDisjoint::new([1..=2]);
376 /// let b = RangeSetBlaze::from_iter([2..=3]).into_ranges();
377 /// let intersection = a & b;
378 /// assert_eq!(intersection.into_string(), "2..=2");
379 /// ```
380 #[inline]
381 fn intersection<R>(self, other: R) -> IntersectionMerge<T, Self, R::IntoIter>
382 where
383 R: IntoIterator<Item = Self::Item>,
384 R::IntoIter: SortedDisjoint<T>,
385 Self: Sized,
386 {
387 !(self.complement() | other.into_iter().complement())
388 }
389
390 /// Given two [`SortedDisjoint`] iterators, efficiently returns a [`SortedDisjoint`] iterator of their set difference.
391 ///
392 /// [SortedDisjoint]: crate::SortedDisjoint.html#table-of-contents
393 ///
394 /// # Examples
395 ///
396 /// ```
397 /// use range_set_blaze::prelude::*;
398 ///
399 /// let a = CheckSortedDisjoint::new([1..=2]);
400 /// let b = RangeSetBlaze::from_iter([2..=3]).into_ranges();
401 /// let difference = a.difference(b);
402 /// assert_eq!(difference.into_string(), "1..=1");
403 ///
404 /// // Alternatively, we can use "-" because CheckSortedDisjoint defines
405 /// // ops::sub as SortedDisjoint::difference.
406 /// let a = CheckSortedDisjoint::new([1..=2]);
407 /// let b = RangeSetBlaze::from_iter([2..=3]).into_ranges();
408 /// let difference = a - b;
409 /// assert_eq!(difference.into_string(), "1..=1");
410 /// ```
411 #[inline]
412 fn difference<R>(self, other: R) -> DifferenceMerge<T, Self, R::IntoIter>
413 where
414 R: IntoIterator<Item = Self::Item>,
415 R::IntoIter: SortedDisjoint<T>,
416 Self: Sized,
417 {
418 !(self.complement() | other.into_iter())
419 }
420
421 /// Given a [`SortedDisjoint`] iterator, efficiently returns a [`SortedDisjoint`] iterator of its complement.
422 ///
423 /// [SortedDisjoint]: crate::SortedDisjoint.html#table-of-contents
424 ///
425 /// # Examples
426 ///
427 /// ```
428 /// use range_set_blaze::prelude::*;
429 ///
430 /// let a = CheckSortedDisjoint::new([10_u8..=20, 100..=200]);
431 /// let complement = a.complement();
432 /// assert_eq!(complement.into_string(), "0..=9, 21..=99, 201..=255");
433 ///
434 /// // Alternatively, we can use "!" because CheckSortedDisjoint defines
435 /// // `ops::Not` as `SortedDisjoint::complement`.
436 /// let a = CheckSortedDisjoint::new([10_u8..=20, 100..=200]);
437 /// let complement = !a;
438 /// assert_eq!(complement.into_string(), "0..=9, 21..=99, 201..=255");
439 /// ```
440 #[inline]
441 fn complement(self) -> NotIter<T, Self>
442 where
443 Self: Sized,
444 {
445 NotIter::new(self)
446 }
447
448 /// Given two [`SortedDisjoint`] iterators, efficiently returns a [`SortedDisjoint`] iterator
449 /// of their symmetric difference.
450 ///
451 /// [SortedDisjoint]: crate::SortedDisjoint.html#table-of-contents
452 /// # Examples
453 ///
454 /// ```
455 /// use range_set_blaze::prelude::*;
456 ///
457 /// let a = CheckSortedDisjoint::new([1..=2]);
458 /// let b = RangeSetBlaze::from_iter([2..=3]).into_ranges();
459 /// let symmetric_difference = a.symmetric_difference(b);
460 /// assert_eq!(symmetric_difference.into_string(), "1..=1, 3..=3");
461 ///
462 /// // Alternatively, we can use "^" because CheckSortedDisjoint defines
463 /// // ops::bitxor as SortedDisjoint::symmetric_difference.
464 /// let a = CheckSortedDisjoint::new([1..=2]);
465 /// let b = RangeSetBlaze::from_iter([2..=3]).into_ranges();
466 /// let symmetric_difference = a ^ b;
467 /// assert_eq!(symmetric_difference.into_string(), "1..=1, 3..=3");
468 /// ```
469 #[inline]
470 fn symmetric_difference<R>(self, other: R) -> SymDiffMerge<T, Self, R::IntoIter>
471 where
472 R: IntoIterator<Item = Self::Item>,
473 R::IntoIter: SortedDisjoint<T>,
474 <R as IntoIterator>::IntoIter:,
475 Self: Sized,
476 {
477 let result: SymDiffIter<T, Merge<T, Self, <R as IntoIterator>::IntoIter>> =
478 SymDiffIter::new2(self, other.into_iter());
479 result
480 }
481
482 /// Given two [`SortedDisjoint`] iterators, efficiently tells if they are equal. Unlike most equality testing in Rust,
483 /// this method takes ownership of the iterators and consumes them.
484 ///
485 /// [SortedDisjoint]: crate::SortedDisjoint.html#table-of-contents
486 ///
487 /// # Examples
488 ///
489 /// ```
490 /// use range_set_blaze::prelude::*;
491 ///
492 /// let a = CheckSortedDisjoint::new([1..=2]);
493 /// let b = RangeSetBlaze::from_iter([1..=2]).into_ranges();
494 /// assert!(a.equal(b));
495 /// ```
496 fn equal<R>(self, other: R) -> bool
497 where
498 R: IntoIterator<Item = Self::Item>,
499 R::IntoIter: SortedDisjoint<T>,
500 Self: Sized,
501 {
502 itertools::equal(self, other)
503 }
504
505 /// Deprecated. Use [`into_string`] instead.
506 ///
507 /// [`into_string`]: trait.IntoString.html
508 #[deprecated(since = "0.2.0", note = "Use `into_string` instead")]
509 fn to_string(self) -> String
510 where
511 Self: Sized,
512 {
513 self.into_string()
514 }
515
516 /// Returns `true` if the set contains no elements.
517 ///
518 /// # Examples
519 ///
520 /// ```
521 /// use range_set_blaze::prelude::*;
522 ///
523 /// let a = CheckSortedDisjoint::new([1..=2]);
524 /// assert!(!a.is_empty());
525 /// ```
526 #[inline]
527 #[allow(clippy::wrong_self_convention)]
528 fn is_empty(mut self) -> bool
529 where
530 Self: Sized,
531 {
532 self.next().is_none()
533 }
534
535 /// Returns `true` if the set contains all possible integers.
536 ///
537 /// For type `T`, this means exactly one range spanning `T::min_value()`..=`T::max_value()`.
538 /// Complexity: O(1) on the first item.
539 ///
540 /// # Examples
541 ///
542 /// ```
543 /// use range_set_blaze::prelude::*;
544 ///
545 /// let a = CheckSortedDisjoint::new([1_u8..=2]);
546 /// assert!(!a.is_universal());
547 ///
548 /// let universal = CheckSortedDisjoint::new([0_u8..=255]);
549 /// assert!(universal.is_universal());
550 /// ```
551 #[inline]
552 #[allow(clippy::wrong_self_convention)]
553 fn is_universal(mut self) -> bool
554 where
555 Self: Sized,
556 {
557 self.next().is_some_and(|range| {
558 let (start, end) = range.into_inner();
559 start == T::min_value() && end == T::max_value()
560 })
561 }
562
563 /// Returns `true` if the set is a subset of another,
564 /// i.e., `other` contains at least all the elements in `self`.
565 ///
566 /// # Examples
567 ///
568 /// ```
569 /// use range_set_blaze::prelude::*;
570 ///
571 /// let sup = CheckSortedDisjoint::new([1..=3]);
572 /// let set: CheckSortedDisjoint<i32, _> = [].into();
573 /// assert_eq!(set.is_subset(sup), true);
574 ///
575 /// let sup = CheckSortedDisjoint::new([1..=3]);
576 /// let set = CheckSortedDisjoint::new([2..=2]);
577 /// assert_eq!(set.is_subset(sup), true);
578 ///
579 /// let sup = CheckSortedDisjoint::new([1..=3]);
580 /// let set = CheckSortedDisjoint::new([2..=2, 4..=4]);
581 /// assert_eq!(set.is_subset(sup), false);
582 /// ```
583 #[must_use]
584 #[inline]
585 #[allow(clippy::wrong_self_convention)]
586 fn is_subset<R>(self, other: R) -> bool
587 where
588 R: IntoIterator<Item = Self::Item>,
589 R::IntoIter: SortedDisjoint<T>,
590 Self: Sized,
591 {
592 // LATER: Could be made a little more efficient by coding the logic directly into the iterators.
593 self.difference(other).is_empty()
594 }
595
596 /// Returns `true` if the set is a superset of another,
597 /// i.e., `self` contains at least all the elements in `other`.
598 ///
599 /// # Examples
600 ///
601 /// ```
602 /// use range_set_blaze::RangeSetBlaze;
603 ///
604 /// let sub = RangeSetBlaze::from_iter([1, 2]);
605 /// let mut set = RangeSetBlaze::new();
606 ///
607 /// assert_eq!(set.is_superset(&sub), false);
608 ///
609 /// set.insert(0);
610 /// set.insert(1);
611 /// assert_eq!(set.is_superset(&sub), false);
612 ///
613 /// set.insert(2);
614 /// assert_eq!(set.is_superset(&sub), true);
615 /// ```
616 #[inline]
617 #[must_use]
618 #[allow(clippy::wrong_self_convention)]
619 fn is_superset<R>(self, other: R) -> bool
620 where
621 R: IntoIterator<Item = Self::Item>,
622 R::IntoIter: SortedDisjoint<T>,
623 Self: Sized,
624 {
625 other.into_iter().is_subset(self)
626 }
627
628 /// Returns `true` if `self` has no elements in common with `other`.
629 /// This is equivalent to checking for an empty intersection.
630 ///
631 /// # Examples
632 ///
633 /// ```
634 /// use range_set_blaze::RangeSetBlaze;
635 ///
636 /// let a = RangeSetBlaze::from_iter([1..=3]);
637 /// let mut b = RangeSetBlaze::new();
638 ///
639 /// assert_eq!(a.is_disjoint(&b), true);
640 /// b.insert(4);
641 /// assert_eq!(a.is_disjoint(&b), true);
642 /// b.insert(1);
643 /// assert_eq!(a.is_disjoint(&b), false);
644 /// ```
645 #[must_use]
646 #[inline]
647 #[allow(clippy::wrong_self_convention)]
648 fn is_disjoint<R>(self, other: R) -> bool
649 where
650 R: IntoIterator<Item = Self::Item>,
651 R::IntoIter: SortedDisjoint<T>,
652 Self: Sized,
653 {
654 self.intersection(other).is_empty()
655 }
656
657 /// Create a [`RangeSetBlaze`] from a [`SortedDisjoint`] iterator.
658 ///
659 /// *For more about constructors and performance, see [`RangeSetBlaze` Constructors](struct.RangeSetBlaze.html#rangesetblaze-constructors).*
660 ///
661 /// [SortedDisjoint]: crate::SortedDisjoint.html#table-of-contents
662 ///
663 /// # Examples
664 ///
665 /// ```
666 /// use range_set_blaze::prelude::*;
667 ///
668 /// let a0 = RangeSetBlaze::from_sorted_disjoint(CheckSortedDisjoint::new([-10..=-5, 1..=2]));
669 /// let a1: RangeSetBlaze<i32> = CheckSortedDisjoint::new([-10..=-5, 1..=2]).into_range_set_blaze();
670 /// assert!(a0 == a1 && a0.to_string() == "-10..=-5, 1..=2");
671 /// ```
672 fn into_range_set_blaze(self) -> RangeSetBlaze<T>
673 where
674 Self: Sized,
675 {
676 RangeSetBlaze::from_sorted_disjoint(self)
677 }
678}
679
680/// Gives the [`SortedDisjoint`] trait to any iterator of ranges. The iterator will panic
681/// if/when it finds that the ranges are not actually sorted and disjoint.
682///
683/// [SortedDisjoint]: crate::SortedDisjoint.html#table-of-contents
684///
685/// # Performance
686///
687/// All checking is done at runtime, but it should still be fast.
688///
689/// # Example
690///
691/// ```
692/// use range_set_blaze::prelude::*;
693///
694/// let a = CheckSortedDisjoint::new([1..=2, 5..=100]);
695/// let b = CheckSortedDisjoint::new([2..=6]);
696/// let union = a | b;
697/// assert_eq!(union.into_string(), "1..=100");
698/// ```
699///
700/// Here the ranges are not sorted and disjoint, so the iterator will panic.
701///```should_panic
702/// use range_set_blaze::prelude::*;
703///
704/// let a = CheckSortedDisjoint::new([1..=2, 5..=100]);
705/// let b = CheckSortedDisjoint::new([2..=6,-10..=-5]);
706/// let union = a | b;
707/// assert_eq!(union.into_string(), "1..=100");
708/// ```
709#[derive(Debug, Clone)]
710#[must_use = "iterators are lazy and do nothing unless consumed"]
711#[allow(clippy::module_name_repetitions)]
712pub struct CheckSortedDisjoint<T, I> {
713 pub(crate) iter: I,
714 prev_end: Option<T>,
715 seen_none: bool,
716}
717
718impl<T, I> CheckSortedDisjoint<T, I>
719where
720 T: Integer,
721 I: Iterator<Item = RangeInclusive<T>> + FusedIterator,
722{
723 /// Creates a new [`CheckSortedDisjoint`] from an iterator of ranges. See [`CheckSortedDisjoint`] for details and examples.
724 #[inline]
725 pub fn new<J: IntoIterator<IntoIter = I>>(iter: J) -> Self {
726 Self {
727 iter: iter.into_iter(),
728 prev_end: None,
729 seen_none: false,
730 }
731 }
732}
733
734impl<T: Integer> Default for CheckSortedDisjoint<T, array::IntoIter<RangeInclusive<T>, 0>> {
735 // Default is an empty iterator.
736 fn default() -> Self {
737 Self::new([])
738 }
739}
740
741impl<T, I> FusedIterator for CheckSortedDisjoint<T, I>
742where
743 T: Integer,
744 I: Iterator<Item = RangeInclusive<T>> + FusedIterator,
745{
746}
747
748impl<T, I> Iterator for CheckSortedDisjoint<T, I>
749where
750 T: Integer,
751 I: Iterator<Item = RangeInclusive<T>> + FusedIterator,
752{
753 type Item = RangeInclusive<T>;
754
755 fn next(&mut self) -> Option<Self::Item> {
756 let next = self.iter.next();
757
758 let Some(range) = next.as_ref() else {
759 self.seen_none = true;
760 return next;
761 };
762
763 assert!(
764 !self.seen_none,
765 "iterator cannot return Some after returning None"
766 );
767 let (start, end) = range.clone().into_inner();
768 assert!(start <= end, "start must be less or equal to end");
769 if let Some(prev_end) = self.prev_end {
770 assert!(
771 prev_end < T::max_value() && prev_end.add_one() < start,
772 "ranges must be disjoint"
773 );
774 }
775 self.prev_end = Some(end);
776
777 next
778 }
779
780 fn size_hint(&self) -> (usize, Option<usize>) {
781 self.iter.size_hint()
782 }
783}
784
785impl<T: Integer, const N: usize> From<[RangeInclusive<T>; N]>
786 for CheckSortedDisjoint<T, array::IntoIter<RangeInclusive<T>, N>>
787{
788 /// Deprecated: Use `new` instead.
789 fn from(arr: [RangeInclusive<T>; N]) -> Self {
790 Self::new(arr)
791 }
792}
793
794pub trait AnythingGoes<T: Integer>: Iterator<Item = RangeInclusive<T>> + FusedIterator {}
795impl<T: Integer, I> AnythingGoes<T> for I where I: Iterator<Item = RangeInclusive<T>> + FusedIterator
796{}
797
798/// `RangeOnce` is an iterator which emits a single `RangeInclusive` value before
799/// fusing.
800///
801/// `RangeOnce` is analogous to [`core::iter::Once`], but modified to treat an
802/// empty [`RangeInclusive`] as an empty [`Iterator`]. This allows `RangeOnce`
803/// to be safely used as a [`SortedDisjoint`] Iterator.
804///
805/// # Example
806///
807/// ```
808/// use range_set_blaze::{ RangeSetBlaze, RangeOnce };
809///
810/// let a = RangeOnce::new(0..=10);
811/// let b = RangeOnce::new(3..=2); // empty range
812/// let c = RangeOnce::new(5..=15);
813///
814/// let combined = RangeSetBlaze::from_sorted_disjoint(a | b | c);
815/// assert_eq!(combined.into_string(), "0..=15");
816/// ```
817pub struct RangeOnce<T>(option::IntoIter<RangeInclusive<T>>);
818
819impl<T: Integer> RangeOnce<T> {
820 /// Creates a new [`RangeOnce`] from a single range. See [`RangeOnce`] for details and examples.
821 pub fn new(range: RangeInclusive<T>) -> Self {
822 Self((!range.is_empty()).then_some(range).into_iter())
823 }
824}
825
826impl<T: Integer> From<RangeInclusive<T>> for RangeOnce<T> {
827 #[inline]
828 fn from(value: RangeInclusive<T>) -> Self {
829 Self::new(value)
830 }
831}
832
833impl<T: Integer> Iterator for RangeOnce<T> {
834 type Item = RangeInclusive<T>;
835
836 fn next(&mut self) -> Option<Self::Item> {
837 self.0.next()
838 }
839
840 fn size_hint(&self) -> (usize, Option<usize>) {
841 self.0.size_hint()
842 }
843}
844
845impl<T: Integer> DoubleEndedIterator for RangeOnce<T> {
846 fn next_back(&mut self) -> Option<Self::Item> {
847 self.0.next_back()
848 }
849}
850
851impl<T: Integer> ExactSizeIterator for RangeOnce<T> {
852 fn len(&self) -> usize {
853 self.0.len()
854 }
855}
856
857impl<T: Integer> FusedIterator for RangeOnce<T> {}
858
859macro_rules! impl_sorted_traits_and_ops {
860 ($IterType:ty, $($more_generics:tt)*) => {
861 #[allow(single_use_lifetimes)]
862 impl<$($more_generics)*, T: Integer> SortedStarts<T> for $IterType {}
863 #[allow(single_use_lifetimes)]
864 impl<$($more_generics)*, T: Integer> SortedDisjoint<T> for $IterType {}
865
866 #[allow(single_use_lifetimes)]
867 impl<$($more_generics)*, T: Integer> ops::Not for $IterType
868 {
869 type Output = NotIter<T, Self>;
870
871 fn not(self) -> Self::Output {
872 self.complement()
873 }
874 }
875
876 #[allow(single_use_lifetimes)]
877 impl<$($more_generics)*, T: Integer, R> ops::BitOr<R> for $IterType
878 where
879 R: SortedDisjoint<T>,
880 {
881 type Output = UnionMerge<T, Self, R>;
882
883 fn bitor(self, other: R) -> Self::Output {
884 SortedDisjoint::union(self, other)
885 }
886 }
887
888 #[allow(single_use_lifetimes)]
889 impl<$($more_generics)*, T: Integer, R> ops::Sub<R> for $IterType
890 where
891 R: SortedDisjoint<T>,
892 {
893 type Output = DifferenceMerge<T, Self, R>;
894
895 fn sub(self, other: R) -> Self::Output {
896 // It would be fun to optimize !!self.iter into self.iter
897 // but that would require also considering fields 'start_not' and 'next_time_return_none'.
898 SortedDisjoint::difference(self, other)
899 }
900 }
901
902 #[allow(single_use_lifetimes)]
903 impl<$($more_generics)*, T: Integer, R> ops::BitXor<R> for $IterType
904 where
905 R: SortedDisjoint<T>,
906 {
907 type Output = SymDiffMerge<T, Self, R>;
908
909 #[allow(clippy::suspicious_arithmetic_impl)]
910 fn bitxor(self, other: R) -> Self::Output {
911 SortedDisjoint::symmetric_difference(self, other)
912 }
913 }
914
915 #[allow(single_use_lifetimes)]
916 impl<$($more_generics)*, T: Integer, R> ops::BitAnd<R> for $IterType
917 where
918 R: SortedDisjoint<T>,
919 {
920 type Output = IntersectionMerge<T, Self, R>;
921
922 fn bitand(self, other: R) -> Self::Output {
923 SortedDisjoint::intersection(self, other)
924 }
925 }
926 };
927}
928
929//CheckList: Be sure that these are all tested in 'test_every_sorted_disjoint_method'
930impl_sorted_traits_and_ops!(CheckSortedDisjoint<T, I>, I: AnythingGoes<T>);
931impl_sorted_traits_and_ops!(DynSortedDisjoint<'a, T>, 'a);
932impl_sorted_traits_and_ops!(IntoRangesIter<T>, 'ignore);
933impl_sorted_traits_and_ops!(MapIntoRangesIter<T, V>, V: Eq + Clone);
934impl_sorted_traits_and_ops!(MapRangesIter<'a, T, V>, 'a, V: Eq + Clone);
935impl_sorted_traits_and_ops!(NotIter<T, I>, I: SortedDisjoint<T>);
936impl_sorted_traits_and_ops!(RangesIter<'a, T>, 'a);
937impl_sorted_traits_and_ops!(RangeValuesToRangesIter<T, VR, I>, VR: ValueRef, I: SortedDisjointMap<T, VR>);
938impl_sorted_traits_and_ops!(SymDiffIter<T, I>, I: SortedStarts<T>);
939impl_sorted_traits_and_ops!(UnionIter<T, I>, I: SortedStarts<T>);
940impl_sorted_traits_and_ops!(RangeOnce<T>, 'ignore);
941
942#[cfg(test)]
943mod tests {
944 use super::*;
945 use core::iter::{empty, once};
946
947 #[test]
948 fn test_union_std_iters() {
949 let a = empty::<RangeInclusive<u64>>();
950 #[allow(clippy::iter_skip_zero)]
951 let b = once(10u64..=20)
952 .skip_while(|_| false)
953 .take_while(|_| true)
954 //.step_by(1)
955 .fuse()
956 .skip(0)
957 .peekable();
958 #[allow(clippy::iter_on_single_items)]
959 let b = Some(b).into_iter().flat_map(|x| x.filter(|_| true));
960 assert_eq!(Some(10u64..=20), a.union(b).next());
961 }
962}