range_set_blaze/float/finite.rs
1//! Finite is a floating point type, suitable for use in ranges. Only finite values are valid.
2//!
3//! Ordering and other semantics are as per normal floating point comparisons.
4//!
5//! Enable with `float_experimental` (stable, `FiniteF32`/`FiniteF64`) and
6//! `float_nightly_experimental` (nightly, adds `FiniteF16`/`FiniteF128`).
7
8use core::{
9 cmp::Ordering,
10 fmt::Debug,
11 hash::{Hash, Hasher},
12 mem,
13 ops::RangeInclusive,
14 slice::from_raw_parts,
15};
16
17use super::finite_float::FiniteFloat;
18
19use crate::Integer;
20#[cfg(feature = "from_slice")]
21use crate::RangeSetBlaze;
22use num_traits::Zero;
23
24/// Total ordered f64, with `-0.0` normalized to `+0.0`, and excluding NaN and infinities.
25pub type FiniteF64 = Finite<f64>;
26/// Total ordered f32, with `-0.0` normalized to `+0.0`, and excluding NaN and infinities.
27pub type FiniteF32 = Finite<f32>;
28/// Total ordered f16, with `-0.0` normalized to `+0.0`, and excluding NaN and infinities.
29#[cfg(feature = "float_nightly_experimental")]
30pub type FiniteF16 = Finite<f16>;
31/// Total ordered f128, with `-0.0` normalized to `+0.0`, and excluding NaN and infinities.
32#[cfg(feature = "float_nightly_experimental")]
33pub type FiniteF128 = Finite<f128>;
34
35/// Construct a [`FiniteF64`] from an `f64`. Shorthand for [`FiniteF64::new`]
36#[must_use]
37pub const fn ff64(x: f64) -> FiniteF64 {
38 finite_f64(x)
39}
40
41/// Construct a [`FiniteF32`] from an `f32`. Shorthand for [`FiniteF32::new`]
42#[must_use]
43pub const fn ff32(x: f32) -> FiniteF32 {
44 finite_f32(x)
45}
46
47/// Construct a [`FiniteF16`] from an `f16`. Shorthand for [`FiniteF16::new`]
48#[cfg(feature = "float_nightly_experimental")]
49#[must_use]
50pub const fn ff16(x: f16) -> FiniteF16 {
51 finite_f16(x)
52}
53
54/// Construct a [`FiniteF128`] from an `f128`. Shorthand for [`FiniteF128::new`]
55#[cfg(feature = "float_nightly_experimental")]
56#[must_use]
57pub const fn ff128(x: f128) -> FiniteF128 {
58 finite_f128(x)
59}
60
61// TODO When const trait methods are stable, make the generic Finite constructors and other
62// eligible methods const, then have these shorthands call Finite::new directly. That will also
63// let their negative-zero normalization share `FiniteFloat::normalize` with runtime paths.
64macro_rules! finite_const_constructor {
65 ($name:ident, $primitive:ty, $finite:ty) => {
66 const fn $name(x: $primitive) -> $finite {
67 assert!(x.is_finite(), "Finite type requires a finite value");
68 let normalized = if x == 0.0 && x.is_sign_negative() {
69 0.0
70 } else {
71 x
72 };
73 Finite(normalized)
74 }
75 };
76}
77
78finite_const_constructor!(finite_f64, f64, FiniteF64);
79finite_const_constructor!(finite_f32, f32, FiniteF32);
80#[cfg(feature = "float_nightly_experimental")]
81finite_const_constructor!(finite_f16, f16, FiniteF16);
82#[cfg(feature = "float_nightly_experimental")]
83finite_const_constructor!(finite_f128, f128, FiniteF128);
84
85/// Experimental: A transparent wrapper around [`f64`] and friends with total ordering.
86///
87/// Comparison, equality, and hashing all agree with `total_cmp` after zero normalization.
88///
89/// # Basic Usage
90/// ```
91/// use range_set_blaze::{RangeSetBlaze, FiniteF64, FiniteF32};
92/// let set = RangeSetBlaze::from_iter([FiniteF64::new(3.0)..=FiniteF64::new(5.0)]);
93/// assert!(set.contains(FiniteF64::new(3.1)));
94/// assert!(!set.contains(FiniteF64::new(2.9)));
95///
96/// let set = RangeSetBlaze::from(FiniteF64::from_primitive_range(3.0..=5.0));
97/// assert!(set.contains(FiniteF64::new(4.9)));
98/// assert!(!set.contains(FiniteF64::new(5.1)));
99///
100/// let set = RangeSetBlaze::from_iter(FiniteF32::from_primitive_ranges([3.0..=5.0, 7.0..=9.0]));
101/// assert!(set.contains(FiniteF32::new(4.0)));
102/// assert!(!set.contains(FiniteF32::new(6.0)));
103/// ```
104///
105/// # Enabling
106///
107/// This type is experimental and must be enabled with the `float_experimental` feature.
108/// ```bash
109/// cargo add range-set-blaze --features "float_experimental"
110/// ```
111/// That provides the `FiniteF32` and `FiniteF64` types.
112///
113/// If you're building with nightly, you can instead use the `float_nightly_experimental` feature.
114/// ```bash
115/// cargo add range-set-blaze --features "float_nightly_experimental"
116/// ```
117/// To also use the `FiniteF16` and `FiniteF128` types.
118#[repr(transparent)]
119#[derive(Copy, Clone, Default, Debug)]
120pub struct Finite<T: FiniteFloat>(T);
121
122impl<T: FiniteFloat> Finite<T> {
123 /// The minimum value that can be represented by the type.\
124 /// Maps directly to `crate::Integer::min_value()`
125 ///
126 /// # Examples
127 /// ```
128 /// use range_set_blaze::FiniteF64;
129 ///
130 /// assert_eq!(FiniteF64::MIN, FiniteF64::new(f64::MIN));
131 /// ```
132 pub const MIN: Self = Self(T::MIN);
133
134 /// The maximum value that can be represented by the type.\
135 /// Maps directly to [`crate::Integer::max_value()`]
136 ///
137 /// # Examples
138 /// ```
139 /// use range_set_blaze::FiniteF64;
140 ///
141 /// assert_eq!(FiniteF64::MAX, FiniteF64::new(f64::MAX));
142 /// ```
143 pub const MAX: Self = Self(T::MAX);
144
145 /// The maximum possible size of a range, i.e. the size if `[MIN..=MAX]`
146 /// For `Finite` types, this is unusual because NaN and infinity values are excluded, and
147 /// `-0.0` and `+0.0` share one slot after normalization.
148 ///
149 /// # Examples
150 /// ```
151 /// use range_set_blaze::FiniteF32;
152 ///
153 /// assert_eq!(FiniteF32::MAX_SIZE, 0xFF00_0000_u32 - 1);
154 /// ```
155 pub const MAX_SIZE: T::SafeLen = T::MAX_SIZE;
156
157 /// Creates a new [`Finite`] from a primitive float.
158 /// Only finite values are legal
159 ///
160 /// # Examples
161 /// ```
162 /// use range_set_blaze::FiniteF64;
163 ///
164 /// let _ = FiniteF64::new(1.0);
165 /// ```
166 /// # Panics
167 ///
168 /// Panics if `x.is_finite()` returns false
169 #[must_use]
170 pub fn new(x: T) -> Self {
171 Self::try_new(x).expect("Finite type requires a finite value")
172 }
173
174 /// Creates a new [`Finite`] from a primitive float.
175 ///
176 /// Returns `None` if the float is not finite (NaN or infinity).
177 ///
178 /// # Examples
179 /// ```
180 /// use range_set_blaze::FiniteF64;
181 ///
182 /// assert_eq!(FiniteF64::try_new(1.0), Some(FiniteF64::new(1.0)));
183 /// assert_eq!(FiniteF64::try_new(f64::NAN), None);
184 /// ```
185 #[must_use]
186 pub fn try_new(x: T) -> Option<Self> {
187 // SAFETY: `T::is_finite` rules out NaN/infinity, and `T::normalize` canonicalizes -0.0.
188 T::is_finite(x).then(|| unsafe { Self::new_unchecked(T::normalize(x)) })
189 }
190
191 /// Creates a new [`Finite`] from a primitive float without validating it.
192 ///
193 /// This is the unchecked building block every validating constructor in this module
194 /// (`new`, `try_new`, `from_primitive_range`, `values`,
195 /// `from_primitive_slice`, ...) is defined in terms
196 /// of. Prefer those; only reach for this when you have already independently established
197 /// the safety precondition below and need to skip the redundant check.
198 ///
199 /// # Safety
200 ///
201 /// The caller must guarantee that:
202 /// - `x` is finite: not NaN, not `+/-infinity`.
203 /// - `x` is not `-0.0`: zero must already be canonicalized to `+0.0`.
204 ///
205 /// [`Finite`] has a public type invariant ("only finite values, with zero canonicalized to
206 /// `+0.0`, are legal"). Even though today's implementation would only produce incorrect
207 /// results (wrong `MAX_SIZE`, a duplicated zero slot, `after`/`before` landing somewhere
208 /// unexpected) rather than immediate undefined behavior if this precondition is violated,
209 /// safe code must never be able to construct a value that breaks it. This preserves the
210 /// option for this crate, and downstream code, to rely on the invariant in future
211 /// (potentially unsafe) abstractions without an audit of every safe caller.
212 #[must_use]
213 pub const unsafe fn new_unchecked(x: T) -> Self {
214 Self(x)
215 }
216
217 /// Computes `self + (b - 1)` where `b` is of type `SafeLen`.
218 ///
219 /// # Panics
220 /// Panics if `b` is not small enough that the result stays within range for `T`
221 /// (checked unconditionally, in both debug and release builds, so safe code can
222 /// never construct a `Finite` value that breaks its invariant this way).
223 #[must_use]
224 pub fn inclusive_end_from_start(self, b: T::SafeLen) -> Self {
225 let max_len = T::prim_safe_len(self.0, T::MAX);
226 assert!(
227 !b.is_zero() && b <= max_len,
228 "b must be in range 1..=max_len"
229 );
230 Self(T::inclusive_end_from_start(self.0, b))
231 }
232
233 /// Computes `self - (b - 1)` where `b` is of type `SafeLen`.
234 ///
235 /// # Panics
236 /// Panics if `b` is not small enough that the result stays within range for `T`
237 /// (checked unconditionally, in both debug and release builds, so safe code can
238 /// never construct a `Finite` value that breaks its invariant this way).
239 #[must_use]
240 pub fn start_from_inclusive_end(self, b: T::SafeLen) -> Self {
241 let max_len = T::prim_safe_len(T::MIN, self.0);
242 assert!(
243 !b.is_zero() && b <= max_len,
244 "b must be in range 1..=max_len"
245 );
246 Self(T::start_from_inclusive_end(self.0, b))
247 }
248
249 /// Returns the wrapped value.
250 ///
251 /// # Examples
252 /// ```
253 /// use range_set_blaze::FiniteF64;
254 ///
255 /// assert_eq!(FiniteF64::new(42.0).into_inner(), 42.0);
256 /// ```
257 #[must_use]
258 pub const fn into_inner(self) -> T {
259 self.0
260 }
261
262 /// Returns the next float, in total order.
263 ///
264 /// # Examples
265 /// ```
266 /// use range_set_blaze::FiniteF64;
267 ///
268 /// assert_eq!(FiniteF64::new(42.0).after().before().into_inner(), 42.0);
269 /// ```
270 ///
271 /// # Panics
272 ///
273 /// Panics if `self` is the maximum value (checked unconditionally, in both debug
274 /// and release builds, so safe code can never construct a `Finite` value that
275 /// breaks its invariant this way).
276 #[must_use]
277 pub fn after(self) -> Self {
278 assert!(self != Self::MAX, "after() called on maximum value");
279 Self(T::normalize(T::after(self.0)))
280 }
281
282 /// Returns the previous float, in total order.
283 ///
284 /// # Examples
285 /// ```
286 /// use range_set_blaze::FiniteF64;
287 ///
288 /// assert_eq!(FiniteF64::new(42.0).before().after().into_inner(), 42.0);
289 /// ```
290 ///
291 /// # Panics
292 ///
293 /// Panics if `self` is the minimum value (checked unconditionally, in both debug
294 /// and release builds, so safe code can never construct a `Finite` value that
295 /// breaks its invariant this way).
296 #[must_use]
297 pub fn before(self) -> Self {
298 assert!(self != Self::MIN, "before() called on minimum value");
299 Self(T::normalize(T::before(self.0)))
300 }
301
302 /// Returns the next float, in total order.
303 ///
304 /// Returns [`None`] if `self` is the maximum value.
305 ///
306 /// # Examples
307 /// ```
308 /// use range_set_blaze::FiniteF64;
309 ///
310 /// let value = FiniteF64::new(42.0);
311 /// assert_eq!(value.checked_after(), Some(value.after()));
312 /// let value = FiniteF64::MAX;
313 /// assert_eq!(value.checked_after(), None);
314 /// ```
315 #[must_use]
316 pub fn checked_after(self) -> Option<Self> {
317 if self == Self::MAX {
318 None
319 } else {
320 Some(self.after())
321 }
322 }
323
324 /// Returns the previous float, in total order.
325 ///
326 /// Returns [`None`] if `self` is the minimum value.
327 ///
328 /// # Examples
329 /// ```
330 /// use range_set_blaze::FiniteF64;
331 ///
332 /// let value = FiniteF64::new(42.0);
333 /// assert_eq!(value.checked_before(), Some(value.before()));
334 /// let value = FiniteF64::MIN;
335 /// assert_eq!(value.checked_before(), None);
336 /// ```
337 #[must_use]
338 pub fn checked_before(self) -> Option<Self> {
339 if self == Self::MIN {
340 None
341 } else {
342 Some(self.before())
343 }
344 }
345
346 /// Converts an inclusive primitive range into an inclusive [`Finite`] range.
347 ///
348 /// "Primitive" here means Rust's built-in float type (e.g. `f64`).
349 ///
350 ///
351 /// # Examples
352 /// ```
353 /// use range_set_blaze::{RangeSetBlaze, FiniteF64};
354 ///
355 /// let short = RangeSetBlaze::from(FiniteF64::from_primitive_range(3.0..=5.0));
356 /// let long = RangeSetBlaze::from(FiniteF64::new(3.0)..=FiniteF64::new(5.0));
357 /// assert_eq!(short, long);
358 /// ```
359 /// # Panics
360 ///
361 /// Panics if `start` or `end` is not finite.
362 #[must_use]
363 pub fn from_primitive_range(range: RangeInclusive<T>) -> RangeInclusive<Self> {
364 let (start, end) = range.into_inner();
365 Self::new(start)..=Self::new(end)
366 }
367
368 /// Converts inclusive primitive ranges into inclusive [`Finite`] ranges.
369 ///
370 /// "Primitive" here means Rust's built-in float type (e.g. `f64`).
371 ///
372 ///
373 /// # Examples
374 /// ```
375 /// use range_set_blaze::{RangeSetBlaze, FiniteF64};
376 ///
377 /// let short = RangeSetBlaze::from_iter(FiniteF64::from_primitive_ranges([1.0..=2.0, 3.0..=4.0]));
378 /// let long = RangeSetBlaze::from_iter([FiniteF64::new(1.0)..=FiniteF64::new(2.0), FiniteF64::new(3.0)..=FiniteF64::new(4.0)]);
379 /// assert_eq!(short, long);
380 /// ```
381 /// # Panics
382 ///
383 /// Panics when the returned iterator is consumed if any range endpoint is not finite.
384 pub fn from_primitive_ranges<I>(ranges: I) -> impl Iterator<Item = RangeInclusive<Self>>
385 where
386 I: IntoIterator<Item = RangeInclusive<T>>,
387 {
388 ranges.into_iter().map(Self::from_primitive_range)
389 }
390
391 /// Convenience method to convert primitive values into ordered [`Finite`] values.
392 /// # Examples
393 /// ```
394 /// use range_set_blaze::{RangeSetBlaze, FiniteF64};
395 ///
396 /// let short = RangeSetBlaze::from_iter(FiniteF64::values([1.0, 2.0, 3.0, 4.0]));
397 /// let long = RangeSetBlaze::from_iter([FiniteF64::new(1.0), FiniteF64::new(2.0), FiniteF64::new(3.0), FiniteF64::new(4.0)]);
398 /// assert_eq!(short, long);
399 /// ```
400 ///
401 /// # Panics
402 ///
403 /// Panics (when iterated) if any value is not finite.
404 pub fn values<I>(values: I) -> impl Iterator<Item = Self>
405 where
406 I: IntoIterator<Item = T>,
407 {
408 values.into_iter().map(Self::new)
409 }
410
411 /// Views primitive values as ordered [`Finite`] values, validating as it goes.
412 ///
413 /// "Primitive" here means Rust's built-in float type (e.g. `f64`).
414 ///
415 ///
416 /// This runs in `O(n)` (to validate every element) and does not allocate.
417 /// # Examples
418 /// ```
419 /// use range_set_blaze::{RangeSetBlaze, FiniteF64};
420 ///
421 /// let short = RangeSetBlaze::from_iter(FiniteF64::from_primitive_slice(&[1.0, 2.0, 3.0, 4.0]));
422 /// let long = RangeSetBlaze::from_iter([FiniteF64::new(1.0), FiniteF64::new(2.0), FiniteF64::new(3.0), FiniteF64::new(4.0)]);
423 /// assert_eq!(short, long);
424 /// ```
425 ///
426 /// # Panics
427 ///
428 /// Panics if any element is not finite, or is `-0.0` (which can't be normalized to `+0.0`
429 /// without copying — see [`Finite::from_primitive_slice_unchecked`] if you need a true
430 /// zero-copy view and can guarantee your data already satisfies [`Finite`]'s invariant).
431 #[must_use]
432 pub fn from_primitive_slice(values: &[T]) -> &[Self] {
433 assert!(
434 values
435 .iter()
436 .all(|&v| T::is_finite(v) && !T::is_neg_zero(v)),
437 "Finite type requires finite, non-negative-zero values"
438 );
439 // SAFETY: just validated every element is finite and not -0.0.
440 unsafe { Self::from_primitive_slice_unchecked(values) }
441 }
442
443 /// Views primitive values as ordered [`Finite`] values, without validating them.
444 ///
445 /// "Primitive" here means Rust's built-in float type (e.g. `f64`).
446 ///
447 ///
448 /// This runs in `O(1)` and does not allocate.
449 ///
450 /// # Safety
451 ///
452 /// The caller must guarantee that every element of `values` is finite (not NaN, not
453 /// `+/-infinity`) and not `-0.0` (zero must already be canonicalized to `+0.0`). Because
454 /// the returned slice is a live view over the same memory (not a copy), there is no
455 /// opportunity to normalize `-0.0` even if the caller wanted to; the data must already be
456 /// clean.
457 ///
458 /// [`Finite`] has a public type invariant that safe code must never be able to break, even
459 /// though violating it today would only produce incorrect results (see
460 /// [`Finite::new_unchecked`] for the full rationale).
461 #[must_use]
462 pub const unsafe fn from_primitive_slice_unchecked(values: &[T]) -> &[Self] {
463 // SAFETY: Finite is #[repr(transparent)] over T, making `&[T]`
464 // and `&[Finite]` entirely interchangeable in layout and lifetimes; the caller is
465 // responsible for the value-level invariant per the safety doc above.
466 unsafe { mem::transmute::<&[T], &[Self]>(values) }
467 }
468}
469
470/// Extension trait for viewing a slice of [`Finite`] values as primitive values.
471pub trait FiniteSliceExt<T: FiniteFloat> {
472 /// Views [`Finite`] values as primitive values.
473 ///
474 /// "Primitive" here means Rust's built-in float type (e.g. `f64`).
475 ///
476 ///
477 /// This runs in `O(1)` and does not allocate.
478 /// # Examples
479 /// ```
480 /// use range_set_blaze::FiniteF64;
481 /// use range_set_blaze::finite::FiniteSliceExt;
482 ///
483 /// let finites = [FiniteF64::new(1.0), FiniteF64::new(2.0), FiniteF64::new(3.0)];
484 /// assert_eq!(&[1.0, 2.0, 3.0], finites.as_primitive_slice());
485 /// ```
486 fn as_primitive_slice(&self) -> &[T];
487}
488
489impl<T: FiniteFloat> FiniteSliceExt<T> for [Finite<T>] {
490 fn as_primitive_slice(&self) -> &[T] {
491 // SAFETY: Finite<T> is #[repr(transparent)] over T, making `&[T]`
492 // and `&[Finite<T>]` entirely interchangeable in layout and lifetimes.
493 unsafe { from_raw_parts(self.as_ptr().cast::<T>(), self.len()) }
494 }
495}
496
497/// Extension trait for converting an inclusive [`Finite`] range into an inclusive primitive
498/// range (or a `(start, end)` primitive tuple).
499pub trait FiniteRangeExt<T: FiniteFloat> {
500 /// Converts an inclusive [`Finite`] range into an inclusive primitive range.
501 ///
502 /// "Primitive" here means Rust's built-in float type (e.g. `f64`).
503 ///
504 ///
505 /// This is the reverse of [`Finite::from_primitive_range`].
506 ///
507 /// # Examples
508 /// ```
509 /// use range_set_blaze::FiniteF64;
510 /// use range_set_blaze::finite::FiniteRangeExt;
511 ///
512 /// let range = FiniteF64::new(3.0)..=FiniteF64::new(5.0);
513 /// assert_eq!(range.into_primitive_range(), 3.0..=5.0);
514 /// ```
515 #[must_use]
516 fn into_primitive_range(self) -> RangeInclusive<T>;
517
518 /// Converts an inclusive [`Finite`] range into a `(start, end)` tuple of primitive values.
519 ///
520 /// "Primitive" here means Rust's built-in float type (e.g. `f64`).
521 ///
522 ///
523 /// Mirrors [`RangeInclusive::into_inner`] from the standard library, which unwraps a
524 /// range into its `(start, end)` tuple; this additionally converts each endpoint to its
525 /// primitive type.
526 ///
527 /// # Examples
528 /// ```
529 /// use range_set_blaze::FiniteF64;
530 /// use range_set_blaze::finite::FiniteRangeExt;
531 ///
532 /// let range = FiniteF64::new(3.0)..=FiniteF64::new(5.0);
533 /// assert_eq!(range.into_primitive_inner(), (3.0, 5.0));
534 /// ```
535 #[must_use]
536 fn into_primitive_inner(self) -> (T, T);
537}
538
539impl<T: FiniteFloat> FiniteRangeExt<T> for RangeInclusive<Finite<T>> {
540 fn into_primitive_range(self) -> RangeInclusive<T> {
541 let (start, end) = self.into_primitive_inner();
542 start..=end
543 }
544
545 fn into_primitive_inner(self) -> (T, T) {
546 let (start, end) = self.into_inner();
547 (start.into_inner(), end.into_inner())
548 }
549}
550
551impl<T: FiniteFloat> PartialEq for Finite<T> {
552 fn eq(&self, other: &Self) -> bool {
553 T::total_cmp(self.0, other.0) == Ordering::Equal
554 }
555}
556
557impl<T: FiniteFloat> Eq for Finite<T> {}
558
559impl<T: FiniteFloat> PartialOrd for Finite<T> {
560 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
561 Some(self.cmp(other))
562 }
563}
564
565impl<T: FiniteFloat> Ord for Finite<T> {
566 fn cmp(&self, other: &Self) -> Ordering {
567 T::total_cmp(self.0, other.0)
568 }
569}
570
571impl<T: FiniteFloat> Hash for Finite<T> {
572 fn hash<H: Hasher>(&self, state: &mut H) {
573 T::hash(self.0, state);
574 }
575}
576
577impl<T: FiniteFloat> Integer for Finite<T> {
578 type SafeLen = T::SafeLen;
579
580 #[inline]
581 fn checked_add_one(self) -> Option<Self> {
582 self.checked_after()
583 }
584
585 // This moves to the next representable float in total_cmp order, not a numeric + 1.0.
586 #[inline]
587 fn add_one(self) -> Self {
588 self.after()
589 }
590
591 #[inline]
592 // This moves to the previous representable float in total_cmp order, not a numeric - 1.0.
593 fn sub_one(self) -> Self {
594 self.before()
595 }
596
597 #[inline]
598 fn assign_sub_one(&mut self) {
599 *self = self.before();
600 }
601
602 // Ideally, we would `impl std::iter::Step for FiniteF64` and just call Range::next(), but that's still experimental.
603 #[inline]
604 fn range_next(range: &mut RangeInclusive<Self>) -> Option<Self> {
605 if range.is_empty() {
606 None
607 } else if range.start() == range.end() && *range.start() == Self::MAX {
608 // Preserve the exhausted range sentinel without calling `after()` on MAX.
609 let next = *range.start();
610 *range = next..=range.end().before();
611 Some(next)
612 } else {
613 let next = *range.start();
614 *range = (next.after())..=*range.end();
615 Some(next)
616 }
617 }
618
619 #[inline]
620 fn range_next_back(range: &mut RangeInclusive<Self>) -> Option<Self> {
621 if range.is_empty() {
622 None
623 } else if range.start() == range.end() && *range.start() == Self::MIN {
624 // Preserve the exhausted range sentinel without calling `before()` on MIN.
625 let last = *range.end();
626 *range = last.after()..=last;
627 Some(last)
628 } else {
629 let last = *range.end();
630 *range = *range.start()..=last.before();
631 Some(last)
632 }
633 }
634
635 #[inline]
636 fn min_value() -> Self {
637 Self::MIN
638 }
639
640 #[inline]
641 fn max_value() -> Self {
642 Self::MAX
643 }
644
645 #[cfg(feature = "from_slice")]
646 #[inline]
647 fn from_slice(slice: impl AsRef<[Self]>) -> RangeSetBlaze<Self> {
648 // TODO Investigate applying the ordered float transform in SIMD chunks here.
649 // no way to do the fancy thing
650 RangeSetBlaze::from_iter(slice.as_ref())
651 }
652
653 fn safe_len(r: &RangeInclusive<Self>) -> Self::SafeLen {
654 let (start, end) = r.clone().into_primitive_inner();
655 T::prim_safe_len(start, end)
656 }
657
658 fn safe_len_to_f64_lossy(len: Self::SafeLen) -> f64 {
659 T::safe_len_to_f64_lossy(len)
660 }
661
662 fn f64_to_safe_len_lossy(f: f64) -> Self::SafeLen {
663 T::f64_to_safe_len_lossy(f)
664 }
665
666 fn inclusive_end_from_start(self, b: Self::SafeLen) -> Self {
667 self.inclusive_end_from_start(b)
668 }
669
670 fn start_from_inclusive_end(self, b: Self::SafeLen) -> Self {
671 self.start_from_inclusive_end(b)
672 }
673}
674
675#[cfg(test)]
676mod tests {
677 use super::*;
678 use crate::Integer;
679 #[cfg(not(target_arch = "wasm32"))]
680 use std::hint::black_box;
681 #[cfg(not(target_arch = "wasm32"))]
682 use std::panic::{AssertUnwindSafe, catch_unwind};
683 use std::vec;
684 use std::vec::Vec;
685
686 #[cfg(not(target_arch = "wasm32"))]
687 fn panics(f: impl FnOnce()) -> bool {
688 catch_unwind(AssertUnwindSafe(f)).is_err()
689 }
690
691 // WASM targets currently abort instead of unwinding, so `catch_unwind`
692 // cannot observe the expected constructor panics there.
693 #[cfg(not(target_arch = "wasm32"))]
694 #[test]
695 fn safe_constructors_preserve_finite_invariant() {
696 assert_eq!(ff32(-0.0).into_inner().to_bits(), 0);
697 assert_eq!(ff64(-0.0).into_inner().to_bits(), 0);
698 assert_eq!(FiniteF64::new(-0.0), ff64(0.0));
699 assert_eq!(FiniteF64::try_new(-0.0), Some(ff64(0.0)));
700
701 for invalid in [f64::NAN, f64::INFINITY, f64::NEG_INFINITY] {
702 assert!(panics(|| {
703 black_box(FiniteF64::new(invalid));
704 }));
705 assert_eq!(FiniteF64::try_new(invalid), None);
706 assert!(panics(|| drop(FiniteF64::from_primitive_range(
707 invalid..=1.0
708 ))));
709 assert!(panics(|| {
710 FiniteF64::values([invalid]).count();
711 }));
712 assert!(panics(|| {
713 black_box(FiniteF64::from_primitive_slice(&[invalid]));
714 }));
715 }
716
717 assert!(panics(|| {
718 black_box(FiniteF64::from_primitive_slice(&[-0.0]));
719 }));
720 assert!(panics(|| {
721 black_box(FiniteF64::from_primitive_slice(&[f64::INFINITY]));
722 }));
723 assert!(panics(|| {
724 black_box(FiniteF64::from_primitive_slice(&[f64::NAN]));
725 }));
726
727 let values = [1.0, 2.0, 3.0];
728 let finites = FiniteF64::from_primitive_slice(&values);
729 assert_eq!(finites.as_primitive_slice(), &values);
730 assert_eq!(
731 FiniteF64::values(values).collect::<Vec<_>>(),
732 vec![ff64(1.0), ff64(2.0), ff64(3.0)]
733 );
734 assert_eq!(
735 FiniteF64::from_primitive_ranges([1.0..=2.0]).collect::<Vec<_>>(),
736 vec![ff64(1.0)..=ff64(2.0)]
737 );
738 }
739
740 #[test]
741 fn ordering_agrees_with_total_cmp() {
742 let values = [-f64::MAX, -1.0, 0.0, 1.0, f64::MAX];
743
744 for left in values {
745 for right in values {
746 assert_eq!(ff64(left).cmp(&ff64(right)), left.total_cmp(&right));
747 }
748 }
749 assert_ne!(ff64(0.0).cmp(&ff64(-0.0)), 0.0_f64.total_cmp(&-0.0));
750 }
751
752 #[test]
753 fn converts_ranges() {
754 assert_eq!(
755 FiniteF64::from_primitive_range(10.0..=20.0),
756 ff64(10.0)..=ff64(20.0)
757 );
758 assert_eq!(
759 FiniteF64::from_primitive_ranges([10.0..=20.0, 30.0..=40.0]).collect::<Vec<_>>(),
760 vec![ff64(10.0)..=ff64(20.0), ff64(30.0)..=ff64(40.0)]
761 );
762 }
763
764 #[test]
765 fn after_and_before_step_through_zero_in_total_order() {
766 assert_eq!(ff64(-0.0), ff64(0.0));
767 assert_ne!(ff64(0.0).before(), ff64(-0.0));
768 assert_eq!(ff64(0.0).after(), ff64(f64::from_bits(1)));
769 assert_eq!(
770 ff64(0.0).before(),
771 ff64(f64::from_bits(0x8000_0000_0000_0001))
772 );
773 }
774
775 #[test]
776 fn after_and_before_panic_at_boundaries_in_all_build_modes() {
777 assert_eq!(FiniteF64::MAX.checked_after(), None);
778 assert_eq!(FiniteF64::MIN.checked_before(), None);
779 }
780
781 #[test]
782 #[should_panic(expected = "b must be in range 1..=max_len")]
783 fn finite_endpoint_offset_cannot_leave_domain() {
784 let _ = FiniteF32::MAX.inclusive_end_from_start(2);
785 }
786
787 #[test]
788 #[should_panic(expected = "after() called on maximum value")]
789 fn after_panics_at_max() {
790 let _ = FiniteF64::MAX.after();
791 }
792
793 #[test]
794 #[should_panic(expected = "before() called on minimum value")]
795 fn before_panics_at_min() {
796 let _ = FiniteF64::MIN.before();
797 }
798
799 #[test]
800 fn checked_after_and_before_stop_at_total_order_boundaries() {
801 assert_eq!(FiniteF64::MIN.checked_before(), None);
802 assert_eq!(FiniteF64::MAX.checked_after(), None);
803 assert_eq!(FiniteF64::MIN.checked_after(), Some(FiniteF64::MIN.after()));
804 assert_eq!(
805 FiniteF64::MAX.checked_before(),
806 Some(FiniteF64::MAX.before())
807 );
808 }
809
810 #[test]
811 fn min_and_max_are_total_order_boundaries() {
812 let values = [
813 ff64(-f64::MAX),
814 ff64(-1.0),
815 ff64(-0.0),
816 ff64(0.0),
817 ff64(1.0),
818 ff64(f64::MAX),
819 ];
820
821 for value in values {
822 assert!(FiniteF64::MIN <= value);
823 assert!(value <= FiniteF64::MAX);
824 }
825 }
826
827 #[test]
828 fn after_and_before_are_neighbors_in_total_order() {
829 let values = [
830 ff64(f64::MIN),
831 ff64(-f64::MAX),
832 ff64(-1.0),
833 ff64(-0.0),
834 ff64(0.0),
835 ff64(1.0),
836 ff64(f64::MAX),
837 ];
838
839 for value in values {
840 if value != ff64(f64::MAX) {
841 assert_eq!(value.after().before(), value);
842 }
843 if value != ff64(f64::MIN) {
844 assert_eq!(value.before().after(), value);
845 }
846 }
847 }
848
849 #[test]
850 fn adjacency_laws_cover_f32_and_f64_edges() {
851 macro_rules! check {
852 ($name:ident, $zero:expr, $negative_subnormal:expr, $positive_subnormal:expr, $min:expr, $max:expr) => {{
853 let values = [
854 ff32($zero),
855 ff32($negative_subnormal),
856 ff32($positive_subnormal),
857 ff32(-1.0),
858 ff32(1.0),
859 ff32($min),
860 ff32($max),
861 ];
862 for value in values {
863 if value != FiniteF32::MAX {
864 assert_eq!(value.after().before(), value);
865 }
866 if value != FiniteF32::MIN {
867 assert_eq!(value.before().after(), value);
868 }
869 }
870 assert_eq!(FiniteF32::MIN.checked_before(), None);
871 assert_eq!(FiniteF32::MAX.checked_after(), None);
872 assert_eq!(ff32($negative_subnormal).after(), ff32($zero));
873 assert_eq!(ff32($zero).after(), ff32($positive_subnormal));
874 let _ = stringify!($name);
875 }};
876 }
877
878 check!(
879 f32_edges,
880 0.0_f32,
881 -f32::from_bits(1),
882 f32::from_bits(1),
883 f32::MIN,
884 f32::MAX
885 );
886
887 let values = [
888 ff64(-f64::from_bits(1)),
889 ff64(0.0),
890 ff64(f64::from_bits(1)),
891 ff64(-1.0),
892 ff64(1.0),
893 FiniteF64::MIN,
894 FiniteF64::MAX,
895 ];
896 for value in values {
897 if value != FiniteF64::MAX {
898 assert_eq!(value.after().before(), value);
899 }
900 if value != FiniteF64::MIN {
901 assert_eq!(value.before().after(), value);
902 }
903 }
904 assert_eq!(FiniteF64::MIN.checked_before(), None);
905 assert_eq!(FiniteF64::MAX.checked_after(), None);
906 assert_eq!(ff64(-f64::from_bits(1)).after(), ff64(0.0));
907 assert_eq!(ff64(0.0).after(), ff64(f64::from_bits(1)));
908 }
909
910 #[test]
911 fn range_length_laws_cover_f32_and_f64() {
912 let start = ff32(-f32::from_bits(1));
913 let end = ff32(f32::from_bits(1));
914 assert_eq!(FiniteF32::safe_len(&(start..=start)), 1);
915 assert_eq!(FiniteF32::safe_len(&(start..=start.after())), 2);
916 assert_eq!(FiniteF32::safe_len(&(start..=end)), 3);
917 assert_eq!(
918 FiniteF32::MAX_SIZE,
919 FiniteF32::safe_len(&(FiniteF32::MIN..=FiniteF32::MAX))
920 );
921 let length = 17;
922 let endpoint = start.inclusive_end_from_start(length);
923 assert_eq!(endpoint.start_from_inclusive_end(length), start);
924 assert_eq!(start.inclusive_end_from_start(length), endpoint);
925
926 let start = ff64(-f64::from_bits(1));
927 let end = ff64(f64::from_bits(1));
928 assert_eq!(FiniteF64::safe_len(&(start..=start)), 1);
929 assert_eq!(FiniteF64::safe_len(&(start..=start.after())), 2);
930 assert_eq!(FiniteF64::safe_len(&(start..=end)), 3);
931 assert_eq!(
932 FiniteF64::MAX_SIZE,
933 FiniteF64::safe_len(&(FiniteF64::MIN..=FiniteF64::MAX))
934 );
935 let length = 17;
936 let endpoint = start.inclusive_end_from_start(length);
937 assert_eq!(endpoint.start_from_inclusive_end(length), start);
938 assert_eq!(start.inclusive_end_from_start(length), endpoint);
939 }
940
941 #[cfg(feature = "float_nightly_experimental")]
942 #[test]
943 fn f16_finite_adjacency_and_lengths_are_exhaustive() {
944 for bits in 0..=u16::MAX {
945 let value = f16::from_bits(bits);
946 let Some(value) = FiniteF16::try_new(value) else {
947 continue;
948 };
949 if value != FiniteF16::MIN {
950 assert_eq!(value.before().after(), value);
951 }
952 if value != FiniteF16::MAX {
953 assert_eq!(value.after().before(), value);
954 }
955 assert_eq!(FiniteF16::safe_len(&(value..=value)), 1);
956 }
957 assert_eq!(
958 FiniteF16::MAX_SIZE,
959 FiniteF16::safe_len(&(FiniteF16::MIN..=FiniteF16::MAX))
960 );
961 }
962}