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