Simplify the to_primitive_float macros

This commit is contained in:
Josh Stone 2018-03-10 23:33:47 -08:00
parent f6dc4d29a4
commit d195eafbe2
1 changed files with 64 additions and 85 deletions

View File

@ -223,112 +223,91 @@ impl_to_primitive_uint!(u32);
impl_to_primitive_uint!(u64); impl_to_primitive_uint!(u64);
macro_rules! impl_to_primitive_float_to_float { macro_rules! impl_to_primitive_float_to_float {
($SrcT:ident, $DstT:ident, $slf:expr) => ({ ($SrcT:ident : $( fn $method:ident -> $DstT:ident ; )*) => {$(
// Only finite values that are reducing size need to worry about overflow. #[inline]
if size_of::<$SrcT>() > size_of::<$DstT>() && FloatCore::is_finite($slf) { fn $method(&self) -> Option<$DstT> {
let n = $slf as f64; // Only finite values that are reducing size need to worry about overflow.
if n < $DstT::MIN as f64 || n > $DstT::MAX as f64 { if size_of::<$SrcT>() > size_of::<$DstT>() && FloatCore::is_finite(*self) {
return None; let n = *self as f64;
if n < $DstT::MIN as f64 || n > $DstT::MAX as f64 {
return None;
}
} }
// We can safely cast NaN, +-inf, and finite values in range.
Some(*self as $DstT)
} }
// We can safely cast NaN, +-inf, and finite values in range. )*}
Some($slf as $DstT)
})
} }
macro_rules! impl_to_primitive_float_to_signed_int { macro_rules! impl_to_primitive_float_to_signed_int {
($SrcT:ident, $DstT:ident, $slf:expr) => ({ ($f:ident : $( fn $method:ident -> $i:ident ; )*) => {$(
let t = $slf.trunc(); // round toward zero. #[inline]
// MIN is a power of two, which we can cast and compare directly. fn $method(&self) -> Option<$i> {
if t >= $DstT::MIN as $SrcT { let t = self.trunc(); // round toward zero.
// The mantissa might not be able to represent all digits of MAX. // MIN is a power of two, which we can cast and compare directly.
let sig_bits = size_of::<$DstT>() as u32 * 8 - 1; if t >= $i::MIN as $f {
let max = if sig_bits > $SrcT::MANTISSA_DIGITS { // The mantissa might not be able to represent all digits of MAX.
let lost_bits = sig_bits - $SrcT::MANTISSA_DIGITS; let sig_bits = size_of::<$i>() as u32 * 8 - 1;
$DstT::MAX & !((1 << lost_bits) - 1) let max = if sig_bits > $f::MANTISSA_DIGITS {
} else { let lost_bits = sig_bits - $f::MANTISSA_DIGITS;
$DstT::MAX $i::MAX & !((1 << lost_bits) - 1)
}; } else {
if t <= max as $SrcT { $i::MAX
return Some($slf as $DstT); };
if t <= max as $f {
return Some(*self as $i);
}
} }
None
} }
None )*}
})
} }
macro_rules! impl_to_primitive_float_to_unsigned_int { macro_rules! impl_to_primitive_float_to_unsigned_int {
($SrcT:ident, $DstT:ident, $slf:expr) => ({ ($f:ident : $( fn $method:ident -> $u:ident ; )*) => {$(
let t = $slf.trunc(); // round toward zero. #[inline]
if t >= 0.0 { fn $method(&self) -> Option<$u> {
// The mantissa might not be able to represent all digits of MAX. let t = self.trunc(); // round toward zero.
let sig_bits = size_of::<$DstT>() as u32 * 8; if t >= 0.0 {
let max = if sig_bits > $SrcT::MANTISSA_DIGITS { // The mantissa might not be able to represent all digits of MAX.
let lost_bits = sig_bits - $SrcT::MANTISSA_DIGITS; let sig_bits = size_of::<$u>() as u32 * 8;
$DstT::MAX & !((1 << lost_bits) - 1) let max = if sig_bits > $f::MANTISSA_DIGITS {
} else { let lost_bits = sig_bits - $f::MANTISSA_DIGITS;
$DstT::MAX $u::MAX & !((1 << lost_bits) - 1)
}; } else {
if t <= max as $SrcT { $u::MAX
return Some($slf as $DstT); };
if t <= max as $f {
return Some(*self as $u);
}
} }
None
} }
None )*}
})
} }
macro_rules! impl_to_primitive_float { macro_rules! impl_to_primitive_float {
($T:ident) => ( ($T:ident) => (
impl ToPrimitive for $T { impl ToPrimitive for $T {
#[inline] impl_to_primitive_float_to_signed_int! { $T:
fn to_isize(&self) -> Option<isize> { fn to_isize -> isize;
impl_to_primitive_float_to_signed_int!($T, isize, *self) fn to_i8 -> i8;
} fn to_i16 -> i16;
#[inline] fn to_i32 -> i32;
fn to_i8(&self) -> Option<i8> { fn to_i64 -> i64;
impl_to_primitive_float_to_signed_int!($T, i8, *self)
}
#[inline]
fn to_i16(&self) -> Option<i16> {
impl_to_primitive_float_to_signed_int!($T, i16, *self)
}
#[inline]
fn to_i32(&self) -> Option<i32> {
impl_to_primitive_float_to_signed_int!($T, i32, *self)
}
#[inline]
fn to_i64(&self) -> Option<i64> {
impl_to_primitive_float_to_signed_int!($T, i64, *self)
} }
#[inline] impl_to_primitive_float_to_unsigned_int! { $T:
fn to_usize(&self) -> Option<usize> { fn to_usize -> usize;
impl_to_primitive_float_to_unsigned_int!($T, usize, *self) fn to_u8 -> u8;
} fn to_u16 -> u16;
#[inline] fn to_u32 -> u32;
fn to_u8(&self) -> Option<u8> { fn to_u64 -> u64;
impl_to_primitive_float_to_unsigned_int!($T, u8, *self)
}
#[inline]
fn to_u16(&self) -> Option<u16> {
impl_to_primitive_float_to_unsigned_int!($T, u16, *self)
}
#[inline]
fn to_u32(&self) -> Option<u32> {
impl_to_primitive_float_to_unsigned_int!($T, u32, *self)
}
#[inline]
fn to_u64(&self) -> Option<u64> {
impl_to_primitive_float_to_unsigned_int!($T, u64, *self)
} }
#[inline] impl_to_primitive_float_to_float! { $T:
fn to_f32(&self) -> Option<f32> { fn to_f32 -> f32;
impl_to_primitive_float_to_float!($T, f32, *self) fn to_f64 -> f64;
}
#[inline]
fn to_f64(&self) -> Option<f64> {
impl_to_primitive_float_to_float!($T, f64, *self)
} }
} }
) )