Skip to main content

int_interval/
u128.rs

1// -----------------------------------------------------------------------------
2// @generated by xtask/codegen (unsigned)
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 saturating_minkowski_tests;
23#[cfg(test)]
24mod symmetric_difference_tests;
25#[cfg(test)]
26mod union_tests;
27
28#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
29pub struct U128CO {
30    start: u128,
31    end_excl: u128,
32}
33
34// ------------------------------------------------------------
35// low-level api: construction / accessors / predicates
36// ------------------------------------------------------------
37
38mod basic {
39
40    use super::*;
41
42    impl U128CO {
43        #[inline]
44        pub const fn try_new(start: u128, end_excl: u128) -> Option<Self> {
45            if start < end_excl {
46                Some(Self { start, end_excl })
47            } else {
48                None
49            }
50        }
51
52        #[inline]
53        pub const unsafe fn new_unchecked(start: u128, end_excl: u128) -> Self {
54            debug_assert!(start < end_excl);
55            Self { start, end_excl }
56        }
57
58        #[inline]
59        pub const fn start(self) -> u128 {
60            self.start
61        }
62
63        #[inline]
64        pub const fn end_excl(self) -> u128 {
65            self.end_excl
66        }
67
68        #[inline]
69        pub const fn end_incl(self) -> u128 {
70            // u128_low_bound =< start < end_excl
71            self.end_excl - 1
72        }
73
74        #[inline]
75        pub const fn len(self) -> u128 {
76            self.end_excl - self.start
77        }
78
79        /// Returns the midpoint of the interval (floor division).
80        #[inline]
81        pub const fn midpoint(self) -> u128 {
82            self.start + (self.len() / 2)
83        }
84
85        /// Construct a `U128CO` from a midpoint and a length.
86        ///
87        /// Returns `None` if the computed interval is invalid or overflows u128.
88        #[inline]
89        pub const fn checked_from_midpoint_len(mid: u128, len: u128) -> Option<Self> {
90            if len == 0 {
91                return None;
92            }
93            // Compute start = mid - floor(len/2)
94            let Some(start) = mid.checked_sub(len / 2) else {
95                return None;
96            };
97            // Compute end_excl = start + len, return None if overflow
98            let Some(end_excl) = start.checked_add(len) else {
99                return None;
100            };
101
102            // # Safety
103            // This function uses `unsafe { Self::new_unchecked(start, end_excl) }` internally.
104            // The safety is guaranteed by the following checks:
105            // 1. `mid.checked_sub(len / 2)` ensures `start` does not underflow `u128`.
106            // 2. `start.checked_add(len)` ensures `end_excl` does not overflow `u128`.
107            // 3. Because `len > 0`, we have `start < end_excl`.
108            // 4. Therefore, the half-open interval invariant `[start, end_excl)` is preserved.
109            Some(unsafe { Self::new_unchecked(start, end_excl) })
110        }
111
112        /// Saturating version: from midpoint + length, keeps start < end_excl
113        #[inline]
114        pub const fn saturating_from_midpoint_len(mid: u128, len: u128) -> Option<Self> {
115            if len == 0 {
116                return None;
117            }
118
119            let start = mid.saturating_sub(len / 2);
120            let end_excl = start.saturating_add(len);
121
122            // Use try_new to enforce start < end_excl invariant
123            Self::try_new(start, end_excl)
124        }
125
126        #[inline]
127        pub const fn contains(self, x: u128) -> bool {
128            self.start <= x && x < self.end_excl
129        }
130
131        #[inline]
132        pub const fn contains_interval(self, other: Self) -> bool {
133            self.start <= other.start && other.end_excl <= self.end_excl
134        }
135
136        #[inline]
137        pub const fn iter(self) -> core::ops::Range<u128> {
138            self.start..self.end_excl
139        }
140
141        #[inline]
142        pub const fn to_range(self) -> core::ops::Range<u128> {
143            self.start..self.end_excl
144        }
145
146        #[inline]
147        pub const fn intersects(self, other: Self) -> bool {
148            !(self.end_excl <= other.start || other.end_excl <= self.start)
149        }
150
151        #[inline]
152        pub const fn is_adjacent(self, other: Self) -> bool {
153            self.end_excl == other.start || other.end_excl == self.start
154        }
155
156        #[inline]
157        pub const fn is_contiguous_with(self, other: Self) -> bool {
158            self.intersects(other) || self.is_adjacent(other)
159        }
160    }
161}
162
163// ------------------------------------------------------------
164// interval algebra api: intersection / convex_hull / between / union / difference / symmetric_difference
165// ------------------------------------------------------------
166
167mod interval_algebra {
168
169    use super::*;
170
171    impl U128CO {
172        /// Returns the intersection of two intervals.
173        ///
174        /// If the intervals do not overlap, returns `None`.
175        #[inline]
176        pub const fn intersection(self, other: Self) -> Option<Self> {
177            let start = if self.start >= other.start {
178                self.start
179            } else {
180                other.start
181            };
182
183            let end_excl = if self.end_excl <= other.end_excl {
184                self.end_excl
185            } else {
186                other.end_excl
187            };
188
189            Self::try_new(start, end_excl)
190        }
191
192        /// Returns the convex hull (smallest interval containing both) of two intervals.
193        ///
194        /// Always returns a valid `U128CO`.
195        #[inline]
196        pub const fn convex_hull(self, other: Self) -> Self {
197            let start = if self.start <= other.start {
198                self.start
199            } else {
200                other.start
201            };
202
203            let end_excl = if self.end_excl >= other.end_excl {
204                self.end_excl
205            } else {
206                other.end_excl
207            };
208
209            Self { start, end_excl }
210        }
211
212        /// Returns the interval strictly between two intervals.
213        ///
214        /// If the intervals are contiguous or overlap, returns `None`.
215        #[inline]
216        pub const fn between(self, other: Self) -> Option<Self> {
217            let (left, right) = if self.start <= other.start {
218                (self, other)
219            } else {
220                (other, self)
221            };
222
223            Self::try_new(left.end_excl, right.start)
224        }
225
226        /// Returns the union of two intervals.
227        ///
228        /// - If intervals are contiguous or overlapping, returns `One` containing the merged interval.
229        /// - Otherwise, returns `Two` containing both intervals in ascending order.
230        #[inline]
231        pub const fn union(self, other: Self) -> OneTwo<Self> {
232            if self.is_contiguous_with(other) {
233                OneTwo::One(self.convex_hull(other))
234            } else if self.start <= other.start {
235                OneTwo::Two(self, other)
236            } else {
237                OneTwo::Two(other, self)
238            }
239        }
240
241        /// Returns the difference of two intervals (self - other).
242        ///
243        /// - If no overlap, returns `One(self)`.
244        /// - If partial overlap, returns `One` or `Two` depending on remaining segments.
245        /// - If fully contained, returns `Zero`.
246        #[inline]
247        pub const fn difference(self, other: Self) -> ZeroOneTwo<Self> {
248            match self.intersection(other) {
249                None => ZeroOneTwo::One(self),
250                Some(inter) => {
251                    let left = Self::try_new(self.start, inter.start);
252                    let right = Self::try_new(inter.end_excl, self.end_excl);
253
254                    match (left, right) {
255                        (None, None) => ZeroOneTwo::Zero,
256                        (Some(x), None) | (None, Some(x)) => ZeroOneTwo::One(x),
257                        (Some(x), Some(y)) => ZeroOneTwo::Two(x, y),
258                    }
259                }
260            }
261        }
262
263        /// Returns the symmetric difference of two intervals.
264        ///
265        /// Equivalent to `(self - other) ∪ (other - self)`.
266        /// - If intervals do not overlap, returns `Two(self, other)` in order.
267        /// - If intervals partially overlap, returns remaining non-overlapping segments as `One` or `Two`.
268        #[inline]
269        pub const fn symmetric_difference(self, other: Self) -> ZeroOneTwo<Self> {
270            match self.intersection(other) {
271                None => {
272                    if self.start <= other.start {
273                        ZeroOneTwo::Two(self, other)
274                    } else {
275                        ZeroOneTwo::Two(other, self)
276                    }
277                }
278                Some(inter) => {
279                    let hull = self.convex_hull(other);
280                    let left = Self::try_new(hull.start, inter.start);
281                    let right = Self::try_new(inter.end_excl, hull.end_excl);
282
283                    match (left, right) {
284                        (None, None) => ZeroOneTwo::Zero,
285                        (Some(x), None) | (None, Some(x)) => ZeroOneTwo::One(x),
286                        (Some(x), Some(y)) => ZeroOneTwo::Two(x, y),
287                    }
288                }
289            }
290        }
291    }
292}
293
294// ------------------------------------------------------------
295// Module: Minkowski arithmetic for U128CO
296// Provides checked and saturating Minkowski operations
297// ------------------------------------------------------------
298
299pub mod minkowski {
300    use super::*;
301
302    pub mod checked {
303        use super::*;
304
305        // --------------------------------------------------------
306        // Interval-to-interval Minkowski operations
307        // --------------------------------------------------------
308        impl U128CO {
309            /// Minkowski addition: [a_start, a_end) + [b_start, b_end)
310            #[inline]
311            pub const fn checked_minkowski_add(self, other: Self) -> Option<Self> {
312                let Some(start) = self.start.checked_add(other.start) else {
313                    return None;
314                };
315                let Some(end_excl) = self.end_excl.checked_add(other.end_incl()) else {
316                    return None;
317                };
318
319                // SAFETY:
320                // `checked_add` guarantees both bounds are computed without overflow.
321                // For half-open intervals, addition preserves ordering:
322                // self.start <= self.end_excl - 1 and other.start <= other.end_incl(),
323                // therefore `start < end_excl` still holds for the resulting interval.
324                Some(unsafe { Self::new_unchecked(start, end_excl) })
325            }
326
327            /// Minkowski subtraction: [a_start, a_end) - [b_start, b_end)
328            #[inline]
329            pub const fn checked_minkowski_sub(self, other: Self) -> Option<Self> {
330                let Some(start) = self.start.checked_sub(other.end_incl()) else {
331                    return None;
332                };
333                let Some(end_excl) = self.end_excl.checked_sub(other.start) else {
334                    return None;
335                };
336
337                // SAFETY:
338                // `checked_sub` guarantees both bounds are computed without underflow.
339                // Since `self.start <= self.end_excl - 1` and `other.start <= other.end_incl()`,
340                // we have `self.start - other.end_incl() < self.end_excl - other.start`,
341                // so the resulting half-open interval remains valid.
342                Some(unsafe { Self::new_unchecked(start, end_excl) })
343            }
344
345            /// Minkowski multiplication: [a_start, a_end) * [b_start, b_end)
346            #[inline]
347            pub const fn checked_minkowski_mul(self, other: Self) -> Option<Self> {
348                let Some(start) = self.start.checked_mul(other.start) else {
349                    return None;
350                };
351                let Some(end_incl) = self.end_incl().checked_mul(other.end_incl()) else {
352                    return None;
353                };
354                let Some(end_excl) = end_incl.checked_add(1) else {
355                    return None;
356                };
357
358                // SAFETY:
359                // For `U128CO`, all values are non-negative, so endpoint-wise multiplication
360                // is monotone. `start` is the minimum product and `end_incl` is the maximum.
361                // `checked_add(1)` converts the inclusive upper bound back to half-open form,
362                // and overflow has already been excluded.
363                Some(unsafe { Self::new_unchecked(start, end_excl) })
364            }
365
366            /// Minkowski division: [a_start, a_end) / [b_start, b_end)
367            #[inline]
368            pub const fn checked_minkowski_div(self, other: Self) -> Option<Self> {
369                if other.start == 0 {
370                    return None;
371                }
372
373                let Some(start) = self.start.checked_div(other.end_incl()) else {
374                    return None;
375                };
376                let Some(end_incl) = self.end_incl().checked_div(other.start) else {
377                    return None;
378                };
379                let Some(end_excl) = end_incl.checked_add(1) else {
380                    return None;
381                };
382
383                // SAFETY:
384                // `other.start != 0` excludes division by zero, and all operands are unsigned.
385                // Over positive integers, division is monotone with respect to the dividend and
386                // anti-monotone with respect to the divisor, so:
387                //   min = self.start / other.end_incl()
388                //   max = self.end_incl() / other.start
389                // Thus `start <= end_incl`, and `end_excl = end_incl + 1` is checked.
390                Some(unsafe { Self::new_unchecked(start, end_excl) })
391            }
392        }
393
394        // --------------------------------------------------------
395        // Interval-to-scalar Minkowski operations
396        // --------------------------------------------------------
397        impl U128CO {
398            /// Add a scalar to an interval: [start, end) + n
399            #[inline]
400            pub const fn checked_minkowski_add_n(self, n: u128) -> Option<Self> {
401                let Some(start) = self.start.checked_add(n) else {
402                    return None;
403                };
404                let Some(end_excl) = self.end_excl.checked_add(n) else {
405                    return None;
406                };
407
408                // SAFETY:
409                // `checked_add` excludes overflow, and adding the same scalar to both bounds
410                // preserves the half-open interval ordering.
411                Some(unsafe { Self::new_unchecked(start, end_excl) })
412            }
413
414            /// Subtract a scalar from an interval: [start, end) - n
415            #[inline]
416            pub const fn checked_minkowski_sub_n(self, n: u128) -> Option<Self> {
417                let Some(start) = self.start.checked_sub(n) else {
418                    return None;
419                };
420                let Some(end_excl) = self.end_excl.checked_sub(n) else {
421                    return None;
422                };
423
424                // SAFETY:
425                // `checked_sub` excludes underflow, and subtracting the same scalar from both
426                // bounds preserves the half-open interval ordering.
427                Some(unsafe { Self::new_unchecked(start, end_excl) })
428            }
429
430            /// Multiply an interval by a scalar: [start, end) * n
431            #[inline]
432            pub const fn checked_minkowski_mul_n(self, n: u128) -> Option<Self> {
433                let Some(start) = self.start.checked_mul(n) else {
434                    return None;
435                };
436                let Some(end_incl) = self.end_incl().checked_mul(n) else {
437                    return None;
438                };
439                let Some(end_excl) = end_incl.checked_add(1) else {
440                    return None;
441                };
442
443                // SAFETY:
444                // For unsigned integers, multiplication by a scalar is monotone.
445                // Therefore `start * n` is the lower bound and `end_incl * n` is the upper bound.
446                // `checked_*` operations exclude overflow, and `end_excl` restores half-open form.
447                Some(unsafe { Self::new_unchecked(start, end_excl) })
448            }
449
450            /// Divide an interval by a scalar: [start, end) / n
451            #[inline]
452            pub const fn checked_minkowski_div_n(self, n: u128) -> Option<Self> {
453                if n == 0 {
454                    return None;
455                }
456
457                let start = self.start / n;
458                let end_incl = self.end_incl() / n;
459                let Some(end_excl) = end_incl.checked_add(1) else {
460                    return None;
461                };
462
463                // SAFETY:
464                // `n != 0` excludes division by zero. For unsigned integers and positive scalar `n`,
465                // division is monotone, so `self.start / n <= self.end_incl() / n`.
466                // `checked_add(1)` safely converts the inclusive upper bound to half-open form.
467                Some(unsafe { Self::new_unchecked(start, end_excl) })
468            }
469        }
470    }
471
472    pub mod saturating {
473        use super::*;
474
475        // --------------------------------------------------------
476        // Interval-to-interval Minkowski operations
477        // --------------------------------------------------------
478        impl U128CO {
479            #[inline]
480            pub const fn saturating_minkowski_add(self, other: Self) -> Option<Self> {
481                let start = self.start.saturating_add(other.start);
482                let end_excl = self.end_excl.saturating_add(other.end_incl());
483                Self::try_new(start, end_excl)
484            }
485
486            #[inline]
487            pub const fn saturating_minkowski_sub(self, other: Self) -> Option<Self> {
488                let start = self.start.saturating_sub(other.end_incl());
489                let end_excl = self.end_excl.saturating_sub(other.start);
490                Self::try_new(start, end_excl)
491            }
492
493            #[inline]
494            pub const fn saturating_minkowski_mul(self, other: Self) -> Option<Self> {
495                let start = self.start.saturating_mul(other.start);
496                let end_incl = self.end_incl().saturating_mul(other.end_incl());
497                let end_excl = end_incl.saturating_add(1);
498                Self::try_new(start, end_excl)
499            }
500
501            #[inline]
502            pub const fn saturating_minkowski_div(self, other: Self) -> Option<Self> {
503                if other.start == 0 {
504                    return None;
505                }
506
507                let start = self.start / other.end_incl();
508                let end_incl = self.end_incl() / other.start;
509                let end_excl = end_incl.saturating_add(1);
510                Self::try_new(start, end_excl)
511            }
512        }
513
514        // --------------------------------------------------------
515        // Interval-to-scalar Minkowski operations
516        // --------------------------------------------------------
517        impl U128CO {
518            /// Saturating add scalar: [start, end) + n
519            #[inline]
520            pub const fn saturating_minkowski_add_n(self, n: u128) -> Option<Self> {
521                let start = self.start.saturating_add(n);
522                let end_excl = self.end_excl.saturating_add(n);
523                Self::try_new(start, end_excl)
524            }
525
526            /// Saturating sub scalar: [start, end) - n
527            #[inline]
528            pub const fn saturating_minkowski_sub_n(self, n: u128) -> Option<Self> {
529                let start = self.start.saturating_sub(n);
530                let end_excl = self.end_excl.saturating_sub(n);
531                Self::try_new(start, end_excl)
532            }
533
534            /// Saturating mul scalar: [start, end) * n
535            #[inline]
536            pub const fn saturating_minkowski_mul_n(self, n: u128) -> Option<Self> {
537                let start = self.start.saturating_mul(n);
538                let end_incl = self.end_incl().saturating_mul(n);
539                let end_excl = end_incl.saturating_add(1);
540                Self::try_new(start, end_excl)
541            }
542
543            /// Saturating div scalar: [start, end) / n
544            #[inline]
545            pub const fn saturating_minkowski_div_n(self, n: u128) -> Option<Self> {
546                if n == 0 {
547                    return None;
548                }
549
550                let start = self.start / n;
551                let end_incl = self.end_incl() / n;
552                let end_excl = end_incl.saturating_add(1);
553                Self::try_new(start, end_excl)
554            }
555        }
556    }
557}