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 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 I128CO {
26    start: i128,
27    end_excl: i128,
28}
29
30// ------------------------------------------------------------
31// low-level api: construction / accessors / predicates
32// ------------------------------------------------------------
33mod construction_accessors_predicates {
34
35    use super::*;
36
37    impl I128CO {
38        #[inline]
39        pub const fn try_new(start: i128, end_excl: i128) -> 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: i128, end_excl: i128) -> Self {
49            debug_assert!(start < end_excl);
50            Self { start, end_excl }
51        }
52
53        #[inline]
54        pub const fn start(self) -> i128 {
55            self.start
56        }
57
58        #[inline]
59        pub const fn end_excl(self) -> i128 {
60            self.end_excl
61        }
62
63        #[inline]
64        pub const fn end_incl(self) -> i128 {
65            // i128_low_bound =< start < end_excl
66            self.end_excl - 1
67        }
68
69        #[inline]
70        pub const fn len(self) -> u128 {
71            (self.end_excl - self.start) as u128
72        }
73
74        #[inline]
75        pub const fn contains(self, x: i128) -> bool {
76            self.start <= x && x < self.end_excl
77        }
78
79        #[inline]
80        pub const fn iter(self) -> core::ops::Range<i128> {
81            self.start..self.end_excl
82        }
83
84        #[inline]
85        pub const fn to_range(self) -> core::ops::Range<i128> {
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 I128CO {
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 `I128CO`.
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 I128CO
238// Provides checked and saturating Minkowski operations for intervals
239// ------------------------------------------------------------
240
241pub mod minkowski {
242    use super::*;
243
244    type Min = i128;
245    type Max = i128;
246
247    #[inline]
248    const fn min_max4(a: i128, b: i128, c: i128, d: i128) -> (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: i128, b: i128) -> (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 I128CO {
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 I128CO {
391            #[inline]
392            pub const fn checked_minkowski_add_n(self, n: i128) -> 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: i128) -> 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: i128) -> 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: i128) -> 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 I128CO {
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 I128CO {
533            #[inline]
534            pub const fn saturating_minkowski_add_n(self, n: i128) -> 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: i128) -> 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: i128) -> 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: i128) -> 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}