1use crate::res::{OneTwo, ZeroOneTwo};
8
9#[cfg(test)]
10mod between_tests;
11#[cfg(test)]
12mod checked_minkowski_tests;
13#[cfg(test)]
14mod convex_hull_tests;
15#[cfg(test)]
16mod difference_tests;
17#[cfg(test)]
18mod intersection_tests;
19#[cfg(test)]
20mod symmetric_difference_tests;
21#[cfg(test)]
22mod union_tests;
23
24#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
25pub struct I32CO {
26 start: i32,
27 end_excl: i32,
28}
29
30mod construction_accessors_predicates {
34
35 use super::*;
36
37 impl I32CO {
38 #[inline]
39 pub const fn try_new(start: i32, end_excl: i32) -> Option<Self> {
40 if start < end_excl {
41 Some(Self { start, end_excl })
42 } else {
43 None
44 }
45 }
46
47 #[inline]
48 pub(super) const fn new_unchecked(start: i32, end_excl: i32) -> Self {
49 debug_assert!(start < end_excl);
50 Self { start, end_excl }
51 }
52
53 #[inline]
54 pub const fn start(self) -> i32 {
55 self.start
56 }
57
58 #[inline]
59 pub const fn end_excl(self) -> i32 {
60 self.end_excl
61 }
62
63 #[inline]
64 pub const fn end_incl(self) -> i32 {
65 self.end_excl - 1
67 }
68
69 #[inline]
70 pub const fn len(self) -> u32 {
71 (self.end_excl - self.start) as u32
72 }
73
74 #[inline]
75 pub const fn contains(self, x: i32) -> bool {
76 self.start <= x && x < self.end_excl
77 }
78
79 #[inline]
80 pub const fn iter(self) -> core::ops::Range<i32> {
81 self.start..self.end_excl
82 }
83
84 #[inline]
85 pub const fn to_range(self) -> core::ops::Range<i32> {
86 self.start..self.end_excl
87 }
88
89 #[inline]
90 pub const fn intersects(self, other: Self) -> bool {
91 !(self.end_excl <= other.start || other.end_excl <= self.start)
92 }
93
94 #[inline]
95 pub const fn is_adjacent(self, other: Self) -> bool {
96 self.end_excl == other.start || other.end_excl == self.start
97 }
98
99 #[inline]
100 pub const fn is_contiguous_with(self, other: Self) -> bool {
101 self.intersects(other) || self.is_adjacent(other)
102 }
103 }
104}
105mod interval_algebra {
110
111 use super::*;
112
113 impl I32CO {
114 #[inline]
118 pub const fn intersection(self, other: Self) -> Option<Self> {
119 let start = if self.start >= other.start {
120 self.start
121 } else {
122 other.start
123 };
124
125 let end_excl = if self.end_excl <= other.end_excl {
126 self.end_excl
127 } else {
128 other.end_excl
129 };
130
131 Self::try_new(start, end_excl)
132 }
133
134 #[inline]
138 pub const fn convex_hull(self, other: Self) -> Self {
139 let start = if self.start <= other.start {
140 self.start
141 } else {
142 other.start
143 };
144
145 let end_excl = if self.end_excl >= other.end_excl {
146 self.end_excl
147 } else {
148 other.end_excl
149 };
150
151 Self { start, end_excl }
152 }
153
154 #[inline]
158 pub const fn between(self, other: Self) -> Option<Self> {
159 let (left, right) = if self.start <= other.start {
160 (self, other)
161 } else {
162 (other, self)
163 };
164
165 Self::try_new(left.end_excl, right.start)
166 }
167
168 #[inline]
173 pub const fn union(self, other: Self) -> OneTwo<Self> {
174 if self.is_contiguous_with(other) {
175 OneTwo::One(self.convex_hull(other))
176 } else if self.start <= other.start {
177 OneTwo::Two(self, other)
178 } else {
179 OneTwo::Two(other, self)
180 }
181 }
182
183 #[inline]
189 pub const fn difference(self, other: Self) -> ZeroOneTwo<Self> {
190 match self.intersection(other) {
191 None => ZeroOneTwo::One(self),
192 Some(inter) => {
193 let left = Self::try_new(self.start, inter.start);
194 let right = Self::try_new(inter.end_excl, self.end_excl);
195
196 match (left, right) {
197 (None, None) => ZeroOneTwo::Zero,
198 (Some(x), None) | (None, Some(x)) => ZeroOneTwo::One(x),
199 (Some(x), Some(y)) => ZeroOneTwo::Two(x, y),
200 }
201 }
202 }
203 }
204
205 #[inline]
211 pub const fn symmetric_difference(self, other: Self) -> ZeroOneTwo<Self> {
212 match self.intersection(other) {
213 None => {
214 if self.start <= other.start {
215 ZeroOneTwo::Two(self, other)
216 } else {
217 ZeroOneTwo::Two(other, self)
218 }
219 }
220 Some(inter) => {
221 let hull = self.convex_hull(other);
222 let left = Self::try_new(hull.start, inter.start);
223 let right = Self::try_new(inter.end_excl, hull.end_excl);
224
225 match (left, right) {
226 (None, None) => ZeroOneTwo::Zero,
227 (Some(x), None) | (None, Some(x)) => ZeroOneTwo::One(x),
228 (Some(x), Some(y)) => ZeroOneTwo::Two(x, y),
229 }
230 }
231 }
232 }
233 }
234}
235
236pub mod minkowski {
242 use super::*;
243
244 type Min = i32;
245 type Max = i32;
246
247 #[inline]
248 const fn min_max4(a: i32, b: i32, c: i32, d: i32) -> (Min, Max) {
249 let (min1, max1) = if a < b { (a, b) } else { (b, a) };
250 let (min2, max2) = if c < d { (c, d) } else { (d, c) };
251 let min = if min1 < min2 { min1 } else { min2 };
252 let max = if max1 > max2 { max1 } else { max2 };
253 (min, max)
254 }
255
256 #[inline]
257 const fn min_max2(a: i32, b: i32) -> (Min, Max) {
258 if a < b { (a, b) } else { (b, a) }
259 }
260
261 pub mod checked {
262 use super::*;
263
264 impl I32CO {
268 #[inline]
269 pub const fn checked_minkowski_add(self, other: Self) -> Option<Self> {
270 let Some(start) = self.start.checked_add(other.start) else {
271 return None;
272 };
273 let Some(end_excl) = self.end_excl.checked_add(other.end_incl()) else {
274 return None;
275 };
276 Some(Self::new_unchecked(start, end_excl))
277 }
278
279 #[inline]
280 pub const fn checked_minkowski_sub(self, other: Self) -> Option<Self> {
281 let Some(start) = self.start.checked_sub(other.end_incl()) else {
282 return None;
283 };
284 let Some(end_excl) = self.end_excl.checked_sub(other.start) else {
285 return None;
286 };
287 Some(Self::new_unchecked(start, end_excl))
288 }
289
290 #[inline]
291 pub const fn checked_minkowski_mul(self, other: Self) -> Option<Self> {
292 let a = self.start;
293 let b = self.end_incl();
294 let c = other.start;
295 let d = other.end_incl();
296
297 let Some(p1) = a.checked_mul(c) else {
298 return None;
299 };
300 let Some(p2) = a.checked_mul(d) else {
301 return None;
302 };
303 let Some(p3) = b.checked_mul(c) else {
304 return None;
305 };
306 let Some(p4) = b.checked_mul(d) else {
307 return None;
308 };
309
310 let (start, end_incl) = min_max4(p1, p2, p3, p4);
311
312 let Some(end_excl) = end_incl.checked_add(1) else {
313 return None;
314 };
315
316 Some(Self::new_unchecked(start, end_excl))
317 }
318
319 #[inline]
320 pub const fn checked_minkowski_div(self, other: Self) -> Option<Self> {
321 if other.start <= 0 && other.end_incl() >= 0 {
322 return None;
323 }
324
325 let a = self.start;
326 let b = self.end_incl();
327 let c = other.start;
328 let d = other.end_incl();
329
330 let Some(p1) = a.checked_div(c) else {
331 return None;
332 };
333 let Some(p2) = a.checked_div(d) else {
334 return None;
335 };
336 let Some(p3) = b.checked_div(c) else {
337 return None;
338 };
339 let Some(p4) = b.checked_div(d) else {
340 return None;
341 };
342
343 let (start, end_incl) = min_max4(p1, p2, p3, p4);
344
345 let Some(end_excl) = end_incl.checked_add(1) else {
346 return None;
347 };
348
349 Some(Self::new_unchecked(start, end_excl))
350 }
351 }
352
353 impl I32CO {
357 #[inline]
358 pub const fn checked_minkowski_add_n(self, n: i32) -> Option<Self> {
359 let Some(start) = self.start.checked_add(n) else {
360 return None;
361 };
362 let Some(end_excl) = self.end_excl.checked_add(n) else {
363 return None;
364 };
365 Some(Self::new_unchecked(start, end_excl))
366 }
367
368 #[inline]
369 pub const fn checked_minkowski_sub_n(self, n: i32) -> Option<Self> {
370 let Some(start) = self.start.checked_sub(n) else {
371 return None;
372 };
373 let Some(end_excl) = self.end_excl.checked_sub(n) else {
374 return None;
375 };
376 Some(Self::new_unchecked(start, end_excl))
377 }
378
379 #[inline]
380 pub const fn checked_minkowski_mul_n(self, n: i32) -> Option<Self> {
381 let Some(a) = self.start.checked_mul(n) else {
382 return None;
383 };
384 let Some(b) = self.end_incl().checked_mul(n) else {
385 return None;
386 };
387
388 let (start, end_incl) = min_max2(a, b);
389
390 let Some(end_excl) = end_incl.checked_add(1) else {
391 return None;
392 };
393 Some(Self::new_unchecked(start, end_excl))
394 }
395
396 #[inline]
397 pub const fn checked_minkowski_div_n(self, n: i32) -> Option<Self> {
398 if n == 0 {
399 return None;
400 }
401 let Some(a) = self.start.checked_div(n) else {
402 return None;
403 };
404 let Some(b) = self.end_incl().checked_div(n) else {
405 return None;
406 };
407
408 let (start, end_incl) = min_max2(a, b);
409
410 let Some(end_excl) = end_incl.checked_add(1) else {
411 return None;
412 };
413 Some(Self::new_unchecked(start, end_excl))
414 }
415 }
416 }
417
418 pub mod saturating {
422 use super::*;
423
424 impl I32CO {
425 #[inline]
426 pub const fn saturating_minkowski_add(self, other: Self) -> Option<Self> {
427 let start = self.start.saturating_add(other.start);
428 let end_excl = self.end_excl.saturating_add(other.end_incl());
429 Self::try_new(start, end_excl)
430 }
431
432 #[inline]
433 pub const fn saturating_minkowski_sub(self, other: Self) -> Option<Self> {
434 let start = self.start.saturating_sub(other.end_incl());
435 let end_excl = self.end_excl.saturating_sub(other.start);
436 Self::try_new(start, end_excl)
437 }
438
439 #[inline]
440 pub const fn saturating_minkowski_mul(self, other: Self) -> Option<Self> {
441 let a = self.start.saturating_mul(other.start);
442 let b = self.start.saturating_mul(other.end_incl());
443 let c = self.end_incl().saturating_mul(other.start);
444 let d = self.end_incl().saturating_mul(other.end_incl());
445
446 let (start, end_incl) = min_max4(a, b, c, d);
447
448 let end_excl = end_incl.saturating_add(1);
449 Self::try_new(start, end_excl)
450 }
451
452 #[inline]
453 pub const fn saturating_minkowski_div(self, other: Self) -> Option<Self> {
454 if other.start <= 0 && other.end_incl() >= 0 {
455 return None;
456 }
457
458 let a = self.start / other.start;
459 let b = self.start / other.end_incl();
460 let c = self.end_incl() / other.start;
461 let d = self.end_incl() / other.end_incl();
462
463 let (start, end_incl) = min_max4(a, b, c, d);
464
465 let end_excl = end_incl.saturating_add(1);
466 Self::try_new(start, end_excl)
467 }
468 }
469
470 impl I32CO {
471 #[inline]
472 pub const fn saturating_minkowski_add_n(self, n: i32) -> Option<Self> {
473 let start = self.start.saturating_add(n);
474 let end_excl = self.end_excl.saturating_add(n);
475 Self::try_new(start, end_excl)
476 }
477
478 #[inline]
479 pub const fn saturating_minkowski_sub_n(self, n: i32) -> Option<Self> {
480 let start = self.start.saturating_sub(n);
481 let end_excl = self.end_excl.saturating_sub(n);
482 Self::try_new(start, end_excl)
483 }
484
485 #[inline]
486 pub const fn saturating_minkowski_mul_n(self, n: i32) -> Option<Self> {
487 let a = self.start.saturating_mul(n);
488 let b = self.end_incl().saturating_mul(n);
489
490 let (start, end_incl) = min_max2(a, b);
491
492 let end_excl = end_incl.saturating_add(1);
493 Self::try_new(start, end_excl)
494 }
495
496 #[inline]
497 pub const fn saturating_minkowski_div_n(self, n: i32) -> Option<Self> {
498 if n == 0 {
499 return None;
500 }
501
502 let a = self.start / n;
503 let b = self.end_incl() / n;
504
505 let (start, end_incl) = min_max2(a, b);
506
507 let end_excl = end_incl.saturating_add(1);
508 Self::try_new(start, end_excl)
509 }
510 }
511 }
512}