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