int_interval/i32.rs
1// -----------------------------------------------------------------------------
2// @generated by xtask/codegen (signed)
3// DO NOT EDIT MANUALLY.
4// Changes will be overwritten.
5// -----------------------------------------------------------------------------
6
7use 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
30// ------------------------------------------------------------
31// low-level api: construction / accessors / predicates
32// ------------------------------------------------------------
33mod 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 const unsafe 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 // i32_low_bound =< start < end_excl
66 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}
105// ------------------------------------------------------------
106// interval algebra api: intersection / convex_hull / between / union / difference / symmetric_difference
107// ------------------------------------------------------------
108
109mod interval_algebra {
110
111 use super::*;
112
113 impl I32CO {
114 /// Returns the intersection of two intervals.
115 ///
116 /// If the intervals do not overlap, returns `None`.
117 #[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 /// Returns the convex hull (smallest interval containing both) of two intervals.
135 ///
136 /// Always returns a valid `I32CO`.
137 #[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 /// Returns the interval strictly between two intervals.
155 ///
156 /// If the intervals are contiguous or overlap, returns `None`.
157 #[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 /// Returns the union of two intervals.
169 ///
170 /// - If intervals are contiguous or overlapping, returns `One` containing the merged interval.
171 /// - Otherwise, returns `Two` containing both intervals in ascending order.
172 #[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 /// Returns the difference of two intervals (self - other).
184 ///
185 /// - If no overlap, returns `One(self)`.
186 /// - If partial overlap, returns `One` or `Two` depending on remaining segments.
187 /// - If fully contained, returns `Zero`.
188 #[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 /// Returns the symmetric difference of two intervals.
206 ///
207 /// Equivalent to `(self - other) ∪ (other - self)`.
208 /// - If intervals do not overlap, returns `Two(self, other)` in order.
209 /// - If intervals partially overlap, returns remaining non-overlapping segments as `One` or `Two`.
210 #[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
236// ------------------------------------------------------------
237// Module: Minkowski arithmetic for I32CO
238// Provides checked and saturating Minkowski operations for intervals
239// ------------------------------------------------------------
240
241pub 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 // --------------------------------------------------------
265 // Interval-to-interval
266 // --------------------------------------------------------
267 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
277 // SAFETY:
278 // `checked_add` guarantees both endpoint computations succeed without overflow.
279 // For half-open intervals, let `a_last = self.end_incl()` and `b_last = other.end_incl()`.
280 // Since `self.start <= a_last` and `other.start <= b_last`, we have
281 // `self.start + other.start <= a_last + b_last < self.end_excl + other.end_incl()`,
282 // hence the computed bounds satisfy `start < end_excl`.
283 Some(unsafe { Self::new_unchecked(start, end_excl) })
284 }
285
286 #[inline]
287 pub const fn checked_minkowski_sub(self, other: Self) -> Option<Self> {
288 let Some(start) = self.start.checked_sub(other.end_incl()) else {
289 return None;
290 };
291 let Some(end_excl) = self.end_excl.checked_sub(other.start) else {
292 return None;
293 };
294
295 // SAFETY:
296 // `checked_sub` guarantees both endpoint computations succeed without overflow.
297 // For interval subtraction, the minimum is attained at `self.start - other.end_incl()`
298 // and the exclusive upper bound is `self.end_excl - other.start`.
299 // Because `other.start <= other.end_incl()`, we get
300 // `self.start - other.end_incl() < self.end_excl - other.start`,
301 // so the resulting half-open interval is valid.
302 Some(unsafe { Self::new_unchecked(start, end_excl) })
303 }
304
305 #[inline]
306 pub const fn checked_minkowski_mul(self, other: Self) -> Option<Self> {
307 let a = self.start;
308 let b = self.end_incl();
309 let c = other.start;
310 let d = other.end_incl();
311
312 let Some(p1) = a.checked_mul(c) else {
313 return None;
314 };
315 let Some(p2) = a.checked_mul(d) else {
316 return None;
317 };
318 let Some(p3) = b.checked_mul(c) else {
319 return None;
320 };
321 let Some(p4) = b.checked_mul(d) else {
322 return None;
323 };
324
325 let (start, end_incl) = min_max4(p1, p2, p3, p4);
326
327 let Some(end_excl) = end_incl.checked_add(1) else {
328 return None;
329 };
330
331 // SAFETY:
332 // All four corner products are computed with `checked_mul`, so no intermediate
333 // multiplication overflows. For multiplication over a closed integer rectangle
334 // `[a, b] × [c, d]`, every attainable extremum occurs at a corner, so
335 // `min_max4(p1, p2, p3, p4)` yields the true inclusive lower/upper bounds.
336 // Therefore `start <= end_incl` holds by construction.
337 // `checked_add(1)` then safely converts the inclusive upper bound to the exclusive
338 // upper bound, and implies `end_excl = end_incl + 1`, hence `start < end_excl`.
339 Some(unsafe { Self::new_unchecked(start, end_excl) })
340 }
341
342 #[inline]
343 pub const fn checked_minkowski_div(self, other: Self) -> Option<Self> {
344 if other.start <= 0 && other.end_incl() >= 0 {
345 return None;
346 }
347
348 let a = self.start;
349 let b = self.end_incl();
350 let c = other.start;
351 let d = other.end_incl();
352
353 let Some(p1) = a.checked_div(c) else {
354 return None;
355 };
356 let Some(p2) = a.checked_div(d) else {
357 return None;
358 };
359 let Some(p3) = b.checked_div(c) else {
360 return None;
361 };
362 let Some(p4) = b.checked_div(d) else {
363 return None;
364 };
365
366 let (start, end_incl) = min_max4(p1, p2, p3, p4);
367
368 let Some(end_excl) = end_incl.checked_add(1) else {
369 return None;
370 };
371
372 // SAFETY:
373 // The guard `other.start <= 0 && other.end_incl() >= 0` rejects any divisor interval
374 // that contains zero, so division by zero cannot occur anywhere in the divisor set.
375 // Each corner quotient is computed with `checked_div`, so exceptional signed cases
376 // such as `MIN / -1` are also rejected.
377 // On each connected component of the divisor domain that excludes zero, integer division
378 // is monotone with respect to the rectangle corners relevant to the extremum search;
379 // thus the global inclusive bounds over the interval pair are captured by the four
380 // corner quotients and recovered by `min_max4`, giving `start <= end_incl`.
381 // `checked_add(1)` safely converts the inclusive upper bound to half-open form, so
382 // the final bounds satisfy `start < end_excl`.
383 Some(unsafe { Self::new_unchecked(start, end_excl) })
384 }
385 }
386
387 // --------------------------------------------------------
388 // Scalar
389 // --------------------------------------------------------
390 impl I32CO {
391 #[inline]
392 pub const fn checked_minkowski_add_n(self, n: i32) -> Option<Self> {
393 let Some(start) = self.start.checked_add(n) else {
394 return None;
395 };
396 let Some(end_excl) = self.end_excl.checked_add(n) else {
397 return None;
398 };
399
400 // SAFETY:
401 // `checked_add` guarantees both translated bounds are computed without overflow.
402 // Adding the same scalar to both endpoints preserves the interval width exactly,
403 // so a valid half-open interval remains valid and still satisfies `start < end_excl`.
404 Some(unsafe { Self::new_unchecked(start, end_excl) })
405 }
406
407 #[inline]
408 pub const fn checked_minkowski_sub_n(self, n: i32) -> Option<Self> {
409 let Some(start) = self.start.checked_sub(n) else {
410 return None;
411 };
412 let Some(end_excl) = self.end_excl.checked_sub(n) else {
413 return None;
414 };
415
416 // SAFETY:
417 // `checked_sub` guarantees both translated bounds are computed without overflow.
418 // Subtracting the same scalar from both endpoints preserves the interval width exactly,
419 // so the strict half-open ordering is unchanged and `start < end_excl` still holds.
420 Some(unsafe { Self::new_unchecked(start, end_excl) })
421 }
422
423 #[inline]
424 pub const fn checked_minkowski_mul_n(self, n: i32) -> Option<Self> {
425 let Some(a) = self.start.checked_mul(n) else {
426 return None;
427 };
428 let Some(b) = self.end_incl().checked_mul(n) else {
429 return None;
430 };
431
432 let (start, end_incl) = min_max2(a, b);
433
434 let Some(end_excl) = end_incl.checked_add(1) else {
435 return None;
436 };
437
438 // SAFETY:
439 // Both endpoint products are computed with `checked_mul`, so no signed overflow occurs.
440 // Multiplication by a scalar maps the closed source interval endpoints to the two extreme
441 // candidates; `min_max2` therefore recovers the true inclusive lower/upper bounds whether
442 // `n` is positive, zero, or negative, giving `start <= end_incl`.
443 // `checked_add(1)` safely converts the inclusive upper bound into the exclusive upper bound,
444 // which guarantees the final half-open interval satisfies `start < end_excl`.
445 Some(unsafe { Self::new_unchecked(start, end_excl) })
446 }
447
448 #[inline]
449 pub const fn checked_minkowski_div_n(self, n: i32) -> Option<Self> {
450 if n == 0 {
451 return None;
452 }
453
454 let Some(a) = self.start.checked_div(n) else {
455 return None;
456 };
457 let Some(b) = self.end_incl().checked_div(n) else {
458 return None;
459 };
460
461 let (start, end_incl) = min_max2(a, b);
462
463 let Some(end_excl) = end_incl.checked_add(1) else {
464 return None;
465 };
466
467 // SAFETY:
468 // The guard `n != 0` excludes division by zero, and `checked_div` additionally rejects
469 // the only overflowing signed case (`MIN / -1`).
470 // Division by a fixed nonzero scalar sends the source closed interval endpoints to the
471 // two extreme candidates for the image interval, so `min_max2` yields the true inclusive
472 // lower/upper bounds and ensures `start <= end_incl`.
473 // `checked_add(1)` safely restores half-open representation, therefore the constructed
474 // interval satisfies `start < end_excl`.
475 Some(unsafe { Self::new_unchecked(start, end_excl) })
476 }
477 }
478 }
479
480 // ========================================================
481 // SATURATING
482 // ========================================================
483 pub mod saturating {
484 use super::*;
485
486 impl I32CO {
487 #[inline]
488 pub const fn saturating_minkowski_add(self, other: Self) -> Option<Self> {
489 let start = self.start.saturating_add(other.start);
490 let end_excl = self.end_excl.saturating_add(other.end_incl());
491 Self::try_new(start, end_excl)
492 }
493
494 #[inline]
495 pub const fn saturating_minkowski_sub(self, other: Self) -> Option<Self> {
496 let start = self.start.saturating_sub(other.end_incl());
497 let end_excl = self.end_excl.saturating_sub(other.start);
498 Self::try_new(start, end_excl)
499 }
500
501 #[inline]
502 pub const fn saturating_minkowski_mul(self, other: Self) -> Option<Self> {
503 let a = self.start.saturating_mul(other.start);
504 let b = self.start.saturating_mul(other.end_incl());
505 let c = self.end_incl().saturating_mul(other.start);
506 let d = self.end_incl().saturating_mul(other.end_incl());
507
508 let (start, end_incl) = min_max4(a, b, c, d);
509
510 let end_excl = end_incl.saturating_add(1);
511 Self::try_new(start, end_excl)
512 }
513
514 #[inline]
515 pub const fn saturating_minkowski_div(self, other: Self) -> Option<Self> {
516 if other.start <= 0 && other.end_incl() >= 0 {
517 return None;
518 }
519
520 let a = self.start / other.start;
521 let b = self.start / other.end_incl();
522 let c = self.end_incl() / other.start;
523 let d = self.end_incl() / other.end_incl();
524
525 let (start, end_incl) = min_max4(a, b, c, d);
526
527 let end_excl = end_incl.saturating_add(1);
528 Self::try_new(start, end_excl)
529 }
530 }
531
532 impl I32CO {
533 #[inline]
534 pub const fn saturating_minkowski_add_n(self, n: i32) -> Option<Self> {
535 let start = self.start.saturating_add(n);
536 let end_excl = self.end_excl.saturating_add(n);
537 Self::try_new(start, end_excl)
538 }
539
540 #[inline]
541 pub const fn saturating_minkowski_sub_n(self, n: i32) -> Option<Self> {
542 let start = self.start.saturating_sub(n);
543 let end_excl = self.end_excl.saturating_sub(n);
544 Self::try_new(start, end_excl)
545 }
546
547 #[inline]
548 pub const fn saturating_minkowski_mul_n(self, n: i32) -> Option<Self> {
549 let a = self.start.saturating_mul(n);
550 let b = self.end_incl().saturating_mul(n);
551
552 let (start, end_incl) = min_max2(a, b);
553
554 let end_excl = end_incl.saturating_add(1);
555 Self::try_new(start, end_excl)
556 }
557
558 #[inline]
559 pub const fn saturating_minkowski_div_n(self, n: i32) -> Option<Self> {
560 if n == 0 {
561 return None;
562 }
563
564 let a = self.start / n;
565 let b = self.end_incl() / n;
566
567 let (start, end_incl) = min_max2(a, b);
568
569 let end_excl = end_incl.saturating_add(1);
570 Self::try_new(start, end_excl)
571 }
572 }
573 }
574}