Skip to main content

int_interval/
usize.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 transform_tests;
21#[cfg(test)]
22mod union_tests;
23
24#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
25pub struct UsizeCO {
26    start: usize,
27    end_excl: usize,
28}
29
30// ------------------------------------------------------------
31// low-level api: construction / accessors / predicates
32// ------------------------------------------------------------
33
34mod construction_accessors_predicates {
35
36    use super::*;
37
38    impl UsizeCO {
39        #[inline]
40        pub const fn try_new(start: usize, end_excl: usize) -> 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: usize, end_excl: usize) -> Self {
50            debug_assert!(start < end_excl);
51            Self { start, end_excl }
52        }
53
54        #[inline]
55        pub const fn start(self) -> usize {
56            self.start
57        }
58
59        #[inline]
60        pub const fn end_excl(self) -> usize {
61            self.end_excl
62        }
63
64        #[inline]
65        pub const fn end_incl(self) -> usize {
66            // usize_low_bound =< start < end_excl
67            self.end_excl - 1
68        }
69
70        #[inline]
71        pub const fn len(self) -> usize {
72            self.end_excl - self.start
73        }
74
75        #[inline]
76        pub const fn contains(self, x: usize) -> bool {
77            self.start <= x && x < self.end_excl
78        }
79
80        #[inline]
81        pub const fn iter(self) -> core::ops::Range<usize> {
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 UsizeCO {
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 `UsizeCO`.
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// interval arithmetic / transform api: scale / shift / scale_then_shift / shift_then_scale
235// ------------------------------------------------------------
236
237mod interval_arithmetic {
238
239    use super::*;
240
241    impl UsizeCO {
242        #[inline]
243        pub const fn scale(self, factor: usize) -> Option<Self> {
244            if factor == 0 || self.end_excl > usize::MAX / factor {
245                return None;
246            }
247            Some(UsizeCO::new_unchecked(
248                self.start * factor,
249                self.end_excl * factor,
250            ))
251        }
252
253        #[inline]
254        pub const fn shift(self, offset: usize) -> Option<Self> {
255            if self.end_excl > usize::MAX - offset {
256                return None;
257            }
258            Some(UsizeCO::new_unchecked(
259                self.start + offset,
260                self.end_excl + offset,
261            ))
262        }
263    }
264}