| use core::ops; |
| |
| macro_rules! hty { |
| ($ty:ty) => { |
| <$ty as LargeInt>::HighHalf |
| }; |
| } |
| |
| macro_rules! os_ty { |
| ($ty:ty) => { |
| <$ty as Int>::OtherSign |
| }; |
| } |
| |
| pub mod addsub; |
| pub mod mul; |
| pub mod sdiv; |
| pub mod shift; |
| pub mod udiv; |
| |
| /// Trait for some basic operations on integers |
| pub trait Int: |
| Copy |
| + PartialEq |
| + PartialOrd |
| + ops::AddAssign |
| + ops::BitAndAssign |
| + ops::BitOrAssign |
| + ops::ShlAssign<i32> |
| + ops::ShrAssign<u32> |
| + ops::Add<Output = Self> |
| + ops::Sub<Output = Self> |
| + ops::Div<Output = Self> |
| + ops::Shl<u32, Output = Self> |
| + ops::Shr<u32, Output = Self> |
| + ops::BitOr<Output = Self> |
| + ops::BitXor<Output = Self> |
| + ops::BitAnd<Output = Self> |
| + ops::Not<Output = Self> |
| { |
| /// Type with the same width but other signedness |
| type OtherSign: Int; |
| /// Unsigned version of Self |
| type UnsignedInt: Int; |
| |
| /// The bitwidth of the int type |
| const BITS: u32; |
| |
| const ZERO: Self; |
| const ONE: Self; |
| |
| /// Extracts the sign from self and returns a tuple. |
| /// |
| /// # Examples |
| /// |
| /// ```rust,ignore |
| /// let i = -25_i32; |
| /// let (sign, u) = i.extract_sign(); |
| /// assert_eq!(sign, true); |
| /// assert_eq!(u, 25_u32); |
| /// ``` |
| fn extract_sign(self) -> (bool, Self::UnsignedInt); |
| |
| fn unsigned(self) -> Self::UnsignedInt; |
| fn from_unsigned(unsigned: Self::UnsignedInt) -> Self; |
| |
| fn from_bool(b: bool) -> Self; |
| |
| // copied from primitive integers, but put in a trait |
| fn max_value() -> Self; |
| fn min_value() -> Self; |
| fn wrapping_add(self, other: Self) -> Self; |
| fn wrapping_mul(self, other: Self) -> Self; |
| fn wrapping_sub(self, other: Self) -> Self; |
| fn wrapping_shl(self, other: u32) -> Self; |
| fn overflowing_add(self, other: Self) -> (Self, bool); |
| fn aborting_div(self, other: Self) -> Self; |
| fn aborting_rem(self, other: Self) -> Self; |
| fn leading_zeros(self) -> u32; |
| } |
| |
| fn unwrap<T>(t: Option<T>) -> T { |
| match t { |
| Some(t) => t, |
| None => ::abort(), |
| } |
| } |
| |
| macro_rules! int_impl_common { |
| ($ty:ty, $bits:expr) => { |
| const BITS: u32 = $bits; |
| |
| const ZERO: Self = 0; |
| const ONE: Self = 1; |
| |
| fn from_bool(b: bool) -> Self { |
| b as $ty |
| } |
| |
| fn max_value() -> Self { |
| <Self>::max_value() |
| } |
| |
| fn min_value() -> Self { |
| <Self>::min_value() |
| } |
| |
| fn wrapping_add(self, other: Self) -> Self { |
| <Self>::wrapping_add(self, other) |
| } |
| |
| fn wrapping_mul(self, other: Self) -> Self { |
| <Self>::wrapping_mul(self, other) |
| } |
| |
| fn wrapping_sub(self, other: Self) -> Self { |
| <Self>::wrapping_sub(self, other) |
| } |
| |
| fn wrapping_shl(self, other: u32) -> Self { |
| <Self>::wrapping_shl(self, other) |
| } |
| |
| fn overflowing_add(self, other: Self) -> (Self, bool) { |
| <Self>::overflowing_add(self, other) |
| } |
| |
| fn aborting_div(self, other: Self) -> Self { |
| unwrap(<Self>::checked_div(self, other)) |
| } |
| |
| fn aborting_rem(self, other: Self) -> Self { |
| unwrap(<Self>::checked_rem(self, other)) |
| } |
| |
| fn leading_zeros(self) -> u32 { |
| <Self>::leading_zeros(self) |
| } |
| } |
| } |
| |
| macro_rules! int_impl { |
| ($ity:ty, $uty:ty, $bits:expr) => { |
| impl Int for $uty { |
| type OtherSign = $ity; |
| type UnsignedInt = $uty; |
| |
| fn extract_sign(self) -> (bool, $uty) { |
| (false, self) |
| } |
| |
| fn unsigned(self) -> $uty { |
| self |
| } |
| |
| fn from_unsigned(me: $uty) -> Self { |
| me |
| } |
| |
| int_impl_common!($uty, $bits); |
| } |
| |
| impl Int for $ity { |
| type OtherSign = $uty; |
| type UnsignedInt = $uty; |
| |
| fn extract_sign(self) -> (bool, $uty) { |
| if self < 0 { |
| (true, (!(self as $uty)).wrapping_add(1)) |
| } else { |
| (false, self as $uty) |
| } |
| } |
| |
| fn unsigned(self) -> $uty { |
| self as $uty |
| } |
| |
| fn from_unsigned(me: $uty) -> Self { |
| me as $ity |
| } |
| |
| int_impl_common!($ity, $bits); |
| } |
| }; |
| } |
| |
| int_impl!(i32, u32, 32); |
| int_impl!(i64, u64, 64); |
| int_impl!(i128, u128, 128); |
| |
| /// Trait to convert an integer to/from smaller parts |
| pub trait LargeInt: Int { |
| type LowHalf: Int; |
| type HighHalf: Int; |
| |
| fn low(self) -> Self::LowHalf; |
| fn low_as_high(low: Self::LowHalf) -> Self::HighHalf; |
| fn high(self) -> Self::HighHalf; |
| fn high_as_low(low: Self::HighHalf) -> Self::LowHalf; |
| fn from_parts(low: Self::LowHalf, high: Self::HighHalf) -> Self; |
| } |
| |
| macro_rules! large_int { |
| ($ty:ty, $tylow:ty, $tyhigh:ty, $halfbits:expr) => { |
| impl LargeInt for $ty { |
| type LowHalf = $tylow; |
| type HighHalf = $tyhigh; |
| |
| fn low(self) -> $tylow { |
| self as $tylow |
| } |
| fn low_as_high(low: $tylow) -> $tyhigh { |
| low as $tyhigh |
| } |
| fn high(self) -> $tyhigh { |
| (self >> $halfbits) as $tyhigh |
| } |
| fn high_as_low(high: $tyhigh) -> $tylow { |
| high as $tylow |
| } |
| fn from_parts(low: $tylow, high: $tyhigh) -> $ty { |
| low as $ty | ((high as $ty) << $halfbits) |
| } |
| } |
| }; |
| } |
| |
| large_int!(u64, u32, u32, 32); |
| large_int!(i64, u32, i32, 32); |
| large_int!(u128, u64, u64, 64); |
| large_int!(i128, u64, i64, 64); |
| |
| /// Trait to express (possibly lossy) casting of integers |
| pub trait CastInto<T: Copy>: Copy { |
| fn cast(self) -> T; |
| } |
| |
| macro_rules! cast_into { |
| ($ty:ty) => { |
| cast_into!($ty; usize, isize, u32, i32, u64, i64, u128, i128); |
| }; |
| ($ty:ty; $($into:ty),*) => {$( |
| impl CastInto<$into> for $ty { |
| fn cast(self) -> $into { |
| self as $into |
| } |
| } |
| )*}; |
| } |
| |
| cast_into!(u32); |
| cast_into!(i32); |
| cast_into!(u64); |
| cast_into!(i64); |
| cast_into!(u128); |
| cast_into!(i128); |
| |
| pub trait WideInt: Int { |
| type Output: Int; |
| |
| fn wide_mul(self, other: Self) -> (Self, Self); |
| fn wide_shift_left(&mut self, low: &mut Self, count: i32); |
| fn wide_shift_right_with_sticky(&mut self, low: &mut Self, count: i32); |
| } |
| |
| macro_rules! impl_wide_int { |
| ($ty:ty, $tywide:ty, $bits:expr) => { |
| impl WideInt for $ty { |
| type Output = $ty; |
| |
| fn wide_mul(self, other: Self) -> (Self, Self) { |
| let product = (self as $tywide).wrapping_mul(other as $tywide); |
| ((product >> ($bits as $ty)) as $ty, product as $ty) |
| } |
| |
| fn wide_shift_left(&mut self, low: &mut Self, count: i32) { |
| *self = (*self << count) | (*low >> ($bits - count)); |
| *low = *low << count; |
| } |
| |
| fn wide_shift_right_with_sticky(&mut self, low: &mut Self, count: i32) { |
| if count < $bits { |
| let sticky = *low << ($bits - count); |
| *low = *self << ($bits - count) | *low >> count | sticky; |
| *self = *self >> count; |
| } else if count < 2 * $bits { |
| let sticky = *self << (2 * $bits - count) | *low; |
| *low = *self >> (count - $bits) | sticky; |
| *self = 0; |
| } else { |
| let sticky = *self | *low; |
| *self = sticky; |
| *self = 0; |
| } |
| } |
| } |
| }; |
| } |
| |
| impl_wide_int!(u32, u64, 32); |
| impl_wide_int!(u64, u128, 64); |
| |
| intrinsics! { |
| #[maybe_use_optimized_c_shim] |
| #[cfg(any( |
| target_pointer_width = "16", |
| target_pointer_width = "32", |
| target_pointer_width = "64" |
| ))] |
| pub extern "C" fn __clzsi2(x: usize) -> usize { |
| // TODO: const this? Would require const-if |
| // Note(Lokathor): the `intrinsics!` macro can't process mut inputs |
| let mut x = x; |
| let mut y: usize; |
| let mut n: usize = { |
| #[cfg(target_pointer_width = "64")] |
| { |
| 64 |
| } |
| #[cfg(target_pointer_width = "32")] |
| { |
| 32 |
| } |
| #[cfg(target_pointer_width = "16")] |
| { |
| 16 |
| } |
| }; |
| #[cfg(target_pointer_width = "64")] |
| { |
| y = x >> 32; |
| if y != 0 { |
| n -= 32; |
| x = y; |
| } |
| } |
| #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] |
| { |
| y = x >> 16; |
| if y != 0 { |
| n -= 16; |
| x = y; |
| } |
| } |
| y = x >> 8; |
| if y != 0 { |
| n -= 8; |
| x = y; |
| } |
| y = x >> 4; |
| if y != 0 { |
| n -= 4; |
| x = y; |
| } |
| y = x >> 2; |
| if y != 0 { |
| n -= 2; |
| x = y; |
| } |
| y = x >> 1; |
| if y != 0 { |
| n - 2 |
| } else { |
| n - x |
| } |
| } |
| } |