Skip to main content

int_interval/
i16.rs

1// -----------------------------------------------------------------------------
2// @generated by xtask/codegen (signed)
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 symmetric_difference_tests;
21#[cfg(test)]
22mod union_tests;
23
24#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
25pub struct I16CO {
26    start: i16,
27    end_excl: i16,
28}
29
30// ------------------------------------------------------------
31// low-level api: construction / accessors / predicates
32// ------------------------------------------------------------
33mod construction_accessors_predicates {
34
35    use super::*;
36
37    impl I16CO {
38        #[inline]
39        pub const fn try_new(start: i16, end_excl: i16) -> Option<Self> {
40            if start < end_excl {
41                Some(Self { start, end_excl })
42            } else {
43                None
44            }
45        }
46
47        #[inline]
48        pub(super) const fn new_unchecked(start: i16, end_excl: i16) -> Self {
49            debug_assert!(start < end_excl);
50            Self { start, end_excl }
51        }
52
53        #[inline]
54        pub const fn start(self) -> i16 {
55            self.start
56        }
57
58        #[inline]
59        pub const fn end_excl(self) -> i16 {
60            self.end_excl
61        }
62
63        #[inline]
64        pub const fn end_incl(self) -> i16 {
65            // i16_low_bound =< start < end_excl
66            self.end_excl - 1
67        }
68
69        #[inline]
70        pub const fn len(self) -> u16 {
71            (self.end_excl - self.start) as u16
72        }
73
74        #[inline]
75        pub const fn contains(self, x: i16) -> bool {
76            self.start <= x && x < self.end_excl
77        }
78
79        #[inline]
80        pub const fn iter(self) -> core::ops::Range<i16> {
81            self.start..self.end_excl
82        }
83
84        #[inline]
85        pub const fn to_range(self) -> core::ops::Range<i16> {
86            self.start..self.end_excl
87        }
88
89        #[inline]
90        pub const fn intersects(self, other: Self) -> bool {
91            !(self.end_excl <= other.start || other.end_excl <= self.start)
92        }
93
94        #[inline]
95        pub const fn is_adjacent(self, other: Self) -> bool {
96            self.end_excl == other.start || other.end_excl == self.start
97        }
98
99        #[inline]
100        pub const fn is_contiguous_with(self, other: Self) -> bool {
101            self.intersects(other) || self.is_adjacent(other)
102        }
103    }
104}
105// ------------------------------------------------------------
106// interval algebra api: intersection / convex_hull / between / union / difference / symmetric_difference
107// ------------------------------------------------------------
108
109mod interval_algebra {
110
111    use super::*;
112
113    impl I16CO {
114        /// Returns the intersection of two intervals.
115        ///
116        /// If the intervals do not overlap, returns `None`.
117        #[inline]
118        pub const fn intersection(self, other: Self) -> Option<Self> {
119            let start = if self.start >= other.start {
120                self.start
121            } else {
122                other.start
123            };
124
125            let end_excl = if self.end_excl <= other.end_excl {
126                self.end_excl
127            } else {
128                other.end_excl
129            };
130
131            Self::try_new(start, end_excl)
132        }
133
134        /// Returns the convex hull (smallest interval containing both) of two intervals.
135        ///
136        /// Always returns a valid `I16CO`.
137        #[inline]
138        pub const fn convex_hull(self, other: Self) -> Self {
139            let start = if self.start <= other.start {
140                self.start
141            } else {
142                other.start
143            };
144
145            let end_excl = if self.end_excl >= other.end_excl {
146                self.end_excl
147            } else {
148                other.end_excl
149            };
150
151            Self { start, end_excl }
152        }
153
154        /// Returns the interval strictly between two intervals.
155        ///
156        /// If the intervals are contiguous or overlap, returns `None`.
157        #[inline]
158        pub const fn between(self, other: Self) -> Option<Self> {
159            let (left, right) = if self.start <= other.start {
160                (self, other)
161            } else {
162                (other, self)
163            };
164
165            Self::try_new(left.end_excl, right.start)
166        }
167
168        /// Returns the union of two intervals.
169        ///
170        /// - If intervals are contiguous or overlapping, returns `One` containing the merged interval.
171        /// - Otherwise, returns `Two` containing both intervals in ascending order.
172        #[inline]
173        pub const fn union(self, other: Self) -> OneTwo<Self> {
174            if self.is_contiguous_with(other) {
175                OneTwo::One(self.convex_hull(other))
176            } else if self.start <= other.start {
177                OneTwo::Two(self, other)
178            } else {
179                OneTwo::Two(other, self)
180            }
181        }
182
183        /// Returns the difference of two intervals (self - other).
184        ///
185        /// - If no overlap, returns `One(self)`.
186        /// - If partial overlap, returns `One` or `Two` depending on remaining segments.
187        /// - If fully contained, returns `Zero`.
188        #[inline]
189        pub const fn difference(self, other: Self) -> ZeroOneTwo<Self> {
190            match self.intersection(other) {
191                None => ZeroOneTwo::One(self),
192                Some(inter) => {
193                    let left = Self::try_new(self.start, inter.start);
194                    let right = Self::try_new(inter.end_excl, self.end_excl);
195
196                    match (left, right) {
197                        (None, None) => ZeroOneTwo::Zero,
198                        (Some(x), None) | (None, Some(x)) => ZeroOneTwo::One(x),
199                        (Some(x), Some(y)) => ZeroOneTwo::Two(x, y),
200                    }
201                }
202            }
203        }
204
205        /// Returns the symmetric difference of two intervals.
206        ///
207        /// Equivalent to `(self - other) ∪ (other - self)`.
208        /// - If intervals do not overlap, returns `Two(self, other)` in order.
209        /// - If intervals partially overlap, returns remaining non-overlapping segments as `One` or `Two`.
210        #[inline]
211        pub const fn symmetric_difference(self, other: Self) -> ZeroOneTwo<Self> {
212            match self.intersection(other) {
213                None => {
214                    if self.start <= other.start {
215                        ZeroOneTwo::Two(self, other)
216                    } else {
217                        ZeroOneTwo::Two(other, self)
218                    }
219                }
220                Some(inter) => {
221                    let hull = self.convex_hull(other);
222                    let left = Self::try_new(hull.start, inter.start);
223                    let right = Self::try_new(inter.end_excl, hull.end_excl);
224
225                    match (left, right) {
226                        (None, None) => ZeroOneTwo::Zero,
227                        (Some(x), None) | (None, Some(x)) => ZeroOneTwo::One(x),
228                        (Some(x), Some(y)) => ZeroOneTwo::Two(x, y),
229                    }
230                }
231            }
232        }
233    }
234}
235
236// ------------------------------------------------------------
237// Module: Minkowski arithmetic for I16CO
238// Provides checked and saturating Minkowski operations for intervals
239// ------------------------------------------------------------
240
241pub mod minkowski {
242    use super::*;
243
244    type Min = i16;
245    type Max = i16;
246
247    #[inline]
248    const fn min_max4(a: i16, b: i16, c: i16, d: i16) -> (Min, Max) {
249        let (min1, max1) = if a < b { (a, b) } else { (b, a) };
250        let (min2, max2) = if c < d { (c, d) } else { (d, c) };
251        let min = if min1 < min2 { min1 } else { min2 };
252        let max = if max1 > max2 { max1 } else { max2 };
253        (min, max)
254    }
255
256    #[inline]
257    const fn min_max2(a: i16, b: i16) -> (Min, Max) {
258        if a < b { (a, b) } else { (b, a) }
259    }
260
261    pub mod checked {
262        use super::*;
263
264        // --------------------------------------------------------
265        // Interval-to-interval
266        // --------------------------------------------------------
267        impl I16CO {
268            #[inline]
269            pub const fn checked_minkowski_add(self, other: Self) -> Option<Self> {
270                let Some(start) = self.start.checked_add(other.start) else {
271                    return None;
272                };
273                let Some(end_excl) = self.end_excl.checked_add(other.end_incl()) else {
274                    return None;
275                };
276                Some(Self::new_unchecked(start, end_excl))
277            }
278
279            #[inline]
280            pub const fn checked_minkowski_sub(self, other: Self) -> Option<Self> {
281                let Some(start) = self.start.checked_sub(other.end_incl()) else {
282                    return None;
283                };
284                let Some(end_excl) = self.end_excl.checked_sub(other.start) else {
285                    return None;
286                };
287                Some(Self::new_unchecked(start, end_excl))
288            }
289
290            #[inline]
291            pub const fn checked_minkowski_mul(self, other: Self) -> Option<Self> {
292                let a = self.start;
293                let b = self.end_incl();
294                let c = other.start;
295                let d = other.end_incl();
296
297                let Some(p1) = a.checked_mul(c) else {
298                    return None;
299                };
300                let Some(p2) = a.checked_mul(d) else {
301                    return None;
302                };
303                let Some(p3) = b.checked_mul(c) else {
304                    return None;
305                };
306                let Some(p4) = b.checked_mul(d) else {
307                    return None;
308                };
309
310                let (start, end_incl) = min_max4(p1, p2, p3, p4);
311
312                let Some(end_excl) = end_incl.checked_add(1) else {
313                    return None;
314                };
315
316                Some(Self::new_unchecked(start, end_excl))
317            }
318
319            #[inline]
320            pub const fn checked_minkowski_div(self, other: Self) -> Option<Self> {
321                if other.start <= 0 && other.end_incl() >= 0 {
322                    return None;
323                }
324
325                let a = self.start;
326                let b = self.end_incl();
327                let c = other.start;
328                let d = other.end_incl();
329
330                let Some(p1) = a.checked_div(c) else {
331                    return None;
332                };
333                let Some(p2) = a.checked_div(d) else {
334                    return None;
335                };
336                let Some(p3) = b.checked_div(c) else {
337                    return None;
338                };
339                let Some(p4) = b.checked_div(d) else {
340                    return None;
341                };
342
343                let (start, end_incl) = min_max4(p1, p2, p3, p4);
344
345                let Some(end_excl) = end_incl.checked_add(1) else {
346                    return None;
347                };
348
349                Some(Self::new_unchecked(start, end_excl))
350            }
351        }
352
353        // --------------------------------------------------------
354        // Scalar
355        // --------------------------------------------------------
356        impl I16CO {
357            #[inline]
358            pub const fn checked_minkowski_add_n(self, n: i16) -> Option<Self> {
359                let Some(start) = self.start.checked_add(n) else {
360                    return None;
361                };
362                let Some(end_excl) = self.end_excl.checked_add(n) else {
363                    return None;
364                };
365                Some(Self::new_unchecked(start, end_excl))
366            }
367
368            #[inline]
369            pub const fn checked_minkowski_sub_n(self, n: i16) -> Option<Self> {
370                let Some(start) = self.start.checked_sub(n) else {
371                    return None;
372                };
373                let Some(end_excl) = self.end_excl.checked_sub(n) else {
374                    return None;
375                };
376                Some(Self::new_unchecked(start, end_excl))
377            }
378
379            #[inline]
380            pub const fn checked_minkowski_mul_n(self, n: i16) -> Option<Self> {
381                let Some(a) = self.start.checked_mul(n) else {
382                    return None;
383                };
384                let Some(b) = self.end_incl().checked_mul(n) else {
385                    return None;
386                };
387
388                let (start, end_incl) = min_max2(a, b);
389
390                let Some(end_excl) = end_incl.checked_add(1) else {
391                    return None;
392                };
393                Some(Self::new_unchecked(start, end_excl))
394            }
395
396            #[inline]
397            pub const fn checked_minkowski_div_n(self, n: i16) -> Option<Self> {
398                if n == 0 {
399                    return None;
400                }
401                let Some(a) = self.start.checked_div(n) else {
402                    return None;
403                };
404                let Some(b) = self.end_incl().checked_div(n) else {
405                    return None;
406                };
407
408                let (start, end_incl) = min_max2(a, b);
409
410                let Some(end_excl) = end_incl.checked_add(1) else {
411                    return None;
412                };
413                Some(Self::new_unchecked(start, end_excl))
414            }
415        }
416    }
417
418    // ========================================================
419    // SATURATING
420    // ========================================================
421    pub mod saturating {
422        use super::*;
423
424        impl I16CO {
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 a = self.start.saturating_mul(other.start);
442                let b = self.start.saturating_mul(other.end_incl());
443                let c = self.end_incl().saturating_mul(other.start);
444                let d = self.end_incl().saturating_mul(other.end_incl());
445
446                let (start, end_incl) = min_max4(a, b, c, d);
447
448                let end_excl = end_incl.saturating_add(1);
449                Self::try_new(start, end_excl)
450            }
451
452            #[inline]
453            pub const fn saturating_minkowski_div(self, other: Self) -> Option<Self> {
454                if other.start <= 0 && other.end_incl() >= 0 {
455                    return None;
456                }
457
458                let a = self.start / other.start;
459                let b = self.start / other.end_incl();
460                let c = self.end_incl() / other.start;
461                let d = self.end_incl() / other.end_incl();
462
463                let (start, end_incl) = min_max4(a, b, c, d);
464
465                let end_excl = end_incl.saturating_add(1);
466                Self::try_new(start, end_excl)
467            }
468        }
469
470        impl I16CO {
471            #[inline]
472            pub const fn saturating_minkowski_add_n(self, n: i16) -> Option<Self> {
473                let start = self.start.saturating_add(n);
474                let end_excl = self.end_excl.saturating_add(n);
475                Self::try_new(start, end_excl)
476            }
477
478            #[inline]
479            pub const fn saturating_minkowski_sub_n(self, n: i16) -> Option<Self> {
480                let start = self.start.saturating_sub(n);
481                let end_excl = self.end_excl.saturating_sub(n);
482                Self::try_new(start, end_excl)
483            }
484
485            #[inline]
486            pub const fn saturating_minkowski_mul_n(self, n: i16) -> Option<Self> {
487                let a = self.start.saturating_mul(n);
488                let b = self.end_incl().saturating_mul(n);
489
490                let (start, end_incl) = min_max2(a, b);
491
492                let end_excl = end_incl.saturating_add(1);
493                Self::try_new(start, end_excl)
494            }
495
496            #[inline]
497            pub const fn saturating_minkowski_div_n(self, n: i16) -> Option<Self> {
498                if n == 0 {
499                    return None;
500                }
501
502                let a = self.start / n;
503                let b = self.end_incl() / n;
504
505                let (start, end_incl) = min_max2(a, b);
506
507                let end_excl = end_incl.saturating_add(1);
508                Self::try_new(start, end_excl)
509            }
510        }
511    }
512}