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