rust ffast-math (defunct, use lower)
Diffstat (limited to 'src/lib.rs')
-rw-r--r--src/lib.rs52
1 files changed, 44 insertions, 8 deletions
diff --git a/src/lib.rs b/src/lib.rs
index ef8c7ba..8c4cd96 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -8,8 +8,8 @@
//! # }
//! ```
#![feature(core_intrinsics)]
-#![warn(clippy::pedantic, clippy::dbg_macro, clippy::use_self, missing_docs)]
-#![cfg_attr(not(doc), no_std)]
+#![warn(clippy::pedantic, clippy::dbg_macro, missing_docs)]
+#![allow(clippy::return_self_not_must_use)]
use core::cmp::{Ordering, PartialEq, PartialOrd};
use core::ops::{
Add as add, AddAssign as add_assign, Deref, DerefMut, Div as div, DivAssign as div_assign,
@@ -18,11 +18,15 @@ use core::ops::{
};
#[cfg(doc)]
use std::f32::{INFINITY as INF, NAN};
+use std::hash::Hash;
+pub mod generic_float;
mod r#trait;
+#[doc(inline)]
+pub use generic_float::Float;
use r#trait::FastFloat;
-/// Float wrapper that uses `ffast-math`. This float also implements [`Ord`], as it is not allowed to be [`NAN`].
+/// Float wrapper that uses `ffast-math`. This float also implements [`Ord`], [`Hash`], and [`Eq`], as it is not allowed to be [`NAN`].
///
/// `FFloat<F>` is guaranteed to have the same memory layout and ABI as F.
/// ```
@@ -32,6 +36,10 @@ use r#trait::FastFloat;
/// assert_eq!(*result, 1136943.0);
/// # }
/// ```
+///
+/// ## Safety Notice (for transmuters)
+///
+/// A [`FFloat`] is _never_ allowed to be [`NAN`] | [`INF`].
#[repr(transparent)]
#[derive(Copy, Clone, PartialEq)]
pub struct FFloat<T>(T);
@@ -50,11 +58,7 @@ impl<T: FastFloat> core::fmt::Display for FFloat<T> {
impl<T: FastFloat> FFloat<T> {
/// Create a new [`FFloat`] from your {[`f32`], [`f64`]}.
- /// # Safety
- ///
- /// - You MUST NEVER call this function with [`NAN`] | [`INF`]
- /// - You MUST NEVER make it [`NAN`] | [`INF`]
- /// - You MUST NEVER combine a [`FFloat`] with a {[`FFloat`], [`f32`], [`f64`]}, to produce a [`NAN`] | [`INF`]
+ #[doc = include_str!("ffloat_safety.md")]
/// ```
/// # use umath::FFloat;
/// // SAFETY: i have verified that 7.0 is infact, not NAN or INF.
@@ -66,6 +70,11 @@ impl<T: FastFloat> FFloat<T> {
new
}
+ /// Checks if somebody else made a mistake, cause UB or panic if so.
+ /// # Safety
+ ///
+ /// This can never cause UB unless someone else made a mistake, therefore ub has already occured.
+ #[inline(always)]
fn check(self) {
if self.bad() {
if cfg!(debug_assertions) {
@@ -206,12 +215,39 @@ impl<T: FastFloat> Ord for FFloat<T> {
}
}
+impl Hash for FFloat<f32> {
+ fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+ self.check();
+ state.write_u32((self.0 + 0.0).to_bits());
+ }
+}
+
+impl Hash for FFloat<f64> {
+ fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+ self.check();
+ state.write_u64((self.0 + 0.0).to_bits());
+ }
+}
+
#[cfg(test)]
mod tests {
+ use std::collections::HashMap;
+
use super::*;
#[test]
fn it_works() {
let result = unsafe { FFloat::new(2.0) + FFloat::new(2.0) };
assert_eq!(*result, 4.0);
}
+
+ #[test]
+ fn hashing() {
+ let mut map = HashMap::new();
+ map.insert(FFloat(2.0), "hi");
+ map.insert(FFloat(7.0), "bye");
+ map.insert(FFloat(-0.0), "edge");
+ assert!(map[&FFloat(2.0)] == "hi");
+ assert!(map[&FFloat(7.0)] == "bye");
+ assert!(map[&FFloat(0.0)] == "edge");
+ }
}