Skip to main content

int_intervals/interval/
u128.rs

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