Skip to main content

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