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 convex_hull_tests;
13#[cfg(test)]
14mod difference_tests;
15#[cfg(test)]
16mod intersection_tests;
17#[cfg(test)]
18mod symmetric_difference_tests;
19#[cfg(test)]
20mod minkowski_tests;
21#[cfg(test)]
22mod union_tests;
23
24#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
25pub struct U64CO {
26    start: u64,
27    end_excl: u64,
28}
29
30// ------------------------------------------------------------
31// low-level api: construction / accessors / predicates
32// ------------------------------------------------------------
33
34mod construction_accessors_predicates {
35
36    use super::*;
37
38    impl U64CO {
39        #[inline]
40        pub const fn try_new(start: u64, end_excl: u64) -> Option<Self> {
41            if start < end_excl {
42                Some(Self { start, end_excl })
43            } else {
44                None
45            }
46        }
47
48        #[inline]
49        pub(super) const fn new_unchecked(start: u64, end_excl: u64) -> Self {
50            debug_assert!(start < end_excl);
51            Self { start, end_excl }
52        }
53
54        #[inline]
55        pub const fn start(self) -> u64 {
56            self.start
57        }
58
59        #[inline]
60        pub const fn end_excl(self) -> u64 {
61            self.end_excl
62        }
63
64        #[inline]
65        pub const fn end_incl(self) -> u64 {
66            // u64_low_bound =< start < end_excl
67            self.end_excl - 1
68        }
69
70        #[inline]
71        pub const fn len(self) -> u64 {
72            self.end_excl - self.start
73        }
74
75        #[inline]
76        pub const fn contains(self, x: u64) -> bool {
77            self.start <= x && x < self.end_excl
78        }
79
80        #[inline]
81        pub const fn iter(self) -> core::ops::Range<u64> {
82            self.start..self.end_excl
83        }
84
85        #[inline]
86        pub const fn intersects(self, other: Self) -> bool {
87            !(self.end_excl <= other.start || other.end_excl <= self.start)
88        }
89
90        #[inline]
91        pub const fn is_adjacent(self, other: Self) -> bool {
92            self.end_excl == other.start || other.end_excl == self.start
93        }
94
95        #[inline]
96        pub const fn is_contiguous_with(self, other: Self) -> bool {
97            self.intersects(other) || self.is_adjacent(other)
98        }
99    }
100}
101
102// ------------------------------------------------------------
103// interval algebra api: intersection / convex_hull / between / union / difference / symmetric_difference
104// ------------------------------------------------------------
105
106mod interval_algebra {
107
108    use super::*;
109
110    impl U64CO {
111        /// Returns the intersection of two intervals.
112        ///
113        /// If the intervals do not overlap, returns `None`.
114        #[inline]
115        pub const fn intersection(self, other: Self) -> Option<Self> {
116            let start = if self.start >= other.start {
117                self.start
118            } else {
119                other.start
120            };
121
122            let end_excl = if self.end_excl <= other.end_excl {
123                self.end_excl
124            } else {
125                other.end_excl
126            };
127
128            Self::try_new(start, end_excl)
129        }
130
131        /// Returns the convex hull (smallest interval containing both) of two intervals.
132        ///
133        /// Always returns a valid `U64CO`.
134        #[inline]
135        pub const fn convex_hull(self, other: Self) -> Self {
136            let start = if self.start <= other.start {
137                self.start
138            } else {
139                other.start
140            };
141
142            let end_excl = if self.end_excl >= other.end_excl {
143                self.end_excl
144            } else {
145                other.end_excl
146            };
147
148            Self { start, end_excl }
149        }
150
151        /// Returns the interval strictly between two intervals.
152        ///
153        /// If the intervals are contiguous or overlap, returns `None`.
154        #[inline]
155        pub const fn between(self, other: Self) -> Option<Self> {
156            let (left, right) = if self.start <= other.start {
157                (self, other)
158            } else {
159                (other, self)
160            };
161
162            Self::try_new(left.end_excl, right.start)
163        }
164
165        /// Returns the union of two intervals.
166        ///
167        /// - If intervals are contiguous or overlapping, returns `One` containing the merged interval.
168        /// - Otherwise, returns `Two` containing both intervals in ascending order.
169        #[inline]
170        pub const fn union(self, other: Self) -> OneTwo<Self> {
171            if self.is_contiguous_with(other) {
172                OneTwo::One(self.convex_hull(other))
173            } else if self.start <= other.start {
174                OneTwo::Two(self, other)
175            } else {
176                OneTwo::Two(other, self)
177            }
178        }
179
180        /// Returns the difference of two intervals (self - other).
181        ///
182        /// - If no overlap, returns `One(self)`.
183        /// - If partial overlap, returns `One` or `Two` depending on remaining segments.
184        /// - If fully contained, returns `Zero`.
185        #[inline]
186        pub const fn difference(self, other: Self) -> ZeroOneTwo<Self> {
187            match self.intersection(other) {
188                None => ZeroOneTwo::One(self),
189                Some(inter) => {
190                    let left = Self::try_new(self.start, inter.start);
191                    let right = Self::try_new(inter.end_excl, self.end_excl);
192
193                    match (left, right) {
194                        (None, None) => ZeroOneTwo::Zero,
195                        (Some(x), None) | (None, Some(x)) => ZeroOneTwo::One(x),
196                        (Some(x), Some(y)) => ZeroOneTwo::Two(x, y),
197                    }
198                }
199            }
200        }
201
202        /// Returns the symmetric difference of two intervals.
203        ///
204        /// Equivalent to `(self - other) ∪ (other - self)`.
205        /// - If intervals do not overlap, returns `Two(self, other)` in order.
206        /// - If intervals partially overlap, returns remaining non-overlapping segments as `One` or `Two`.
207        #[inline]
208        pub const fn symmetric_difference(self, other: Self) -> ZeroOneTwo<Self> {
209            match self.intersection(other) {
210                None => {
211                    if self.start <= other.start {
212                        ZeroOneTwo::Two(self, other)
213                    } else {
214                        ZeroOneTwo::Two(other, self)
215                    }
216                }
217                Some(inter) => {
218                    let hull = self.convex_hull(other);
219                    let left = Self::try_new(hull.start, inter.start);
220                    let right = Self::try_new(inter.end_excl, hull.end_excl);
221
222                    match (left, right) {
223                        (None, None) => ZeroOneTwo::Zero,
224                        (Some(x), None) | (None, Some(x)) => ZeroOneTwo::One(x),
225                        (Some(x), Some(y)) => ZeroOneTwo::Two(x, y),
226                    }
227                }
228            }
229        }
230    }
231}
232
233// ------------------------------------------------------------
234// Module: Minkowski arithmetic for U64CO
235// Provides checked Minkowski operations for intervals
236// ------------------------------------------------------------
237
238pub mod minkowski {
239    use super::U64CO;
240
241    // --------------------------------------------------------
242    // Interval-to-interval Minkowski operations
243    // --------------------------------------------------------
244    impl U64CO {
245        /// Minkowski addition: [a_start, a_end) + [b_start, b_end)
246        #[inline]
247        pub const fn minkowski_add(self, other: Self) -> Option<Self> {
248            match self.start.checked_add(other.start) {
249                Some(start) => match self.end_incl().checked_add(other.end_incl()) {
250                    Some(end_incl) => match end_incl.checked_add(1) {
251                        Some(end_excl) => Some(Self::new_unchecked(start, end_excl)),
252                        None => None,
253                    },
254                    None => None,
255                },
256                None => None,
257            }
258        }
259
260        /// Minkowski subtraction: [a_start, a_end) - [b_start, b_end)
261        #[inline]
262        pub const fn minkowski_sub(self, other: Self) -> Option<Self> {
263            match self.start.checked_sub(other.end_incl()) {
264                Some(start) => match self.end_incl().checked_sub(other.start) {
265                    Some(end_incl) => match end_incl.checked_add(1) {
266                        Some(end_excl) => Some(Self::new_unchecked(start, end_excl)),
267                        None => None,
268                    },
269                    None => None,
270                },
271                None => None,
272            }
273        }
274
275        /// Minkowski multiplication: [a_start, a_end) * [b_start, b_end)
276        #[inline]
277        pub const fn minkowski_mul(self, other: Self) -> Option<Self> {
278            match self.start.checked_mul(other.start) {
279                Some(start) => match self.end_incl().checked_mul(other.end_incl()) {
280                    Some(end_incl) => match end_incl.checked_add(1) {
281                        Some(end_excl) => Some(Self::new_unchecked(start, end_excl)),
282                        None => None,
283                    },
284                    None => None,
285                },
286                None => None,
287            }
288        }
289
290        /// Minkowski division: [a_start, a_end) / [b_start, b_end)
291        #[inline]
292        pub const fn minkowski_div(self, other: Self) -> Option<Self> {
293            if other.start == 0 {
294                return None; // avoid division by zero
295            }
296            match self.start.checked_div(other.end_incl()) {
297                Some(start) => match self.end_incl().checked_div(other.start) {
298                    Some(end_incl) => match end_incl.checked_add(1) {
299                        Some(end_excl) => Some(Self::new_unchecked(start, end_excl)),
300                        None => None,
301                    },
302                    None => None,
303                },
304                None => None,
305            }
306        }
307    }
308
309    // --------------------------------------------------------
310    // Interval-to-scalar Minkowski operations
311    // --------------------------------------------------------
312    impl U64CO {
313        /// Add a scalar to an interval: [start, end) + n
314        #[inline]
315        pub const fn minkowski_add_n(self, n: u64) -> Option<Self> {
316            match self.start.checked_add(n) {
317                Some(start) => match self.end_excl.checked_add(n) {
318                    Some(end_excl) => Some(Self::new_unchecked(start, end_excl)),
319                    None => None,
320                },
321                None => None,
322            }
323        }
324
325        /// Subtract a scalar from an interval: [start, end) - n
326        #[inline]
327        pub const fn minkowski_sub_n(self, n: u64) -> Option<Self> {
328            match self.start.checked_sub(n) {
329                Some(start) => match self.end_excl.checked_sub(n) {
330                    Some(end_excl) => Some(Self::new_unchecked(start, end_excl)),
331                    None => None,
332                },
333                None => None,
334            }
335        }
336
337        /// Multiply an interval by a scalar: [start, end) * n
338        #[inline]
339        pub const fn minkowski_mul_n(self, n: u64) -> Option<Self> {
340            match self.start.checked_mul(n) {
341                Some(start) => match self.end_incl().checked_mul(n) {
342                    Some(end_incl) => match end_incl.checked_add(1) {
343                        Some(end_excl) => Some(Self::new_unchecked(start, end_excl)),
344                        None => None,
345                    },
346                    None => None,
347                },
348                None => None,
349            }
350        }
351
352        /// Divide an interval by a scalar: [start, end) / n
353        #[inline]
354        pub const fn minkowski_div_n(self, n: u64) -> Option<Self> {
355            if n == 0 {
356                return None; // avoid division by zero
357            }
358            let start = self.start / n;
359            let end_incl = self.end_incl() / n;
360            match end_incl.checked_add(1) {
361                Some(end_excl) => Some(Self::new_unchecked(start, end_excl)),
362                None => None,
363            }
364        }
365    }
366}