1use crate::res::{OneTwo, ZeroOneTwo};
8
9#[cfg(test)]
10mod between_tests;
11#[cfg(test)]
12mod convex_hull_tests;
13#[cfg(test)]
14mod difference_tests;
15#[cfg(test)]
16mod intersection_tests;
17#[cfg(test)]
18mod symmetric_difference_tests;
19#[cfg(test)]
20mod transform_tests;
21#[cfg(test)]
22mod union_tests;
23
24#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
25pub struct U128CO {
26 start: u128,
27 end_excl: u128,
28}
29
30mod construction_accessors_predicates {
35
36 use super::*;
37
38 impl U128CO {
39 #[inline]
40 pub const fn try_new(start: u128, end_excl: u128) -> Option<Self> {
41 if start < end_excl {
42 Some(Self { start, end_excl })
43 } else {
44 None
45 }
46 }
47
48 #[inline]
49 pub(super) const fn new_unchecked(start: u128, end_excl: u128) -> Self {
50 debug_assert!(start < end_excl);
51 Self { start, end_excl }
52 }
53
54 #[inline]
55 pub const fn start(self) -> u128 {
56 self.start
57 }
58
59 #[inline]
60 pub const fn end_excl(self) -> u128 {
61 self.end_excl
62 }
63
64 #[inline]
65 pub const fn end_incl(self) -> u128 {
66 self.end_excl - 1
68 }
69
70 #[inline]
71 pub const fn len(self) -> u128 {
72 self.end_excl - self.start
73 }
74
75 #[inline]
76 pub const fn contains(self, x: u128) -> bool {
77 self.start <= x && x < self.end_excl
78 }
79
80 #[inline]
81 pub const fn iter(self) -> core::ops::Range<u128> {
82 self.start..self.end_excl
83 }
84
85 #[inline]
86 pub const fn intersects(self, other: Self) -> bool {
87 !(self.end_excl <= other.start || other.end_excl <= self.start)
88 }
89
90 #[inline]
91 pub const fn is_adjacent(self, other: Self) -> bool {
92 self.end_excl == other.start || other.end_excl == self.start
93 }
94
95 #[inline]
96 pub const fn is_contiguous_with(self, other: Self) -> bool {
97 self.intersects(other) || self.is_adjacent(other)
98 }
99 }
100}
101
102mod interval_algebra {
107
108 use super::*;
109
110 impl U128CO {
111 #[inline]
115 pub const fn intersection(self, other: Self) -> Option<Self> {
116 let start = if self.start >= other.start {
117 self.start
118 } else {
119 other.start
120 };
121
122 let end_excl = if self.end_excl <= other.end_excl {
123 self.end_excl
124 } else {
125 other.end_excl
126 };
127
128 Self::try_new(start, end_excl)
129 }
130
131 #[inline]
135 pub const fn convex_hull(self, other: Self) -> Self {
136 let start = if self.start <= other.start {
137 self.start
138 } else {
139 other.start
140 };
141
142 let end_excl = if self.end_excl >= other.end_excl {
143 self.end_excl
144 } else {
145 other.end_excl
146 };
147
148 Self { start, end_excl }
149 }
150
151 #[inline]
155 pub const fn between(self, other: Self) -> Option<Self> {
156 let (left, right) = if self.start <= other.start {
157 (self, other)
158 } else {
159 (other, self)
160 };
161
162 Self::try_new(left.end_excl, right.start)
163 }
164
165 #[inline]
170 pub const fn union(self, other: Self) -> OneTwo<Self> {
171 if self.is_contiguous_with(other) {
172 OneTwo::One(self.convex_hull(other))
173 } else if self.start <= other.start {
174 OneTwo::Two(self, other)
175 } else {
176 OneTwo::Two(other, self)
177 }
178 }
179
180 #[inline]
186 pub const fn difference(self, other: Self) -> ZeroOneTwo<Self> {
187 match self.intersection(other) {
188 None => ZeroOneTwo::One(self),
189 Some(inter) => {
190 let left = Self::try_new(self.start, inter.start);
191 let right = Self::try_new(inter.end_excl, self.end_excl);
192
193 match (left, right) {
194 (None, None) => ZeroOneTwo::Zero,
195 (Some(x), None) | (None, Some(x)) => ZeroOneTwo::One(x),
196 (Some(x), Some(y)) => ZeroOneTwo::Two(x, y),
197 }
198 }
199 }
200 }
201
202 #[inline]
208 pub const fn symmetric_difference(self, other: Self) -> ZeroOneTwo<Self> {
209 match self.intersection(other) {
210 None => {
211 if self.start <= other.start {
212 ZeroOneTwo::Two(self, other)
213 } else {
214 ZeroOneTwo::Two(other, self)
215 }
216 }
217 Some(inter) => {
218 let hull = self.convex_hull(other);
219 let left = Self::try_new(hull.start, inter.start);
220 let right = Self::try_new(inter.end_excl, hull.end_excl);
221
222 match (left, right) {
223 (None, None) => ZeroOneTwo::Zero,
224 (Some(x), None) | (None, Some(x)) => ZeroOneTwo::One(x),
225 (Some(x), Some(y)) => ZeroOneTwo::Two(x, y),
226 }
227 }
228 }
229 }
230 }
231}
232
233mod interval_arithmetic {
238
239 use super::*;
240
241 impl U128CO {
242 #[inline]
243 pub const fn scale(self, factor: u128) -> Option<Self> {
244 if factor == 0 || self.end_excl > u128::MAX / factor {
245 return None;
246 }
247 Some(U128CO::new_unchecked(
248 self.start * factor,
249 self.end_excl * factor,
250 ))
251 }
252
253 #[inline]
254 pub const fn shift(self, offset: u128) -> Option<Self> {
255 if self.end_excl > u128::MAX - offset {
256 return None;
257 }
258 Some(U128CO::new_unchecked(
259 self.start + offset,
260 self.end_excl + offset,
261 ))
262 }
263 }
264}