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