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 basic_tests;
11#[cfg(test)]
12mod between_tests;
13#[cfg(test)]
14mod checked_minkowski_tests;
15#[cfg(test)]
16mod convex_hull_tests;
17#[cfg(test)]
18mod difference_tests;
19#[cfg(test)]
20mod intersection_tests;
21#[cfg(test)]
22mod symmetric_difference_tests;
23#[cfg(test)]
24mod union_tests;
25
26#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
27pub struct I32CO {
28 start: i32,
29 end_excl: i32,
30}
31
32// ------------------------------------------------------------
33// low-level api: construction / accessors / predicates
34// ------------------------------------------------------------
35mod basic {
36
37 use super::*;
38
39 impl I32CO {
40 #[inline]
41 pub const fn try_new(start: i32, end_excl: i32) -> Option<Self> {
42 if start < end_excl {
43 Some(Self { start, end_excl })
44 } else {
45 None
46 }
47 }
48
49 #[inline]
50 pub const unsafe fn new_unchecked(start: i32, end_excl: i32) -> Self {
51 debug_assert!(start < end_excl);
52 Self { start, end_excl }
53 }
54
55 #[inline]
56 pub const fn start(self) -> i32 {
57 self.start
58 }
59
60 #[inline]
61 pub const fn end_excl(self) -> i32 {
62 self.end_excl
63 }
64
65 #[inline]
66 pub const fn end_incl(self) -> i32 {
67 // i32_low_bound =< start < end_excl
68 self.end_excl - 1
69 }
70
71 #[inline]
72 pub const fn len(self) -> u32 {
73 const SIGN_MASK: u32 = 1 << (i32::BITS - 1);
74 ((self.end_excl as u32) ^ SIGN_MASK) - ((self.start as u32) ^ SIGN_MASK)
75 }
76
77 /// Returns the midpoint of the interval `[start, end_excl)`,
78 /// using floor division if the length is even.
79 ///
80 /// # Guarantees
81 /// - `midpoint()` ∈ `[self.start, self.end_excl - 1]`
82 /// - Works for intervals with maximum length (entire `i32` range)
83 #[inline]
84 pub const fn midpoint(self) -> i32 {
85 self.start + (self.len() / 2) as i32
86 }
87
88 /// Constructs an `I32CO` interval from a midpoint and length (`u32`).
89 ///
90 /// # Parameters
91 /// - `mid`: the desired midpoint of the interval
92 /// - `len`: the desired length of the interval in units, must be `1..=u32::MAX`
93 ///
94 /// # Returns
95 /// - `Some(I32CO)` if the interval `[start, end_excl)` can be represented in `i32`
96 /// - `None` if `len = 0` or the computed `start` / `end_excl` would overflow `i32`
97 ///
98 /// # Guarantees
99 /// - Returned interval satisfies `start < end_excl`
100 /// - Maximum accepted input length is `u32::MAX`
101 #[inline]
102 pub const fn checked_from_midpoint_len(mid: i32, len: u32) -> Option<Self> {
103 if len == 0 {
104 return None;
105 }
106
107 let half = (len / 2) as i32;
108
109 let Some(start) = mid.checked_sub(half) else {
110 return None;
111 };
112 let Some(end_incl) = mid.checked_add(half) else {
113 return None;
114 };
115 let Some(end_excl) = end_incl.checked_add((len % 2) as i32) else {
116 return None;
117 };
118
119 // # Safety
120 // This function uses `unsafe { Self::new_unchecked(start, end_excl) }` internally.
121 // The safety is guaranteed by the following checks:
122 // 1. `mid.checked_sub(half)` ensures `start` does not underflow `i32`.
123 // 2. `mid.checked_add(the_other_half)` ensures `end_excl` does not overflow `i32`.
124 // 3. Because `half >= 0` and `the_other_half > 0`, we have `start < end_excl`.
125 // 4. Therefore, the half-open interval invariant `[start, end_excl)` is preserved.
126 Some(unsafe { Self::new_unchecked(start, end_excl) })
127 }
128
129 /// Constructs an `I32CO` interval from a midpoint and length (`u32`) with saturating semantics.
130 ///
131 /// # Parameters
132 /// - `mid`: the desired midpoint of the interval
133 /// - `len`: the desired length of the interval in units, must be `1..=u32::MAX`
134 ///
135 /// # Behavior
136 /// - Values are saturated at `i32::MIN` / `i32::MAX` to prevent overflow.
137 /// - If `len = 0`, returns `None`.
138 ///
139 /// # Guarantees
140 /// - Returned interval satisfies `start < end_excl`
141 /// - Maximum accepted input length is `u32::MAX`
142 /// - Fully compatible with codegen for other signed integer interval types
143 #[inline]
144 pub const fn saturating_from_midpoint_len(mid: i32, len: u32) -> Option<Self> {
145 if len == 0 {
146 return None;
147 }
148
149 let half = (len / 2) as i32;
150
151 let start = mid.saturating_sub(half);
152 let end_incl = mid.saturating_add(half);
153 let end_excl = end_incl.saturating_add((len % 2) as i32);
154
155 Self::try_new(start, end_excl)
156 }
157
158 #[inline]
159 pub const fn contains(self, x: i32) -> bool {
160 self.start <= x && x < self.end_excl
161 }
162
163 #[inline]
164 pub const fn contains_interval(self, other: Self) -> bool {
165 self.start <= other.start && other.end_excl <= self.end_excl
166 }
167
168 #[inline]
169 pub const fn iter(self) -> core::ops::Range<i32> {
170 self.start..self.end_excl
171 }
172
173 #[inline]
174 pub const fn to_range(self) -> core::ops::Range<i32> {
175 self.start..self.end_excl
176 }
177
178 #[inline]
179 pub const fn intersects(self, other: Self) -> bool {
180 !(self.end_excl <= other.start || other.end_excl <= self.start)
181 }
182
183 #[inline]
184 pub const fn is_adjacent(self, other: Self) -> bool {
185 self.end_excl == other.start || other.end_excl == self.start
186 }
187
188 #[inline]
189 pub const fn is_contiguous_with(self, other: Self) -> bool {
190 self.intersects(other) || self.is_adjacent(other)
191 }
192 }
193}
194
195// ------------------------------------------------------------
196// interval algebra api: intersection / convex_hull / between / union / difference / symmetric_difference
197// ------------------------------------------------------------
198
199mod interval_algebra {
200
201 use super::*;
202
203 impl I32CO {
204 /// Returns the intersection of two intervals.
205 ///
206 /// If the intervals do not overlap, returns `None`.
207 #[inline]
208 pub const fn intersection(self, other: Self) -> Option<Self> {
209 let start = if self.start >= other.start {
210 self.start
211 } else {
212 other.start
213 };
214
215 let end_excl = if self.end_excl <= other.end_excl {
216 self.end_excl
217 } else {
218 other.end_excl
219 };
220
221 Self::try_new(start, end_excl)
222 }
223
224 /// Returns the convex hull (smallest interval containing both) of two intervals.
225 ///
226 /// Always returns a valid `I32CO`.
227 #[inline]
228 pub const fn convex_hull(self, other: Self) -> Self {
229 let start = if self.start <= other.start {
230 self.start
231 } else {
232 other.start
233 };
234
235 let end_excl = if self.end_excl >= other.end_excl {
236 self.end_excl
237 } else {
238 other.end_excl
239 };
240
241 Self { start, end_excl }
242 }
243
244 /// Returns the interval strictly between two intervals.
245 ///
246 /// If the intervals are contiguous or overlap, returns `None`.
247 #[inline]
248 pub const fn between(self, other: Self) -> Option<Self> {
249 let (left, right) = if self.start <= other.start {
250 (self, other)
251 } else {
252 (other, self)
253 };
254
255 Self::try_new(left.end_excl, right.start)
256 }
257
258 /// Returns the union of two intervals.
259 ///
260 /// - If intervals are contiguous or overlapping, returns `One` containing the merged interval.
261 /// - Otherwise, returns `Two` containing both intervals in ascending order.
262 #[inline]
263 pub const fn union(self, other: Self) -> OneTwo<Self> {
264 if self.is_contiguous_with(other) {
265 OneTwo::One(self.convex_hull(other))
266 } else if self.start <= other.start {
267 OneTwo::Two(self, other)
268 } else {
269 OneTwo::Two(other, self)
270 }
271 }
272
273 /// Returns the difference of two intervals (self - other).
274 ///
275 /// - If no overlap, returns `One(self)`.
276 /// - If partial overlap, returns `One` or `Two` depending on remaining segments.
277 /// - If fully contained, returns `Zero`.
278 #[inline]
279 pub const fn difference(self, other: Self) -> ZeroOneTwo<Self> {
280 match self.intersection(other) {
281 None => ZeroOneTwo::One(self),
282 Some(inter) => {
283 let left = Self::try_new(self.start, inter.start);
284 let right = Self::try_new(inter.end_excl, self.end_excl);
285
286 match (left, right) {
287 (None, None) => ZeroOneTwo::Zero,
288 (Some(x), None) | (None, Some(x)) => ZeroOneTwo::One(x),
289 (Some(x), Some(y)) => ZeroOneTwo::Two(x, y),
290 }
291 }
292 }
293 }
294
295 /// Returns the symmetric difference of two intervals.
296 ///
297 /// Equivalent to `(self - other) ∪ (other - self)`.
298 /// - If intervals do not overlap, returns `Two(self, other)` in order.
299 /// - If intervals partially overlap, returns remaining non-overlapping segments as `One` or `Two`.
300 #[inline]
301 pub const fn symmetric_difference(self, other: Self) -> ZeroOneTwo<Self> {
302 match self.intersection(other) {
303 None => {
304 if self.start <= other.start {
305 ZeroOneTwo::Two(self, other)
306 } else {
307 ZeroOneTwo::Two(other, self)
308 }
309 }
310 Some(inter) => {
311 let hull = self.convex_hull(other);
312 let left = Self::try_new(hull.start, inter.start);
313 let right = Self::try_new(inter.end_excl, hull.end_excl);
314
315 match (left, right) {
316 (None, None) => ZeroOneTwo::Zero,
317 (Some(x), None) | (None, Some(x)) => ZeroOneTwo::One(x),
318 (Some(x), Some(y)) => ZeroOneTwo::Two(x, y),
319 }
320 }
321 }
322 }
323 }
324}
325
326// ------------------------------------------------------------
327// Module: Minkowski arithmetic for I32CO
328// Provides checked and saturating Minkowski operations for intervals
329// ------------------------------------------------------------
330
331pub mod minkowski {
332 use super::*;
333
334 type Min = i32;
335 type Max = i32;
336
337 #[inline]
338 const fn min_max4(a: i32, b: i32, c: i32, d: i32) -> (Min, Max) {
339 let (min1, max1) = if a < b { (a, b) } else { (b, a) };
340 let (min2, max2) = if c < d { (c, d) } else { (d, c) };
341 let min = if min1 < min2 { min1 } else { min2 };
342 let max = if max1 > max2 { max1 } else { max2 };
343 (min, max)
344 }
345
346 #[inline]
347 const fn min_max2(a: i32, b: i32) -> (Min, Max) {
348 if a < b { (a, b) } else { (b, a) }
349 }
350
351 pub mod checked {
352 use super::*;
353
354 // --------------------------------------------------------
355 // Interval-to-interval
356 // --------------------------------------------------------
357 impl I32CO {
358 #[inline]
359 pub const fn checked_minkowski_add(self, other: Self) -> Option<Self> {
360 let Some(start) = self.start.checked_add(other.start) else {
361 return None;
362 };
363 let Some(end_excl) = self.end_excl.checked_add(other.end_incl()) else {
364 return None;
365 };
366
367 // SAFETY:
368 // `checked_add` guarantees both endpoint computations succeed without overflow.
369 // For half-open intervals, let `a_last = self.end_incl()` and `b_last = other.end_incl()`.
370 // Since `self.start <= a_last` and `other.start <= b_last`, we have
371 // `self.start + other.start <= a_last + b_last < self.end_excl + other.end_incl()`,
372 // hence the computed bounds satisfy `start < end_excl`.
373 Some(unsafe { Self::new_unchecked(start, end_excl) })
374 }
375
376 #[inline]
377 pub const fn checked_minkowski_sub(self, other: Self) -> Option<Self> {
378 let Some(start) = self.start.checked_sub(other.end_incl()) else {
379 return None;
380 };
381 let Some(end_excl) = self.end_excl.checked_sub(other.start) else {
382 return None;
383 };
384
385 // SAFETY:
386 // `checked_sub` guarantees both endpoint computations succeed without overflow.
387 // For interval subtraction, the minimum is attained at `self.start - other.end_incl()`
388 // and the exclusive upper bound is `self.end_excl - other.start`.
389 // Because `other.start <= other.end_incl()`, we get
390 // `self.start - other.end_incl() < self.end_excl - other.start`,
391 // so the resulting half-open interval is valid.
392 Some(unsafe { Self::new_unchecked(start, end_excl) })
393 }
394
395 #[inline]
396 pub const fn checked_minkowski_mul(self, other: Self) -> Option<Self> {
397 let a = self.start;
398 let b = self.end_incl();
399 let c = other.start;
400 let d = other.end_incl();
401
402 let Some(p1) = a.checked_mul(c) else {
403 return None;
404 };
405 let Some(p2) = a.checked_mul(d) else {
406 return None;
407 };
408 let Some(p3) = b.checked_mul(c) else {
409 return None;
410 };
411 let Some(p4) = b.checked_mul(d) else {
412 return None;
413 };
414
415 let (start, end_incl) = min_max4(p1, p2, p3, p4);
416
417 let Some(end_excl) = end_incl.checked_add(1) else {
418 return None;
419 };
420
421 // SAFETY:
422 // All four corner products are computed with `checked_mul`, so no intermediate
423 // multiplication overflows. For multiplication over a closed integer rectangle
424 // `[a, b] × [c, d]`, every attainable extremum occurs at a corner, so
425 // `min_max4(p1, p2, p3, p4)` yields the true inclusive lower/upper bounds.
426 // Therefore `start <= end_incl` holds by construction.
427 // `checked_add(1)` then safely converts the inclusive upper bound to the exclusive
428 // upper bound, and implies `end_excl = end_incl + 1`, hence `start < end_excl`.
429 Some(unsafe { Self::new_unchecked(start, end_excl) })
430 }
431
432 #[inline]
433 pub const fn checked_minkowski_div(self, other: Self) -> Option<Self> {
434 if other.start <= 0 && other.end_incl() >= 0 {
435 return None;
436 }
437
438 let a = self.start;
439 let b = self.end_incl();
440 let c = other.start;
441 let d = other.end_incl();
442
443 let Some(p1) = a.checked_div(c) else {
444 return None;
445 };
446 let Some(p2) = a.checked_div(d) else {
447 return None;
448 };
449 let Some(p3) = b.checked_div(c) else {
450 return None;
451 };
452 let Some(p4) = b.checked_div(d) else {
453 return None;
454 };
455
456 let (start, end_incl) = min_max4(p1, p2, p3, p4);
457
458 let Some(end_excl) = end_incl.checked_add(1) else {
459 return None;
460 };
461
462 // SAFETY:
463 // The guard `other.start <= 0 && other.end_incl() >= 0` rejects any divisor interval
464 // that contains zero, so division by zero cannot occur anywhere in the divisor set.
465 // Each corner quotient is computed with `checked_div`, so exceptional signed cases
466 // such as `MIN / -1` are also rejected.
467 // On each connected component of the divisor domain that excludes zero, integer division
468 // is monotone with respect to the rectangle corners relevant to the extremum search;
469 // thus the global inclusive bounds over the interval pair are captured by the four
470 // corner quotients and recovered by `min_max4`, giving `start <= end_incl`.
471 // `checked_add(1)` safely converts the inclusive upper bound to half-open form, so
472 // the final bounds satisfy `start < end_excl`.
473 Some(unsafe { Self::new_unchecked(start, end_excl) })
474 }
475 }
476
477 // --------------------------------------------------------
478 // Scalar
479 // --------------------------------------------------------
480 impl I32CO {
481 #[inline]
482 pub const fn checked_minkowski_add_n(self, n: i32) -> Option<Self> {
483 let Some(start) = self.start.checked_add(n) else {
484 return None;
485 };
486 let Some(end_excl) = self.end_excl.checked_add(n) else {
487 return None;
488 };
489
490 // SAFETY:
491 // `checked_add` guarantees both translated bounds are computed without overflow.
492 // Adding the same scalar to both endpoints preserves the interval width exactly,
493 // so a valid half-open interval remains valid and still satisfies `start < end_excl`.
494 Some(unsafe { Self::new_unchecked(start, end_excl) })
495 }
496
497 #[inline]
498 pub const fn checked_minkowski_sub_n(self, n: i32) -> Option<Self> {
499 let Some(start) = self.start.checked_sub(n) else {
500 return None;
501 };
502 let Some(end_excl) = self.end_excl.checked_sub(n) else {
503 return None;
504 };
505
506 // SAFETY:
507 // `checked_sub` guarantees both translated bounds are computed without overflow.
508 // Subtracting the same scalar from both endpoints preserves the interval width exactly,
509 // so the strict half-open ordering is unchanged and `start < end_excl` still holds.
510 Some(unsafe { Self::new_unchecked(start, end_excl) })
511 }
512
513 #[inline]
514 pub const fn checked_minkowski_mul_n(self, n: i32) -> Option<Self> {
515 let Some(a) = self.start.checked_mul(n) else {
516 return None;
517 };
518 let Some(b) = self.end_incl().checked_mul(n) else {
519 return None;
520 };
521
522 let (start, end_incl) = min_max2(a, b);
523
524 let Some(end_excl) = end_incl.checked_add(1) else {
525 return None;
526 };
527
528 // SAFETY:
529 // Both endpoint products are computed with `checked_mul`, so no signed overflow occurs.
530 // Multiplication by a scalar maps the closed source interval endpoints to the two extreme
531 // candidates; `min_max2` therefore recovers the true inclusive lower/upper bounds whether
532 // `n` is positive, zero, or negative, giving `start <= end_incl`.
533 // `checked_add(1)` safely converts the inclusive upper bound into the exclusive upper bound,
534 // which guarantees the final half-open interval satisfies `start < end_excl`.
535 Some(unsafe { Self::new_unchecked(start, end_excl) })
536 }
537
538 #[inline]
539 pub const fn checked_minkowski_div_n(self, n: i32) -> Option<Self> {
540 if n == 0 {
541 return None;
542 }
543
544 let Some(a) = self.start.checked_div(n) else {
545 return None;
546 };
547 let Some(b) = self.end_incl().checked_div(n) else {
548 return None;
549 };
550
551 let (start, end_incl) = min_max2(a, b);
552
553 let Some(end_excl) = end_incl.checked_add(1) else {
554 return None;
555 };
556
557 // SAFETY:
558 // The guard `n != 0` excludes division by zero, and `checked_div` additionally rejects
559 // the only overflowing signed case (`MIN / -1`).
560 // Division by a fixed nonzero scalar sends the source closed interval endpoints to the
561 // two extreme candidates for the image interval, so `min_max2` yields the true inclusive
562 // lower/upper bounds and ensures `start <= end_incl`.
563 // `checked_add(1)` safely restores half-open representation, therefore the constructed
564 // interval satisfies `start < end_excl`.
565 Some(unsafe { Self::new_unchecked(start, end_excl) })
566 }
567 }
568 }
569
570 // ========================================================
571 // SATURATING
572 // ========================================================
573 pub mod saturating {
574 use super::*;
575
576 impl I32CO {
577 #[inline]
578 pub const fn saturating_minkowski_add(self, other: Self) -> Option<Self> {
579 let start = self.start.saturating_add(other.start);
580 let end_excl = self.end_excl.saturating_add(other.end_incl());
581 Self::try_new(start, end_excl)
582 }
583
584 #[inline]
585 pub const fn saturating_minkowski_sub(self, other: Self) -> Option<Self> {
586 let start = self.start.saturating_sub(other.end_incl());
587 let end_excl = self.end_excl.saturating_sub(other.start);
588 Self::try_new(start, end_excl)
589 }
590
591 #[inline]
592 pub const fn saturating_minkowski_mul(self, other: Self) -> Option<Self> {
593 let a = self.start.saturating_mul(other.start);
594 let b = self.start.saturating_mul(other.end_incl());
595 let c = self.end_incl().saturating_mul(other.start);
596 let d = self.end_incl().saturating_mul(other.end_incl());
597
598 let (start, end_incl) = min_max4(a, b, c, d);
599
600 let end_excl = end_incl.saturating_add(1);
601 Self::try_new(start, end_excl)
602 }
603
604 #[inline]
605 pub const fn saturating_minkowski_div(self, other: Self) -> Option<Self> {
606 if other.start <= 0 && other.end_incl() >= 0 {
607 return None;
608 }
609
610 let a = self.start / other.start;
611 let b = self.start / other.end_incl();
612 let c = self.end_incl() / other.start;
613 let d = self.end_incl() / other.end_incl();
614
615 let (start, end_incl) = min_max4(a, b, c, d);
616
617 let end_excl = end_incl.saturating_add(1);
618 Self::try_new(start, end_excl)
619 }
620 }
621
622 impl I32CO {
623 #[inline]
624 pub const fn saturating_minkowski_add_n(self, n: i32) -> Option<Self> {
625 let start = self.start.saturating_add(n);
626 let end_excl = self.end_excl.saturating_add(n);
627 Self::try_new(start, end_excl)
628 }
629
630 #[inline]
631 pub const fn saturating_minkowski_sub_n(self, n: i32) -> Option<Self> {
632 let start = self.start.saturating_sub(n);
633 let end_excl = self.end_excl.saturating_sub(n);
634 Self::try_new(start, end_excl)
635 }
636
637 #[inline]
638 pub const fn saturating_minkowski_mul_n(self, n: i32) -> Option<Self> {
639 let a = self.start.saturating_mul(n);
640 let b = self.end_incl().saturating_mul(n);
641
642 let (start, end_incl) = min_max2(a, b);
643
644 let end_excl = end_incl.saturating_add(1);
645 Self::try_new(start, end_excl)
646 }
647
648 #[inline]
649 pub const fn saturating_minkowski_div_n(self, n: i32) -> Option<Self> {
650 if n == 0 {
651 return None;
652 }
653
654 let a = self.start / n;
655 let b = self.end_incl() / n;
656
657 let (start, end_incl) = min_max2(a, b);
658
659 let end_excl = end_incl.saturating_add(1);
660 Self::try_new(start, end_excl)
661 }
662 }
663 }
664}