repr/interval.rs
1//! <https://en.wikipedia.org/wiki/Boundary_(topology)>
2//! <https://en.wikipedia.org/wiki/Partition_of_a_set>
3//! <https://en.wikipedia.org/wiki/Sequence>
4
5use core::{
6 cmp::{max, min},
7 iter::{IntoIterator, Step},
8 ops::RangeInclusive,
9};
10
11use unconst::unconst;
12
13use crate::repr::Repr::{self, Or, Zero};
14use crate::traits::Integral;
15
16#[unconst]
17// TODO(rinarakaki) Does negative Interval (self.1 < self.0) have use case?
18#[derive_const(Clone, Default, PartialEq, PartialOrd, Ord)]
19#[derive(Copy, Debug, Eq)]
20pub struct Interval<I: const Integral>(pub I, pub I);
21
22#[unconst]
23impl<I: const Integral> Interval<I> {
24 pub const fn new(from: I, to: I) -> Self {
25 if from <= to {
26 Interval(from, to)
27 } else {
28 Interval(to, from)
29 }
30 }
31
32 pub const fn full() -> Self {
33 Interval(I::MIN, I::MAX)
34 }
35
36 /// Intersect this Interval with the given Interval and return the result.
37 ///
38 /// If the intersection is empty, then return Zero.
39 pub const fn and(self, other: Self) -> Repr<I> {
40 if max(self.0, other.0) <= min(self.1, other.1) {
41 Repr::Interval(Self::new(max(self.0, other.0), min(self.1, other.1)))
42 } else {
43 Zero
44 }
45 }
46
47 /// Union the given overlapping Interval into this Interval.
48 ///
49 /// If the two Seqs aren't contiguous, then don't union them.
50 pub const fn or(self, other: Self) -> Repr<I> {
51 if max(self.0, other.0) <= min(self.1, other.1).succ() {
52 Repr::Interval(Self::new(min(self.0, other.0), max(self.1, other.1)))
53 } else {
54 Or(
55 Box::new(Repr::Interval(self)),
56 Box::new(Repr::Interval(other)),
57 )
58 }
59 }
60
61 // /// Compute the symmetric difference the given Interval from this Interval. This
62 // /// returns the union of the two Intervals minus its intersection.
63 // pub const fn xor(self, other: Self) -> Repr<I> {
64 // let or = match self.or(other) {
65 // Or(lhs, rhs) => return Or(lhs, rhs),
66 // Repr::Interval(or) => or,
67 // };
68 // let and = match self.and(other) {
69 // Or(lhs, rhs) => return Or(lhs, rhs),
70 // Repr::Interval(and) => and,
71 // };
72 // or.sub(and)
73 // }
74
75 // /// Subtract the given Interval from this Interval and return the resulting
76 // /// Seqs.
77 // ///
78 // /// If subtraction would result in an empty Interval, then no Seqs are
79 // /// returned.
80 // ///
81 // /// other.0 <= self.0 <= self.1 <= other.1 (self <= other) => Zero
82 // /// self.0 <= other.0 <= other.1 <= self.1 (other <= self) => (lower, upper)
83 // /// self.0 <= other.0 <= self.1 <= other.1 => (lower, None)
84 // /// other.0 <= self.0 <= other.1 <= self.1 => (None, uppper)
85 // pub const fn sub(self, other: Self) -> Repr<I> {
86 // if self.le(&other) {
87 // return Zero;
88 // }
89 // if self.contiguous(&other) {
90 // return Repr::Interval(self.clone());
91 // }
92 // let mut ret = (None, None);
93 // if self.0 < other.0 {
94 // ret.0 = Some(Self::new(self.0, other.0.pred()));
95 // }
96 // if other.1 < self.1 {
97 // let range = Self::new(other.1.succ(), self.1);
98 // if ret.0.is_none() {
99 // ret.0 = Some(range);
100 // } else {
101 // ret.1 = Some(range);
102 // }
103 // }
104 // ret
105 // }
106
107 ///
108 pub const fn contiguous(&self, other: &Self) -> bool {
109 max(self.0, other.0) <= min(self.1, other.1)
110 }
111
112 // /// Negate this Interval.
113 // ///
114 // /// For all `a` where `a` is any element, if `a` is in this interval, then it will not be in this set after negation.
115 // pub const fn not(self) -> Repr<I> {
116 // Self::full().sub(self)
117 // }
118
119 // TODO(rinarakaki) Why not simply `other.0 <= self.0 && self.1 <= other.1`
120 /// a ⊆ b
121 pub const fn le(&self, other: &Self) -> bool {
122 (other.0 <= self.0 && self.0 <= other.1) && (other.0 <= self.1 && self.1 <= other.1)
123 }
124
125 /// i ∈ a
126 pub fn has(&self, i: I) -> bool {
127 self.0 <= i && i <= self.1
128 }
129
130 pub const fn len(&self) -> usize {
131 <I as Step>::steps_between(&self.0, &self.1).1.unwrap()
132 }
133}
134
135#[unconst]
136impl<I: const Integral> const IntoIterator for Interval<I> {
137 type Item = I;
138 type IntoIter = RangeInclusive<I>;
139
140 fn into_iter(self) -> Self::IntoIter {
141 self.0..=self.1
142 }
143}
144
145impl Interval<char> {
146 /// Returns true if and only if this character class will either match
147 /// nothing or only ASCII bytes. Stated differently, this returns false
148 /// if and only if this class contains a non-ASCII codepoint.
149 pub fn is_all_ascii(&self) -> bool {
150 self.1 <= '\x7F'
151 }
152}