use crate::NumHash;
use num_modular::{ModularCoreOps, ModularOps};
use num_traits::Float;
use core::hash::{Hash, Hasher};
const P64: u64 = 0xFFFFFFFFFFFFFFC5; const M61: i64 = 0x1FFFFFFFFFFFFFFF; const HASH_INF: i64 = i64::MAX;
impl NumHash for i64 {
#[inline]
fn num_hash<H: Hasher>(&self, state: &mut H) {
(self % M61).hash(state)
}
}
impl NumHash for u64 {
#[inline]
fn num_hash<H: Hasher>(&self, state: &mut H) {
((self % M61 as u64) as i64).hash(state)
}
}
macro_rules! impl_hash_for_small_int {
($($signed:ty)*) => ($(
impl NumHash for $signed {
#[inline]
fn num_hash<H: Hasher>(&self, state: &mut H) {
(&(*self as i64)).hash(state) }
}
)*);
}
impl_hash_for_small_int! { i8 i16 i32 u8 u16 u32 }
impl NumHash for usize {
#[inline]
fn num_hash<H: Hasher>(&self, state: &mut H) {
(&(*self as u64)).num_hash(state)
}
}
impl NumHash for isize {
#[inline]
fn num_hash<H: Hasher>(&self, state: &mut H) {
(&(*self as i64)).num_hash(state)
}
}
impl NumHash for u128 {
#[inline]
fn num_hash<H: Hasher>(&self, state: &mut H) {
((self % M61 as u128) as i64).hash(state)
}
}
impl NumHash for i128 {
#[inline]
fn num_hash<H: Hasher>(&self, state: &mut H) {
((self % M61 as i128) as i64).hash(state)
}
}
#[cfg(feature = "num-bigint")]
mod _num_bigint {
use super::*;
use num_bigint::{BigInt, BigUint};
use num_traits::ToPrimitive;
impl NumHash for BigUint {
fn num_hash<H: Hasher>(&self, state: &mut H) {
(self % BigUint::from(M61 as u64)).to_i64().unwrap().hash(state)
}
}
impl NumHash for BigInt {
fn num_hash<H: Hasher>(&self, state: &mut H) {
(self % BigInt::from(M61)).to_i64().unwrap().hash(state)
}
}
}
macro_rules! impl_hash_for_float {
($($float:ty)*) => ($(
impl NumHash for $float {
fn num_hash<H: Hasher>(&self, state: &mut H) {
if self.is_nan() {
0i64.num_hash(state) } else if self.is_infinite() {
if self.is_sign_positive() {
HASH_INF.num_hash(state)
} else {
(-HASH_INF).num_hash(state)
}
} else {
let (mantissa, exp, sign) = self.integer_decode();
let exp = if exp > 0 { (exp as u64) % 61 } else { ModularCoreOps::<u64>::negm(&(-exp as u64), &61) };
let v = mantissa.mulm(1u64 << ((exp as u64) % 61), &(M61 as u64));
(v as i64 * sign as i64).hash(state);
}
}
}
)*);
}
impl_hash_for_float! { f32 f64 }
#[cfg(feature = "num-rational")]
mod _num_rational {
use super::*;
use core::ops::Neg;
use num_rational::Ratio;
macro_rules! impl_hash_for_ratio {
($($int:ty)*) => ($(
impl NumHash for Ratio<$int> {
fn num_hash<H: Hasher>(&self, state: &mut H) {
let ub = *self.denom() as u64;
let binv = if ub % M61 as u64 != 0 {
ModularOps::<&u64>::invm(&ub, &(M61 as u64)).unwrap()
} else {
HASH_INF as u64 };
let ua = if self.numer() < &0 { (*self.numer() as u64).wrapping_neg() } else { *self.numer() as u64 };
let ab = (ua % M61 as u64).mulm(binv, &(M61 as u64));
if self.numer() >= &0 {
(ab as i64).hash(state)
} else {
(ab as i64).neg().hash(state)
}
}
}
)*);
}
impl_hash_for_ratio!(i8 i16 i32 i64 isize);
impl NumHash for Ratio<i128> {
fn num_hash<H: Hasher>(&self, state: &mut H) {
let ub = (self.denom() % M61 as i128) as u64;
let binv = if ub > 0 {
ModularOps::<&u64>::invm(&ub, &(M61 as u64)).unwrap()
} else {
HASH_INF as u64 };
let ua = if self.numer() < &0 { (*self.numer() as u128).wrapping_neg() } else { *self.numer() as u128 };
let ua = (ua % M61 as u128) as u64;
let ab = ua.mulm(&binv, &(M61 as u64));
if self.numer() >= &0 {
(ab as i64).hash(state)
} else {
(ab as i64).neg().hash(state)
}
}
}
}
#[cfg(feature = "num-complex")]
mod _num_complex {
}