Skip to main content

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