1use super::total_float::TotalFloat;
25use crate::Integer;
26#[cfg(feature = "from_slice")]
27use crate::RangeSetBlaze;
28use core::{
29 cmp::Ordering,
30 fmt::Debug,
31 hash::{Hash, Hasher},
32 mem,
33 ops::RangeInclusive,
34 slice::from_raw_parts,
35};
36pub type TotalF64 = Total<f64>;
38pub type TotalF32 = Total<f32>;
40#[cfg(feature = "float_nightly_experimental")]
42pub type TotalF16 = Total<f16>;
43#[cfg(feature = "float_nightly_experimental")]
45pub type TotalF128 = Total<f128>;
46
47#[must_use]
49pub const fn tf64(x: f64) -> TotalF64 {
50 TotalF64::new(x)
51}
52
53#[must_use]
55pub const fn tf32(x: f32) -> TotalF32 {
56 TotalF32::new(x)
57}
58
59#[cfg(feature = "float_nightly_experimental")]
61#[must_use]
62pub const fn tf16(x: f16) -> TotalF16 {
63 TotalF16::new(x)
64}
65
66#[cfg(feature = "float_nightly_experimental")]
68#[must_use]
69pub const fn tf128(x: f128) -> TotalF128 {
70 TotalF128::new(x)
71}
72
73#[repr(transparent)]
81#[derive(Copy, Clone, Default, Debug)]
82pub struct Total<T: TotalFloat>(T);
83
84impl<T: TotalFloat> Total<T> {
85 pub const MIN: Self = Self(T::MIN);
96
97 pub const MAX: Self = Self(T::MAX);
108
109 pub const MAX_SIZE: T::SafeLen = T::MAX_SIZE;
118
119 #[must_use]
129 pub const fn new(x: T) -> Self {
130 Self(x)
131 }
132
133 #[must_use]
141 pub fn inclusive_end_from_start(self, b: T::SafeLen) -> Self {
142 Self(T::inclusive_end_from_start(self.0, b))
143 }
144
145 #[must_use]
153 pub fn start_from_inclusive_end(self, b: T::SafeLen) -> Self {
154 Self(T::start_from_inclusive_end(self.0, b))
155 }
156
157 #[must_use]
166 pub const fn into_inner(self) -> T {
167 self.0
168 }
169
170 #[must_use]
184 pub fn after(self) -> Self {
185 debug_assert!(self != Self::MAX, "after() called on maximum value");
186 Self(T::after(self.0))
187 }
188
189 #[must_use]
203 pub fn before(self) -> Self {
204 debug_assert!(self != Self::MIN, "before() called on minimum value");
205 Self(T::before(self.0))
206 }
207
208 #[must_use]
222 pub fn checked_after(self) -> Option<Self> {
223 if self == Self::MAX {
224 None
225 } else {
226 Some(self.after())
227 }
228 }
229
230 #[must_use]
244 pub fn checked_before(self) -> Option<Self> {
245 if self == Self::MIN {
246 None
247 } else {
248 Some(self.before())
249 }
250 }
251
252 #[must_use]
265 pub fn from_primitive_range(range: RangeInclusive<T>) -> RangeInclusive<Self> {
266 let (start, end) = range.into_inner();
267 Self(start)..=Self(end)
268 }
269
270 pub fn from_primitive_ranges<I>(ranges: I) -> impl Iterator<Item = RangeInclusive<Self>>
283 where
284 I: IntoIterator<Item = RangeInclusive<T>>,
285 {
286 ranges.into_iter().map(Self::from_primitive_range)
287 }
288
289 pub fn values<I>(values: I) -> impl Iterator<Item = Self>
299 where
300 I: IntoIterator<Item = T>,
301 {
302 values.into_iter().map(Self)
303 }
304
305 #[must_use]
319 pub const fn from_primitive_slice(values: &[T]) -> &[Self] {
320 unsafe { mem::transmute::<&[T], &[Self]>(values) }
323 }
324}
325
326pub trait TotalSliceExt<T: TotalFloat> {
328 fn as_primitive_slice(&self) -> &[T];
342}
343
344impl<T: TotalFloat> TotalSliceExt<T> for [Total<T>] {
345 fn as_primitive_slice(&self) -> &[T] {
346 unsafe { from_raw_parts(self.as_ptr().cast::<T>(), self.len()) }
349 }
350}
351
352pub trait TotalRangeExt<T: TotalFloat> {
355 #[must_use]
370 fn into_primitive_range(self) -> RangeInclusive<T>;
371
372 #[must_use]
389 fn into_primitive_inner(self) -> (T, T);
390}
391
392impl<T: TotalFloat> TotalRangeExt<T> for RangeInclusive<Total<T>> {
393 fn into_primitive_range(self) -> RangeInclusive<T> {
394 let (start, end) = self.into_primitive_inner();
395 start..=end
396 }
397
398 fn into_primitive_inner(self) -> (T, T) {
399 let (start, end) = self.into_inner();
400 (start.into_inner(), end.into_inner())
401 }
402}
403
404impl<T: TotalFloat> PartialEq for Total<T> {
405 fn eq(&self, other: &Self) -> bool {
406 T::total_cmp(self.0, other.0) == Ordering::Equal
407 }
408}
409
410impl<T: TotalFloat> Eq for Total<T> {}
411
412impl<T: TotalFloat> PartialOrd for Total<T> {
413 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
414 Some(self.cmp(other))
415 }
416}
417
418impl<T: TotalFloat> Ord for Total<T> {
419 fn cmp(&self, other: &Self) -> Ordering {
420 T::total_cmp(self.0, other.0)
421 }
422}
423
424impl<T: TotalFloat> Hash for Total<T> {
425 fn hash<H: Hasher>(&self, state: &mut H) {
426 T::hash(self.0, state);
427 }
428}
429
430impl<T: TotalFloat> Integer for Total<T> {
431 type SafeLen = T::SafeLen;
432
433 #[inline]
434 fn checked_add_one(self) -> Option<Self> {
435 self.checked_after()
436 }
437
438 #[inline]
440 fn add_one(self) -> Self {
441 self.after()
442 }
443
444 #[inline]
445 fn sub_one(self) -> Self {
447 self.before()
448 }
449
450 #[inline]
451 fn assign_sub_one(&mut self) {
452 *self = self.before();
453 }
454
455 #[inline]
457 fn range_next(range: &mut RangeInclusive<Self>) -> Option<Self> {
458 if range.is_empty() {
459 None
460 } else if range.start() == range.end() && *range.start() == Self::MAX {
461 let next = *range.start();
463 *range = next..=range.end().before();
464 Some(next)
465 } else {
466 let next = *range.start();
467 *range = (next.after())..=*range.end();
468 Some(next)
469 }
470 }
471
472 #[inline]
473 fn range_next_back(range: &mut RangeInclusive<Self>) -> Option<Self> {
474 if range.is_empty() {
475 None
476 } else if range.start() == range.end() && *range.start() == Self::MIN {
477 let last = *range.end();
479 *range = last.after()..=last;
480 Some(last)
481 } else {
482 let last = *range.end();
483 *range = *range.start()..=last.before();
484 Some(last)
485 }
486 }
487
488 #[inline]
489 fn min_value() -> Self {
490 Self::MIN
491 }
492
493 #[inline]
494 fn max_value() -> Self {
495 Self::MAX
496 }
497
498 #[cfg(feature = "from_slice")]
499 #[inline]
500 fn from_slice(slice: impl AsRef<[Self]>) -> RangeSetBlaze<Self> {
501 RangeSetBlaze::from_iter(slice.as_ref())
504 }
505
506 fn safe_len(r: &RangeInclusive<Self>) -> Self::SafeLen {
507 let (start, end) = r.clone().into_primitive_inner();
508 T::prim_safe_len(start, end)
509 }
510
511 fn safe_len_to_f64_lossy(len: Self::SafeLen) -> f64 {
512 T::safe_len_to_f64_lossy(len)
513 }
514
515 fn f64_to_safe_len_lossy(f: f64) -> Self::SafeLen {
516 T::f64_to_safe_len_lossy(f)
517 }
518
519 fn inclusive_end_from_start(self, b: Self::SafeLen) -> Self {
520 self.inclusive_end_from_start(b)
521 }
522
523 fn start_from_inclusive_end(self, b: Self::SafeLen) -> Self {
524 self.start_from_inclusive_end(b)
525 }
526}
527
528#[cfg(test)]
529mod tests {
530 use super::*;
531 use crate::Integer;
532 use crate::float::total_float::{
533 from_ordered_32, from_ordered_64, to_ordered_32, to_ordered_64,
534 };
535 use std::collections::hash_map::DefaultHasher;
536 use std::vec;
537 use std::vec::Vec;
538
539 #[test]
540 fn ordering_agrees_with_total_cmp() {
541 let values = [
542 f64::NEG_INFINITY,
543 -f64::MAX,
544 -1.0,
545 -0.0,
546 0.0,
547 1.0,
548 f64::MAX,
549 f64::INFINITY,
550 f64::NAN,
551 f64::from_bits(0x7ff8_0000_0000_0001),
552 f64::from_bits(0xfff8_0000_0000_0001),
553 ];
554
555 for left in values {
556 for right in values {
557 assert_eq!(tf64(left).cmp(&tf64(right)), left.total_cmp(&right));
558 }
559 }
560 }
561
562 #[test]
563 fn equality_agrees_with_total_cmp() {
564 assert_ne!(tf64(-0.0), tf64(0.0));
565 assert_eq!(tf64(f64::NAN), tf64(f64::NAN));
566 }
567
568 #[test]
569 fn equal_values_hash_equally() {
570 let left = hash(tf64(f64::NAN));
571 let right = hash(tf64(f64::NAN));
572
573 assert_eq!(left, right);
574 }
575
576 #[test]
577 fn converts_ranges() {
578 assert_eq!(
579 TotalF64::from_primitive_range(10.0..=20.0),
580 tf64(10.0)..=tf64(20.0)
581 );
582 assert_eq!(
583 TotalF64::from_primitive_ranges([10.0..=20.0, 30.0..=40.0]).collect::<Vec<_>>(),
584 vec![tf64(10.0)..=tf64(20.0), tf64(30.0)..=tf64(40.0)]
585 );
586 }
587
588 #[test]
589 fn after_and_before_step_through_zero_in_total_order() {
590 assert_eq!(tf64(-0.0).after(), tf64(0.0));
591 assert_eq!(tf64(0.0).before(), tf64(-0.0));
592 assert_eq!(tf64(0.0).after(), tf64(f64::from_bits(1)));
593 assert_eq!(
594 tf64(-0.0).before(),
595 tf64(f64::from_bits(0x8000_0000_0000_0001))
596 );
597 }
598
599 #[test]
600 fn checked_after_and_before_are_not_wrapping() {
601 assert_eq!(TotalF64::MAX.checked_after(), None);
602 assert_eq!(TotalF64::MIN.checked_before(), None);
603 }
604
605 #[test]
606 #[cfg(debug_assertions)]
607 #[should_panic(expected = "after() called on maximum value")]
608 fn total_after_panics_at_max_in_debug() {
609 let _ = TotalF64::MAX.after();
610 }
611
612 #[test]
613 #[cfg(not(debug_assertions))]
614 fn total_after_wraps_at_max_in_release() {
615 assert_eq!(TotalF64::MAX.after(), TotalF64::MIN);
616 }
617
618 #[test]
619 #[cfg(debug_assertions)]
620 #[should_panic(expected = "before() called on minimum value")]
621 fn total_before_panics_at_min_in_debug() {
622 let _ = TotalF64::MIN.before();
623 }
624
625 #[test]
626 #[cfg(not(debug_assertions))]
627 fn total_before_wraps_at_min_in_release() {
628 assert_eq!(TotalF64::MIN.before(), TotalF64::MAX);
629 }
630
631 #[test]
632 fn stable_ordered_round_trips() {
633 let edge_f64 = [
634 0,
635 1,
636 u64::MAX,
637 0x7ff0_0000_0000_0000,
638 0xfff0_0000_0000_0000,
639 0x7ff8_0000_0000_0001,
640 0xfff8_0000_0000_0001,
641 ];
642 for bits in edge_f64 {
643 let value = f64::from_bits(bits);
644 assert_eq!(from_ordered_64(to_ordered_64(value)).to_bits(), bits);
645 }
646
647 let edge_f32 = [
648 0,
649 1,
650 u32::MAX,
651 0x7f80_0000,
652 0xff80_0000,
653 0x7fc0_0001,
654 0xffc0_0001,
655 ];
656 for bits in edge_f32 {
657 let value = f32::from_bits(bits);
658 assert_eq!(from_ordered_32(to_ordered_32(value)).to_bits(), bits);
659 }
660
661 let mut state = 0x9e37_79b9_u64;
662 for _ in 0..10_000 {
663 state = state
664 .wrapping_mul(6_364_136_223_846_793_005)
665 .wrapping_add(1);
666 let value = f64::from_bits(state);
667 assert_eq!(from_ordered_64(to_ordered_64(value)).to_bits(), state);
668 let bytes = state.to_le_bytes();
669 let bits = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
670 let value = f32::from_bits(bits);
671 assert_eq!(from_ordered_32(to_ordered_32(value)).to_bits(), bits);
672 }
673 }
674
675 #[test]
676 fn after_and_before_step_around_infinities() {
677 assert_eq!(tf64(f64::MAX).after(), tf64(f64::INFINITY));
678 assert_eq!(tf64(f64::INFINITY).before(), tf64(f64::MAX));
679 assert_eq!(tf64(f64::NEG_INFINITY).after(), tf64(-f64::MAX));
680 assert_eq!(tf64(-f64::MAX).before(), tf64(f64::NEG_INFINITY));
681 }
682
683 #[test]
684 fn checked_after_and_before_stop_at_total_order_boundaries() {
685 assert_eq!(TotalF64::MIN.checked_before(), None);
686 assert_eq!(TotalF64::MAX.checked_after(), None);
687 assert_eq!(TotalF64::MIN.checked_after(), Some(TotalF64::MIN.after()));
688 assert_eq!(TotalF64::MAX.checked_before(), Some(TotalF64::MAX.before()));
689 }
690
691 #[test]
692 fn min_and_max_are_total_order_boundaries() {
693 let values = [
694 tf64(f64::NEG_INFINITY),
695 tf64(-f64::MAX),
696 tf64(-1.0),
697 tf64(-0.0),
698 tf64(0.0),
699 tf64(1.0),
700 tf64(f64::MAX),
701 tf64(f64::INFINITY),
702 tf64(f64::NAN),
703 tf64(f64::from_bits(0x7ff8_0000_0000_0001)),
704 tf64(f64::from_bits(0xfff8_0000_0000_0001)),
705 ];
706
707 for value in values {
708 assert!(TotalF64::MIN <= value);
709 assert!(value <= TotalF64::MAX);
710 }
711 }
712
713 #[test]
714 fn after_and_before_are_neighbors_in_total_order() {
715 let values = [
716 tf64(f64::NEG_INFINITY),
717 tf64(-f64::MAX),
718 tf64(-1.0),
719 tf64(-0.0),
720 tf64(0.0),
721 tf64(1.0),
722 tf64(f64::MAX),
723 tf64(f64::INFINITY),
724 tf64(f64::NAN),
725 tf64(f64::from_bits(0x7ff8_0000_0000_0001)),
726 tf64(f64::from_bits(0xfff8_0000_0000_0001)),
727 ];
728
729 for value in values {
730 assert_eq!(value.after().before(), value);
731 assert_eq!(value.before().after(), value);
732 }
733 }
734
735 #[test]
736 fn adjacency_laws_cover_f32_and_f64_edges() {
737 macro_rules! check {
738 ($wrapper:ident, $constructor:ident, $zero:expr, $negative_subnormal:expr, $positive_subnormal:expr, $min:expr, $max:expr) => {
739 let values = [
740 $constructor($zero),
741 $constructor($negative_subnormal),
742 $constructor($positive_subnormal),
743 $constructor(-1.0),
744 $constructor(1.0),
745 $constructor($min),
746 $constructor($max),
747 $constructor(f32::INFINITY),
748 $constructor(f32::NAN),
749 ];
750 for value in values {
751 assert_eq!(value.after().before(), value);
752 assert_eq!(value.before().after(), value);
753 }
754 assert_eq!($wrapper::MIN.checked_before(), None);
755 assert_eq!($wrapper::MAX.checked_after(), None);
756 };
757 }
758 check!(
759 TotalF32,
760 tf32,
761 0.0_f32,
762 -f32::from_bits(1),
763 f32::from_bits(1),
764 f32::MIN,
765 f32::MAX
766 );
767
768 let values = [
769 tf64(-0.0),
770 tf64(0.0),
771 tf64(-f64::from_bits(1)),
772 tf64(f64::from_bits(1)),
773 tf64(-f64::MAX),
774 tf64(f64::MAX),
775 tf64(f64::NEG_INFINITY),
776 tf64(f64::INFINITY),
777 tf64(f64::from_bits(0x7ff8_0000_0000_0001)),
778 ];
779 for value in values {
780 assert_eq!(value.after().before(), value);
781 assert_eq!(value.before().after(), value);
782 }
783 assert_eq!(TotalF64::MIN.checked_before(), None);
784 assert_eq!(TotalF64::MAX.checked_after(), None);
785 }
786
787 #[test]
788 fn range_length_laws_cover_f32_and_f64() {
789 let start = tf32(-f32::from_bits(1));
790 assert_eq!(TotalF32::safe_len(&(start..=start)), 1);
791 assert_eq!(TotalF32::safe_len(&(start..=start.after())), 2);
792 assert_eq!(
793 TotalF32::MAX_SIZE,
794 TotalF32::safe_len(&(TotalF32::MIN..=TotalF32::MAX))
795 );
796 let length = 17;
797 let end = start.inclusive_end_from_start(length);
798 assert_eq!(end.start_from_inclusive_end(length), start);
799
800 let start = tf64(-f64::from_bits(1));
801 assert_eq!(TotalF64::safe_len(&(start..=start)), 1);
802 assert_eq!(TotalF64::safe_len(&(start..=start.after())), 2);
803 assert_eq!(
804 TotalF64::MAX_SIZE,
805 TotalF64::safe_len(&(TotalF64::MIN..=TotalF64::MAX))
806 );
807 let length = 17;
808 let end = start.inclusive_end_from_start(length);
809 assert_eq!(end.start_from_inclusive_end(length), start);
810 }
811
812 #[cfg(feature = "float_nightly_experimental")]
813 #[test]
814 fn f16_total_adjacency_and_lengths_are_exhaustive() {
815 for bits in 0..=u16::MAX {
816 let value = TotalF16::new(f16::from_bits(bits));
817 if value != TotalF16::MAX {
818 assert_eq!(value.after().before(), value);
819 }
820 if value != TotalF16::MIN {
821 assert_eq!(value.before().after(), value);
822 }
823 assert_eq!(TotalF16::safe_len(&(value..=value)), 1);
824 }
825 assert_eq!(
826 TotalF16::MAX_SIZE,
827 TotalF16::safe_len(&(TotalF16::MIN..=TotalF16::MAX))
828 );
829 }
830
831 fn hash(value: TotalF64) -> u64 {
832 let mut hasher = DefaultHasher::new();
833 value.hash(&mut hasher);
834 hasher.finish()
835 }
836 #[test]
837 #[cfg(feature = "float_nightly_experimental")]
838 fn ordered_round_trip() {
839 use crate::float::total_float::from_ordered_16;
840 use crate::float::total_float::to_ordered_16;
841 for x in i16::MIN..=i16::MAX {
842 assert_eq!(to_ordered_16(from_ordered_16(x)), x);
843 }
844 }
845}