Refactor int builtins to use associated consts

This commit is contained in:
est31 2017-09-13 21:01:40 +02:00
parent 23f14d3f05
commit c9a261895e
6 changed files with 52 additions and 66 deletions

View File

@ -11,7 +11,7 @@ macro_rules! int_to_float {
let mant_dig = <$fty>::significand_bits() + 1; let mant_dig = <$fty>::significand_bits() + 1;
let exponent_bias = <$fty>::exponent_bias(); let exponent_bias = <$fty>::exponent_bias();
let n = <$ity>::bits(); let n = <$ity>::BITS;
let (s, a) = i.extract_sign(); let (s, a) = i.extract_sign();
let mut a = a; let mut a = a;
@ -21,7 +21,7 @@ macro_rules! int_to_float {
// exponent // exponent
let mut e = sd - 1; let mut e = sd - 1;
if <$ity>::bits() < mant_dig { if <$ity>::BITS < mant_dig {
return <$fty>::from_parts(s, return <$fty>::from_parts(s,
(e + exponent_bias) as <$fty as Float>::Int, (e + exponent_bias) as <$fty as Float>::Int,
(a as <$fty as Float>::Int) << (mant_dig - e - 1)) (a as <$fty as Float>::Int) << (mant_dig - e - 1))
@ -142,7 +142,7 @@ macro_rules! float_to_int {
let f = $f; let f = $f;
let fixint_min = <$ity>::min_value(); let fixint_min = <$ity>::min_value();
let fixint_max = <$ity>::max_value(); let fixint_max = <$ity>::max_value();
let fixint_bits = <$ity>::bits() as usize; let fixint_bits = <$ity>::BITS as usize;
let fixint_unsigned = fixint_min == 0; let fixint_unsigned = fixint_min == 0;
let sign_bit = <$fty>::sign_mask(); let sign_bit = <$fty>::sign_mask();

View File

@ -39,11 +39,11 @@ pub trait Int:
/// Unsigned version of Self /// Unsigned version of Self
type UnsignedInt: Int; type UnsignedInt: Int;
/// Returns the bitwidth of the int type /// The bitwidth of the int type
fn bits() -> u32; const BITS: u32;
fn zero() -> Self; const ZERO: Self;
fn one() -> Self; const ONE: Self;
/// Extracts the sign from self and returns a tuple. /// Extracts the sign from self and returns a tuple.
/// ///
@ -83,17 +83,10 @@ macro_rules! int_impl {
type OtherSign = $ity; type OtherSign = $ity;
type UnsignedInt = $uty; type UnsignedInt = $uty;
fn zero() -> Self { const BITS: u32 = $bits;
0
}
fn one() -> Self { const ZERO: Self = 0;
1 const ONE: Self = 1;
}
fn bits() -> u32 {
$bits
}
fn extract_sign(self) -> (bool, $uty) { fn extract_sign(self) -> (bool, $uty) {
(false, self) (false, self)
@ -140,17 +133,10 @@ macro_rules! int_impl {
type OtherSign = $uty; type OtherSign = $uty;
type UnsignedInt = $uty; type UnsignedInt = $uty;
fn bits() -> u32 { const BITS: u32 = $bits;
$bits
}
fn zero() -> Self { const ZERO: Self = 0;
0 const ONE: Self = 1;
}
fn one() -> Self {
1
}
fn extract_sign(self) -> (bool, $uty) { fn extract_sign(self) -> (bool, $uty) {
if self < 0 { if self < 0 {

View File

@ -5,8 +5,8 @@ use int::Int;
trait Mul: LargeInt { trait Mul: LargeInt {
fn mul(self, other: Self) -> Self { fn mul(self, other: Self) -> Self {
let half_bits = Self::bits() / 4; let half_bits = Self::BITS / 4;
let lower_mask = !<<Self as LargeInt>::LowHalf>::zero() >> half_bits; let lower_mask = !<<Self as LargeInt>::LowHalf>::ZERO >> half_bits;
let mut low = (self.low() & lower_mask).wrapping_mul(other.low() & lower_mask); let mut low = (self.low() & lower_mask).wrapping_mul(other.low() & lower_mask);
let mut t = low >> half_bits; let mut t = low >> half_bits;
low &= lower_mask; low &= lower_mask;
@ -33,23 +33,23 @@ trait Mulo: Int + ops::Neg<Output = Self> {
*overflow = 0; *overflow = 0;
let result = self.wrapping_mul(other); let result = self.wrapping_mul(other);
if self == Self::min_value() { if self == Self::min_value() {
if other != Self::zero() && other != Self::one() { if other != Self::ZERO && other != Self::ONE {
*overflow = 1; *overflow = 1;
} }
return result; return result;
} }
if other == Self::min_value() { if other == Self::min_value() {
if self != Self::zero() && self != Self::one() { if self != Self::ZERO && self != Self::ONE {
*overflow = 1; *overflow = 1;
} }
return result; return result;
} }
let sa = self >> (Self::bits() - 1); let sa = self >> (Self::BITS - 1);
let abs_a = (self ^ sa) - sa; let abs_a = (self ^ sa) - sa;
let sb = other >> (Self::bits() - 1); let sb = other >> (Self::BITS - 1);
let abs_b = (other ^ sb) - sb; let abs_b = (other ^ sb) - sb;
let two = Self::one() + Self::one(); let two = Self::ONE + Self::ONE;
if abs_a < two || abs_b < two { if abs_a < two || abs_b < two {
return result; return result;
} }

View File

@ -3,9 +3,9 @@ use int::Int;
trait Div: Int { trait Div: Int {
/// Returns `a / b` /// Returns `a / b`
fn div(self, other: Self) -> Self { fn div(self, other: Self) -> Self {
let s_a = self >> (Self::bits() - 1); let s_a = self >> (Self::BITS - 1);
let s_b = other >> (Self::bits() - 1); let s_b = other >> (Self::BITS - 1);
// NOTE it's OK to overflow here because of the `as $uty` cast below // NOTE it's OK to overflow here because of the `.unsigned()` below.
// This whole operation is computing the absolute value of the inputs // This whole operation is computing the absolute value of the inputs
// So some overflow will happen when dealing with e.g. `i64::MIN` // So some overflow will happen when dealing with e.g. `i64::MIN`
// where the absolute value is `(-i64::MIN) as u64` // where the absolute value is `(-i64::MIN) as u64`
@ -25,10 +25,10 @@ impl Div for i128 {}
trait Mod: Int { trait Mod: Int {
/// Returns `a % b` /// Returns `a % b`
fn mod_(self, other: Self) -> Self { fn mod_(self, other: Self) -> Self {
let s = other >> (Self::bits() - 1); let s = other >> (Self::BITS - 1);
// NOTE(wrapping_sub) see comment in the `div` // NOTE(wrapping_sub) see comment in the `div`
let b = (other ^ s).wrapping_sub(s); let b = (other ^ s).wrapping_sub(s);
let s = self >> (Self::bits() - 1); let s = self >> (Self::BITS - 1);
let a = (self ^ s).wrapping_sub(s); let a = (self ^ s).wrapping_sub(s);
let r = a.unsigned().aborting_rem(b.unsigned()); let r = a.unsigned().aborting_rem(b.unsigned());

View File

@ -1,13 +1,13 @@
use int::{Int, LargeInt}; use int::{Int, LargeInt};
trait Ashl: Int + LargeInt { trait Ashl: Int + LargeInt {
/// Returns `a << b`, requires `b < $ty::bits()` /// Returns `a << b`, requires `b < Self::BITS`
fn ashl(self, offset: u32) -> Self fn ashl(self, offset: u32) -> Self
where Self: LargeInt<HighHalf = <Self as LargeInt>::LowHalf>, where Self: LargeInt<HighHalf = <Self as LargeInt>::LowHalf>,
{ {
let half_bits = Self::bits() / 2; let half_bits = Self::BITS / 2;
if offset & half_bits != 0 { if offset & half_bits != 0 {
Self::from_parts(Int::zero(), self.low() << (offset - half_bits)) Self::from_parts(Int::ZERO, self.low() << (offset - half_bits))
} else if offset == 0 { } else if offset == 0 {
self self
} else { } else {
@ -22,11 +22,11 @@ impl Ashl for u64 {}
impl Ashl for u128 {} impl Ashl for u128 {}
trait Ashr: Int + LargeInt { trait Ashr: Int + LargeInt {
/// Returns arithmetic `a >> b`, requires `b < $ty::bits()` /// Returns arithmetic `a >> b`, requires `b < Self::BITS`
fn ashr(self, offset: u32) -> Self fn ashr(self, offset: u32) -> Self
where Self: LargeInt<LowHalf = <<Self as LargeInt>::HighHalf as Int>::UnsignedInt>, where Self: LargeInt<LowHalf = <<Self as LargeInt>::HighHalf as Int>::UnsignedInt>,
{ {
let half_bits = Self::bits() / 2; let half_bits = Self::BITS / 2;
if offset & half_bits != 0 { if offset & half_bits != 0 {
Self::from_parts((self.high() >> (offset - half_bits)).unsigned(), Self::from_parts((self.high() >> (offset - half_bits)).unsigned(),
self.high() >> (half_bits - 1)) self.high() >> (half_bits - 1))
@ -44,13 +44,13 @@ impl Ashr for i64 {}
impl Ashr for i128 {} impl Ashr for i128 {}
trait Lshr: Int + LargeInt { trait Lshr: Int + LargeInt {
/// Returns logical `a >> b`, requires `b < $ty::bits()` /// Returns logical `a >> b`, requires `b < Self::BITS`
fn lshr(self, offset: u32) -> Self fn lshr(self, offset: u32) -> Self
where Self: LargeInt<HighHalf = <Self as LargeInt>::LowHalf>, where Self: LargeInt<HighHalf = <Self as LargeInt>::LowHalf>,
{ {
let half_bits = Self::bits() / 2; let half_bits = Self::BITS / 2;
if offset & half_bits != 0 { if offset & half_bits != 0 {
Self::from_parts(self.high() >> (offset - half_bits), Int::zero()) Self::from_parts(self.high() >> (offset - half_bits), Int::ZERO)
} else if offset == 0 { } else if offset == 0 {
self self
} else { } else {

View File

@ -63,7 +63,7 @@ macro_rules! udivmod_inner {
sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros());
// D > N // D > N
if sr > <hty!($ty)>::bits() - 2 { if sr > <hty!($ty)>::BITS - 2 {
if let Some(rem) = rem { if let Some(rem) = rem {
*rem = n; *rem = n;
} }
@ -72,8 +72,8 @@ macro_rules! udivmod_inner {
sr += 1; sr += 1;
// 1 <= sr <= <hty!($ty)>::bits() - 1 // 1 <= sr <= <hty!($ty)>::BITS - 1
q = n << (<$ty>::bits() - sr); q = n << (<$ty>::BITS - sr);
r = n >> sr; r = n >> sr;
} else if d.high() == 0 { } else if d.high() == 0 {
// K X // K X
@ -92,10 +92,10 @@ macro_rules! udivmod_inner {
}; };
} }
sr = 1 + <hty!($ty)>::bits() + d.low().leading_zeros() - n.high().leading_zeros(); sr = 1 + <hty!($ty)>::BITS + d.low().leading_zeros() - n.high().leading_zeros();
// 2 <= sr <= u64::bits() - 1 // 2 <= sr <= u64::BITS - 1
q = n << (<$ty>::bits() - sr); q = n << (<$ty>::BITS - sr);
r = n >> sr; r = n >> sr;
} else { } else {
// K X // K X
@ -104,7 +104,7 @@ macro_rules! udivmod_inner {
sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros());
// D > N // D > N
if sr > <hty!($ty)>::bits() - 1 { if sr > <hty!($ty)>::BITS - 1 {
if let Some(rem) = rem { if let Some(rem) = rem {
*rem = n; *rem = n;
} }
@ -113,16 +113,16 @@ macro_rules! udivmod_inner {
sr += 1; sr += 1;
// 1 <= sr <= <hty!($ty)>::bits() // 1 <= sr <= <hty!($ty)>::BITS
q = n << (<$ty>::bits() - sr); q = n << (<$ty>::BITS - sr);
r = n >> sr; r = n >> sr;
} }
// Not a special case // Not a special case
// q and r are initialized with // q and r are initialized with
// q = n << (u64::bits() - sr) // q = n << (u64::BITS - sr)
// r = n >> sr // r = n >> sr
// 1 <= sr <= u64::bits() - 1 // 1 <= sr <= u64::BITS - 1
let mut carry = 0; let mut carry = 0;
// Don't use a range because they may generate references to memcpy in unoptimized code // Don't use a range because they may generate references to memcpy in unoptimized code
@ -131,7 +131,7 @@ macro_rules! udivmod_inner {
i += 1; i += 1;
// r:q = ((r:q) << 1) | carry // r:q = ((r:q) << 1) | carry
r = (r << 1) | (q >> (<$ty>::bits() - 1)); r = (r << 1) | (q >> (<$ty>::BITS - 1));
q = (q << 1) | carry as $ty; q = (q << 1) | carry as $ty;
// carry = 0 // carry = 0
@ -139,7 +139,7 @@ macro_rules! udivmod_inner {
// r -= d; // r -= d;
// carry = 1; // carry = 1;
// } // }
let s = (d.wrapping_sub(r).wrapping_sub(1)) as os_ty!($ty) >> (<$ty>::bits() - 1); let s = (d.wrapping_sub(r).wrapping_sub(1)) as os_ty!($ty) >> (<$ty>::BITS - 1);
carry = (s & 1) as hty!($ty); carry = (s & 1) as hty!($ty);
r -= d & s as $ty; r -= d & s as $ty;
} }
@ -169,19 +169,19 @@ intrinsics! {
let mut sr = d.leading_zeros().wrapping_sub(n.leading_zeros()); let mut sr = d.leading_zeros().wrapping_sub(n.leading_zeros());
// d > n // d > n
if sr > u32::bits() - 1 { if sr > u32::BITS - 1 {
return 0; return 0;
} }
// d == 1 // d == 1
if sr == u32::bits() - 1 { if sr == u32::BITS - 1 {
return n; return n;
} }
sr += 1; sr += 1;
// 1 <= sr <= u32::bits() - 1 // 1 <= sr <= u32::BITS - 1
let mut q = n << (u32::bits() - sr); let mut q = n << (u32::BITS - sr);
let mut r = n >> sr; let mut r = n >> sr;
let mut carry = 0; let mut carry = 0;
@ -192,7 +192,7 @@ intrinsics! {
i += 1; i += 1;
// r:q = ((r:q) << 1) | carry // r:q = ((r:q) << 1) | carry
r = (r << 1) | (q >> (u32::bits() - 1)); r = (r << 1) | (q >> (u32::BITS - 1));
q = (q << 1) | carry; q = (q << 1) | carry;
// carry = 0; // carry = 0;
@ -201,7 +201,7 @@ intrinsics! {
// carry = 1; // carry = 1;
// } // }
let s = (d.wrapping_sub(r).wrapping_sub(1)) as i32 >> (u32::bits() - 1); let s = (d.wrapping_sub(r).wrapping_sub(1)) as i32 >> (u32::BITS - 1);
carry = (s & 1) as u32; carry = (s & 1) as u32;
r -= d & s as u32; r -= d & s as u32;
} }