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