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)]
91#[derive(Copy, Clone, Default, Debug)]
92pub struct Total<T: TotalFloat>(T);
93
94impl<T: TotalFloat> Total<T> {
95 pub const MIN: Self = Self(T::MIN);
106
107 pub const MAX: Self = Self(T::MAX);
118
119 pub const MAX_SIZE: T::SafeLen = T::MAX_SIZE;
128
129 #[must_use]
139 pub const fn new(x: T) -> Self {
140 Self(x)
141 }
142
143 #[must_use]
151 pub fn inclusive_end_from_start(self, b: T::SafeLen) -> Self {
152 Self(T::inclusive_end_from_start(self.0, b))
153 }
154
155 #[must_use]
163 pub fn start_from_inclusive_end(self, b: T::SafeLen) -> Self {
164 Self(T::start_from_inclusive_end(self.0, b))
165 }
166
167 #[must_use]
176 pub const fn into_inner(self) -> T {
177 self.0
178 }
179
180 #[must_use]
194 pub fn after(self) -> Self {
195 debug_assert!(self != Self::MAX, "after() called on maximum value");
196 Self(T::after(self.0))
197 }
198
199 #[must_use]
213 pub fn before(self) -> Self {
214 debug_assert!(self != Self::MIN, "before() called on minimum value");
215 Self(T::before(self.0))
216 }
217
218 #[must_use]
232 pub fn checked_after(self) -> Option<Self> {
233 if self == Self::MAX {
234 None
235 } else {
236 Some(self.after())
237 }
238 }
239
240 #[must_use]
254 pub fn checked_before(self) -> Option<Self> {
255 if self == Self::MIN {
256 None
257 } else {
258 Some(self.before())
259 }
260 }
261
262 #[must_use]
275 pub fn from_primitive_range(range: RangeInclusive<T>) -> RangeInclusive<Self> {
276 let (start, end) = range.into_inner();
277 Self(start)..=Self(end)
278 }
279
280 pub fn from_primitive_ranges<I>(ranges: I) -> impl Iterator<Item = RangeInclusive<Self>>
293 where
294 I: IntoIterator<Item = RangeInclusive<T>>,
295 {
296 ranges.into_iter().map(Self::from_primitive_range)
297 }
298
299 pub fn values<I>(values: I) -> impl Iterator<Item = Self>
309 where
310 I: IntoIterator<Item = T>,
311 {
312 values.into_iter().map(Self)
313 }
314
315 #[must_use]
329 pub const fn from_primitive_slice(values: &[T]) -> &[Self] {
330 unsafe { mem::transmute::<&[T], &[Self]>(values) }
333 }
334}
335
336pub trait TotalSliceExt<T: TotalFloat> {
338 fn as_primitive_slice(&self) -> &[T];
352}
353
354impl<T: TotalFloat> TotalSliceExt<T> for [Total<T>] {
355 fn as_primitive_slice(&self) -> &[T] {
356 unsafe { from_raw_parts(self.as_ptr().cast::<T>(), self.len()) }
359 }
360}
361
362pub trait TotalRangeExt<T: TotalFloat> {
365 #[must_use]
380 fn into_primitive_range(self) -> RangeInclusive<T>;
381
382 #[must_use]
399 fn into_primitive_inner(self) -> (T, T);
400}
401
402impl<T: TotalFloat> TotalRangeExt<T> for RangeInclusive<Total<T>> {
403 fn into_primitive_range(self) -> RangeInclusive<T> {
404 let (start, end) = self.into_primitive_inner();
405 start..=end
406 }
407
408 fn into_primitive_inner(self) -> (T, T) {
409 let (start, end) = self.into_inner();
410 (start.into_inner(), end.into_inner())
411 }
412}
413
414impl<T: TotalFloat> PartialEq for Total<T> {
415 fn eq(&self, other: &Self) -> bool {
416 T::total_cmp(self.0, other.0) == Ordering::Equal
417 }
418}
419
420impl<T: TotalFloat> Eq for Total<T> {}
421
422impl<T: TotalFloat> PartialOrd for Total<T> {
423 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
424 Some(self.cmp(other))
425 }
426}
427
428impl<T: TotalFloat> Ord for Total<T> {
429 fn cmp(&self, other: &Self) -> Ordering {
430 T::total_cmp(self.0, other.0)
431 }
432}
433
434impl<T: TotalFloat> Hash for Total<T> {
435 fn hash<H: Hasher>(&self, state: &mut H) {
436 T::hash(self.0, state);
437 }
438}
439
440impl<T: TotalFloat> Integer for Total<T> {
441 type SafeLen = T::SafeLen;
442
443 #[inline]
444 fn checked_add_one(self) -> Option<Self> {
445 self.checked_after()
446 }
447
448 #[inline]
450 fn add_one(self) -> Self {
451 self.after()
452 }
453
454 #[inline]
455 fn sub_one(self) -> Self {
457 self.before()
458 }
459
460 #[inline]
461 fn assign_sub_one(&mut self) {
462 *self = self.before();
463 }
464
465 #[inline]
467 fn range_next(range: &mut RangeInclusive<Self>) -> Option<Self> {
468 if range.is_empty() {
469 None
470 } else if range.start() == range.end() && *range.start() == Self::MAX {
471 let next = *range.start();
473 *range = next..=range.end().before();
474 Some(next)
475 } else {
476 let next = *range.start();
477 *range = (next.after())..=*range.end();
478 Some(next)
479 }
480 }
481
482 #[inline]
483 fn range_next_back(range: &mut RangeInclusive<Self>) -> Option<Self> {
484 if range.is_empty() {
485 None
486 } else if range.start() == range.end() && *range.start() == Self::MIN {
487 let last = *range.end();
489 *range = last.after()..=last;
490 Some(last)
491 } else {
492 let last = *range.end();
493 *range = *range.start()..=last.before();
494 Some(last)
495 }
496 }
497
498 #[inline]
499 fn min_value() -> Self {
500 Self::MIN
501 }
502
503 #[inline]
504 fn max_value() -> Self {
505 Self::MAX
506 }
507
508 #[cfg(feature = "from_slice")]
509 #[inline]
510 fn from_slice(slice: impl AsRef<[Self]>) -> RangeSetBlaze<Self> {
511 RangeSetBlaze::from_iter(slice.as_ref())
514 }
515
516 fn safe_len(r: &RangeInclusive<Self>) -> Self::SafeLen {
517 let (start, end) = r.clone().into_primitive_inner();
518 T::prim_safe_len(start, end)
519 }
520
521 fn safe_len_to_f64_lossy(len: Self::SafeLen) -> f64 {
522 T::safe_len_to_f64_lossy(len)
523 }
524
525 fn f64_to_safe_len_lossy(f: f64) -> Self::SafeLen {
526 T::f64_to_safe_len_lossy(f)
527 }
528
529 fn inclusive_end_from_start(self, b: Self::SafeLen) -> Self {
530 self.inclusive_end_from_start(b)
531 }
532
533 fn start_from_inclusive_end(self, b: Self::SafeLen) -> Self {
534 self.start_from_inclusive_end(b)
535 }
536}
537
538#[cfg(test)]
539mod tests {
540 use super::*;
541 use crate::Integer;
542 use crate::float::total_float::{
543 from_ordered_32, from_ordered_64, to_ordered_32, to_ordered_64,
544 };
545 use std::collections::hash_map::DefaultHasher;
546 use std::vec;
547 use std::vec::Vec;
548
549 #[test]
550 fn ordering_agrees_with_total_cmp() {
551 let values = [
552 f64::NEG_INFINITY,
553 -f64::MAX,
554 -1.0,
555 -0.0,
556 0.0,
557 1.0,
558 f64::MAX,
559 f64::INFINITY,
560 f64::NAN,
561 f64::from_bits(0x7ff8_0000_0000_0001),
562 f64::from_bits(0xfff8_0000_0000_0001),
563 ];
564
565 for left in values {
566 for right in values {
567 assert_eq!(tf64(left).cmp(&tf64(right)), left.total_cmp(&right));
568 }
569 }
570 }
571
572 #[test]
573 fn equality_agrees_with_total_cmp() {
574 assert_ne!(tf64(-0.0), tf64(0.0));
575 assert_eq!(tf64(f64::NAN), tf64(f64::NAN));
576 }
577
578 #[test]
579 fn equal_values_hash_equally() {
580 let left = hash(tf64(f64::NAN));
581 let right = hash(tf64(f64::NAN));
582
583 assert_eq!(left, right);
584 }
585
586 #[test]
587 fn converts_ranges() {
588 assert_eq!(
589 TotalF64::from_primitive_range(10.0..=20.0),
590 tf64(10.0)..=tf64(20.0)
591 );
592 assert_eq!(
593 TotalF64::from_primitive_ranges([10.0..=20.0, 30.0..=40.0]).collect::<Vec<_>>(),
594 vec![tf64(10.0)..=tf64(20.0), tf64(30.0)..=tf64(40.0)]
595 );
596 }
597
598 #[test]
599 fn after_and_before_step_through_zero_in_total_order() {
600 assert_eq!(tf64(-0.0).after(), tf64(0.0));
601 assert_eq!(tf64(0.0).before(), tf64(-0.0));
602 assert_eq!(tf64(0.0).after(), tf64(f64::from_bits(1)));
603 assert_eq!(
604 tf64(-0.0).before(),
605 tf64(f64::from_bits(0x8000_0000_0000_0001))
606 );
607 }
608
609 #[test]
610 fn checked_after_and_before_are_not_wrapping() {
611 assert_eq!(TotalF64::MAX.checked_after(), None);
612 assert_eq!(TotalF64::MIN.checked_before(), None);
613 }
614
615 #[test]
616 #[cfg(debug_assertions)]
617 #[should_panic(expected = "after() called on maximum value")]
618 fn total_after_panics_at_max_in_debug() {
619 let _ = TotalF64::MAX.after();
620 }
621
622 #[test]
623 #[cfg(not(debug_assertions))]
624 fn total_after_wraps_at_max_in_release() {
625 assert_eq!(TotalF64::MAX.after(), TotalF64::MIN);
626 }
627
628 #[test]
629 #[cfg(debug_assertions)]
630 #[should_panic(expected = "before() called on minimum value")]
631 fn total_before_panics_at_min_in_debug() {
632 let _ = TotalF64::MIN.before();
633 }
634
635 #[test]
636 #[cfg(not(debug_assertions))]
637 fn total_before_wraps_at_min_in_release() {
638 assert_eq!(TotalF64::MIN.before(), TotalF64::MAX);
639 }
640
641 #[test]
642 fn stable_ordered_round_trips() {
643 let edge_f64 = [
644 0,
645 1,
646 u64::MAX,
647 0x7ff0_0000_0000_0000,
648 0xfff0_0000_0000_0000,
649 0x7ff8_0000_0000_0001,
650 0xfff8_0000_0000_0001,
651 ];
652 for bits in edge_f64 {
653 let value = f64::from_bits(bits);
654 assert_eq!(from_ordered_64(to_ordered_64(value)).to_bits(), bits);
655 }
656
657 let edge_f32 = [
658 0,
659 1,
660 u32::MAX,
661 0x7f80_0000,
662 0xff80_0000,
663 0x7fc0_0001,
664 0xffc0_0001,
665 ];
666 for bits in edge_f32 {
667 let value = f32::from_bits(bits);
668 assert_eq!(from_ordered_32(to_ordered_32(value)).to_bits(), bits);
669 }
670
671 let mut state = 0x9e37_79b9_u64;
672 for _ in 0..10_000 {
673 state = state
674 .wrapping_mul(6_364_136_223_846_793_005)
675 .wrapping_add(1);
676 let value = f64::from_bits(state);
677 assert_eq!(from_ordered_64(to_ordered_64(value)).to_bits(), state);
678 let bytes = state.to_le_bytes();
679 let bits = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
680 let value = f32::from_bits(bits);
681 assert_eq!(from_ordered_32(to_ordered_32(value)).to_bits(), bits);
682 }
683 }
684
685 #[test]
686 fn after_and_before_step_around_infinities() {
687 assert_eq!(tf64(f64::MAX).after(), tf64(f64::INFINITY));
688 assert_eq!(tf64(f64::INFINITY).before(), tf64(f64::MAX));
689 assert_eq!(tf64(f64::NEG_INFINITY).after(), tf64(-f64::MAX));
690 assert_eq!(tf64(-f64::MAX).before(), tf64(f64::NEG_INFINITY));
691 }
692
693 #[test]
694 fn checked_after_and_before_stop_at_total_order_boundaries() {
695 assert_eq!(TotalF64::MIN.checked_before(), None);
696 assert_eq!(TotalF64::MAX.checked_after(), None);
697 assert_eq!(TotalF64::MIN.checked_after(), Some(TotalF64::MIN.after()));
698 assert_eq!(TotalF64::MAX.checked_before(), Some(TotalF64::MAX.before()));
699 }
700
701 #[test]
702 fn min_and_max_are_total_order_boundaries() {
703 let values = [
704 tf64(f64::NEG_INFINITY),
705 tf64(-f64::MAX),
706 tf64(-1.0),
707 tf64(-0.0),
708 tf64(0.0),
709 tf64(1.0),
710 tf64(f64::MAX),
711 tf64(f64::INFINITY),
712 tf64(f64::NAN),
713 tf64(f64::from_bits(0x7ff8_0000_0000_0001)),
714 tf64(f64::from_bits(0xfff8_0000_0000_0001)),
715 ];
716
717 for value in values {
718 assert!(TotalF64::MIN <= value);
719 assert!(value <= TotalF64::MAX);
720 }
721 }
722
723 #[test]
724 fn after_and_before_are_neighbors_in_total_order() {
725 let values = [
726 tf64(f64::NEG_INFINITY),
727 tf64(-f64::MAX),
728 tf64(-1.0),
729 tf64(-0.0),
730 tf64(0.0),
731 tf64(1.0),
732 tf64(f64::MAX),
733 tf64(f64::INFINITY),
734 tf64(f64::NAN),
735 tf64(f64::from_bits(0x7ff8_0000_0000_0001)),
736 tf64(f64::from_bits(0xfff8_0000_0000_0001)),
737 ];
738
739 for value in values {
740 assert_eq!(value.after().before(), value);
741 assert_eq!(value.before().after(), value);
742 }
743 }
744
745 #[test]
746 fn adjacency_laws_cover_f32_and_f64_edges() {
747 macro_rules! check {
748 ($wrapper:ident, $constructor:ident, $zero:expr, $negative_subnormal:expr, $positive_subnormal:expr, $min:expr, $max:expr) => {
749 let values = [
750 $constructor($zero),
751 $constructor($negative_subnormal),
752 $constructor($positive_subnormal),
753 $constructor(-1.0),
754 $constructor(1.0),
755 $constructor($min),
756 $constructor($max),
757 $constructor(f32::INFINITY),
758 $constructor(f32::NAN),
759 ];
760 for value in values {
761 assert_eq!(value.after().before(), value);
762 assert_eq!(value.before().after(), value);
763 }
764 assert_eq!($wrapper::MIN.checked_before(), None);
765 assert_eq!($wrapper::MAX.checked_after(), None);
766 };
767 }
768 check!(
769 TotalF32,
770 tf32,
771 0.0_f32,
772 -f32::from_bits(1),
773 f32::from_bits(1),
774 f32::MIN,
775 f32::MAX
776 );
777
778 let values = [
779 tf64(-0.0),
780 tf64(0.0),
781 tf64(-f64::from_bits(1)),
782 tf64(f64::from_bits(1)),
783 tf64(-f64::MAX),
784 tf64(f64::MAX),
785 tf64(f64::NEG_INFINITY),
786 tf64(f64::INFINITY),
787 tf64(f64::from_bits(0x7ff8_0000_0000_0001)),
788 ];
789 for value in values {
790 assert_eq!(value.after().before(), value);
791 assert_eq!(value.before().after(), value);
792 }
793 assert_eq!(TotalF64::MIN.checked_before(), None);
794 assert_eq!(TotalF64::MAX.checked_after(), None);
795 }
796
797 #[test]
798 fn range_length_laws_cover_f32_and_f64() {
799 let start = tf32(-f32::from_bits(1));
800 assert_eq!(TotalF32::safe_len(&(start..=start)), 1);
801 assert_eq!(TotalF32::safe_len(&(start..=start.after())), 2);
802 assert_eq!(
803 TotalF32::MAX_SIZE,
804 TotalF32::safe_len(&(TotalF32::MIN..=TotalF32::MAX))
805 );
806 let length = 17;
807 let end = start.inclusive_end_from_start(length);
808 assert_eq!(end.start_from_inclusive_end(length), start);
809
810 let start = tf64(-f64::from_bits(1));
811 assert_eq!(TotalF64::safe_len(&(start..=start)), 1);
812 assert_eq!(TotalF64::safe_len(&(start..=start.after())), 2);
813 assert_eq!(
814 TotalF64::MAX_SIZE,
815 TotalF64::safe_len(&(TotalF64::MIN..=TotalF64::MAX))
816 );
817 let length = 17;
818 let end = start.inclusive_end_from_start(length);
819 assert_eq!(end.start_from_inclusive_end(length), start);
820 }
821
822 #[cfg(feature = "float_nightly_experimental")]
823 #[test]
824 fn f16_total_adjacency_and_lengths_are_exhaustive() {
825 for bits in 0..=u16::MAX {
826 let value = TotalF16::new(f16::from_bits(bits));
827 if value != TotalF16::MAX {
828 assert_eq!(value.after().before(), value);
829 }
830 if value != TotalF16::MIN {
831 assert_eq!(value.before().after(), value);
832 }
833 assert_eq!(TotalF16::safe_len(&(value..=value)), 1);
834 }
835 assert_eq!(
836 TotalF16::MAX_SIZE,
837 TotalF16::safe_len(&(TotalF16::MIN..=TotalF16::MAX))
838 );
839 }
840
841 fn hash(value: TotalF64) -> u64 {
842 let mut hasher = DefaultHasher::new();
843 value.hash(&mut hasher);
844 hasher.finish()
845 }
846 #[test]
847 #[cfg(feature = "float_nightly_experimental")]
848 fn ordered_round_trip() {
849 use crate::float::total_float::from_ordered_16;
850 use crate::float::total_float::to_ordered_16;
851 for x in i16::MIN..=i16::MAX {
852 assert_eq!(to_ordered_16(from_ordered_16(x)), x);
853 }
854 }
855}