use crate::Float;
use core::cmp::Ordering;
use core::hash::{Hash, Hasher};
#[derive(Clone, Debug)]
#[repr(transparent)]
pub struct OrdFloat {
inner: Float,
}
static_assert_same_layout!(OrdFloat, Float);
impl OrdFloat {
#[inline]
pub const fn as_float(&self) -> &Float {
&self.inner
}
#[inline]
pub fn as_float_mut(&mut self) -> &mut Float {
&mut self.inner
}
}
impl Hash for OrdFloat {
fn hash<H: Hasher>(&self, state: &mut H) {
let float = &self.inner;
float.inner().sign.hash(state);
float.inner().exp.hash(state);
let slice = float.inner_data();
if let Some(first) = slice.iter().position(|&limb| limb != 0) {
slice[first..].hash(state);
}
}
}
impl Eq for OrdFloat {}
impl Ord for OrdFloat {
#[inline]
fn cmp(&self, other: &OrdFloat) -> Ordering {
self.inner.total_cmp(&other.inner)
}
}
impl PartialEq for OrdFloat {
#[inline]
fn eq(&self, other: &OrdFloat) -> bool {
let s = &self.inner;
let o = &other.inner;
if s.is_sign_negative() != o.is_sign_negative() {
return false;
}
let o_nan = o.is_nan();
if s.is_nan() {
return o_nan;
}
if o_nan {
return false;
}
s.eq(o)
}
}
impl PartialOrd for OrdFloat {
#[inline]
fn partial_cmp(&self, other: &OrdFloat) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl From<Float> for OrdFloat {
#[inline]
fn from(src: Float) -> Self {
OrdFloat { inner: src }
}
}
impl From<OrdFloat> for Float {
#[inline]
fn from(src: OrdFloat) -> Self {
src.inner
}
}
impl AsRef<Float> for OrdFloat {
#[inline]
fn as_ref(&self) -> &Float {
self.as_float()
}
}
impl AsMut<Float> for OrdFloat {
#[inline]
fn as_mut(&mut self) -> &mut Float {
self.as_float_mut()
}
}
#[allow(clippy::eq_op)]
#[cfg(test)]
mod tests {
use crate::float;
use crate::float::{FreeCache, OrdFloat, Special};
use crate::ops::NegAssign;
use crate::{Assign, Float};
use core::hash::{Hash, Hasher};
use core::ptr;
use std::collections::hash_map::DefaultHasher;
fn calculate_hash<T: Hash>(t: &T) -> u64 {
let mut s = DefaultHasher::new();
t.hash(&mut s);
s.finish()
}
#[test]
fn check_zero() {
let p = Float::with_val(53, Special::Zero);
let n = Float::with_val(53, Special::NegZero);
assert_eq!(p, n);
let ord_p = p.as_ord();
let ord_n = n.as_ord();
assert_eq!(ord_p, ord_p);
assert_eq!(ord_n, ord_n);
assert_eq!(calculate_hash(ord_p), calculate_hash(ord_p));
assert_eq!(calculate_hash(ord_n), calculate_hash(ord_n));
assert_ne!(ord_p, ord_n);
assert_ne!(calculate_hash(ord_p), calculate_hash(ord_n));
float::free_cache(FreeCache::All);
}
fn hash(f: &OrdFloat) -> u64 {
let mut hasher = DefaultHasher::new();
f.hash(&mut hasher);
hasher.finish()
}
#[test]
fn check_hash_different_prec() {
let mut f = Float::new(53);
let mut g = Float::new(5301);
assert_eq!(f, g);
assert_eq!(f.as_ord(), g.as_ord());
assert_eq!(hash(f.as_ord()), hash(g.as_ord()));
g.neg_assign();
assert_eq!(f, g);
assert_ne!(f.as_ord(), g.as_ord());
assert_ne!(hash(f.as_ord()), hash(g.as_ord()));
f.assign(23.5);
g.assign(23.5);
assert_eq!(f, g);
assert_eq!(f.as_ord(), g.as_ord());
assert_eq!(hash(f.as_ord()), hash(g.as_ord()));
g.neg_assign();
assert_ne!(f, g);
assert_ne!(f.as_ord(), g.as_ord());
assert_ne!(hash(f.as_ord()), hash(g.as_ord()));
f.assign(Special::Nan);
g.assign(Special::Nan);
assert_ne!(f, g);
assert_eq!(f.as_ord(), g.as_ord());
assert_eq!(hash(f.as_ord()), hash(g.as_ord()));
g.neg_assign();
assert_ne!(f, g);
assert_ne!(f.as_ord(), g.as_ord());
assert_ne!(hash(f.as_ord()), hash(g.as_ord()));
}
#[test]
fn check_refs() {
let f = Float::with_val(53, 23.5);
assert_eq!(
ptr::addr_of!(f).cast::<OrdFloat>(),
f.as_ord() as *const OrdFloat
);
assert_eq!(
ptr::addr_of!(f).cast::<OrdFloat>(),
AsRef::<OrdFloat>::as_ref(&f) as *const OrdFloat
);
let mut o = OrdFloat::from(f);
assert_eq!(
ptr::addr_of!(o).cast::<Float>(),
o.as_float() as *const Float
);
assert_eq!(
ptr::addr_of!(o).cast::<Float>(),
AsRef::<Float>::as_ref(&o) as *const Float
);
assert_eq!(
ptr::addr_of_mut!(o).cast::<Float>(),
o.as_float_mut() as *mut Float
);
assert_eq!(
ptr::addr_of_mut!(o).cast::<Float>(),
AsMut::<Float>::as_mut(&mut o) as *mut Float
);
}
}