Skip to main content

int_interval/
i128.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 I128CO {
28    start: i128,
29    end_excl: i128,
30}
31
32// ------------------------------------------------------------
33// low-level api: construction / accessors / predicates
34// ------------------------------------------------------------
35mod basic {
36
37    use super::*;
38
39    impl I128CO {
40        #[inline]
41        pub const fn try_new(start: i128, end_excl: i128) -> 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: i128, end_excl: i128) -> Self {
51            debug_assert!(start < end_excl);
52            Self { start, end_excl }
53        }
54
55        #[inline]
56        pub const fn start(self) -> i128 {
57            self.start
58        }
59
60        #[inline]
61        pub const fn end_excl(self) -> i128 {
62            self.end_excl
63        }
64
65        #[inline]
66        pub const fn end_incl(self) -> i128 {
67            // i128_low_bound =< start < end_excl
68            self.end_excl - 1
69        }
70
71        #[inline]
72        pub const fn len(self) -> u128 {
73            const SIGN_MASK: u128 = 1 << (i128::BITS - 1);
74            ((self.end_excl as u128) ^ SIGN_MASK) - ((self.start as u128) ^ 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 `i128` range)
83        #[inline]
84        pub const fn midpoint(self) -> i128 {
85            self.start + (self.len() / 2) as i128
86        }
87
88        /// Constructs an `I128CO` interval from a midpoint and length (`u128`).
89        ///
90        /// # Parameters
91        /// - `mid`: the desired midpoint of the interval
92        /// - `len`: the desired length of the interval in units, must be `1..=u128::MAX`
93        ///
94        /// # Returns
95        /// - `Some(I128CO)` if the interval `[start, end_excl)` can be represented in `i128`
96        /// - `None` if `len = 0` or the computed `start` / `end_excl` would overflow `i128`
97        ///
98        /// # Guarantees
99        /// - Returned interval satisfies `start < end_excl`
100        /// - Maximum accepted input length is `u128::MAX`
101        #[inline]
102        pub const fn checked_from_midpoint_len(mid: i128, len: u128) -> Option<Self> {
103            if len == 0 {
104                return None;
105            }
106
107            let half = (len / 2) as i128;
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 i128) 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 `i128`.
123            // 2. `mid.checked_add(the_other_half)` ensures `end_excl` does not overflow `i128`.
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 `I128CO` interval from a midpoint and length (`u128`) 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..=u128::MAX`
134        ///
135        /// # Behavior
136        /// - Values are saturated at `i128::MIN` / `i128::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 `u128::MAX`
142        /// - Fully compatible with codegen for other signed integer interval types
143        #[inline]
144        pub const fn saturating_from_midpoint_len(mid: i128, len: u128) -> Option<Self> {
145            if len == 0 {
146                return None;
147            }
148
149            let half = (len / 2) as i128;
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 i128);
154
155            Self::try_new(start, end_excl)
156        }
157
158        #[inline]
159        pub const fn contains(self, x: i128) -> 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<i128> {
170            self.start..self.end_excl
171        }
172
173        #[inline]
174        pub const fn to_range(self) -> core::ops::Range<i128> {
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 I128CO {
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 `I128CO`.
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 I128CO
328// Provides checked and saturating Minkowski operations for intervals
329// ------------------------------------------------------------
330
331pub mod minkowski {
332    use super::*;
333
334    type Min = i128;
335    type Max = i128;
336
337    #[inline]
338    const fn min_max4(a: i128, b: i128, c: i128, d: i128) -> (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: i128, b: i128) -> (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 I128CO {
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 I128CO {
481            #[inline]
482            pub const fn checked_minkowski_add_n(self, n: i128) -> 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: i128) -> 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: i128) -> 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: i128) -> 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 I128CO {
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 I128CO {
623            #[inline]
624            pub const fn saturating_minkowski_add_n(self, n: i128) -> 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: i128) -> 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: i128) -> 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: i128) -> 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}