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