Skip to main content

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