use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr};
use crate::bounds::Bounded;
use crate::ops::checked::*;
use crate::ops::saturating::Saturating;
use crate::{Num, NumCast};
pub trait PrimInt:
Sized
+ Copy
+ Num
+ NumCast
+ Bounded
+ PartialOrd
+ Ord
+ Eq
+ Not<Output = Self>
+ BitAnd<Output = Self>
+ BitOr<Output = Self>
+ BitXor<Output = Self>
+ Shl<usize, Output = Self>
+ Shr<usize, Output = Self>
+ CheckedAdd<Output = Self>
+ CheckedSub<Output = Self>
+ CheckedMul<Output = Self>
+ CheckedDiv<Output = Self>
+ Saturating
{
fn count_ones(self) -> u32;
fn count_zeros(self) -> u32;
fn leading_ones(self) -> u32 {
(!self).leading_zeros()
}
fn leading_zeros(self) -> u32;
fn trailing_ones(self) -> u32 {
(!self).trailing_zeros()
}
fn trailing_zeros(self) -> u32;
fn rotate_left(self, n: u32) -> Self;
fn rotate_right(self, n: u32) -> Self;
fn signed_shl(self, n: u32) -> Self;
fn signed_shr(self, n: u32) -> Self;
fn unsigned_shl(self, n: u32) -> Self;
fn unsigned_shr(self, n: u32) -> Self;
fn swap_bytes(self) -> Self;
fn reverse_bits(self) -> Self {
reverse_bits_fallback(self)
}
fn from_be(x: Self) -> Self;
fn from_le(x: Self) -> Self;
fn to_be(self) -> Self;
fn to_le(self) -> Self;
fn pow(self, exp: u32) -> Self;
}
fn one_per_byte<P: PrimInt>() -> P {
let mut ret = P::one();
let mut shift = 8;
let mut b = ret.count_zeros() >> 3;
while b != 0 {
ret = (ret << shift) | ret;
shift <<= 1;
b >>= 1;
}
ret
}
fn reverse_bits_fallback<P: PrimInt>(i: P) -> P {
let rep_01: P = one_per_byte();
let rep_03 = (rep_01 << 1) | rep_01;
let rep_05 = (rep_01 << 2) | rep_01;
let rep_0f = (rep_03 << 2) | rep_03;
let rep_33 = (rep_03 << 4) | rep_03;
let rep_55 = (rep_05 << 4) | rep_05;
let mut ret = i.swap_bytes();
ret = ((ret & rep_0f) << 4) | ((ret >> 4) & rep_0f);
ret = ((ret & rep_33) << 2) | ((ret >> 2) & rep_33);
ret = ((ret & rep_55) << 1) | ((ret >> 1) & rep_55);
ret
}
macro_rules! prim_int_impl {
($T:ty, $S:ty, $U:ty) => {
impl PrimInt for $T {
#[inline]
fn count_ones(self) -> u32 {
<$T>::count_ones(self)
}
#[inline]
fn count_zeros(self) -> u32 {
<$T>::count_zeros(self)
}
#[inline]
fn leading_ones(self) -> u32 {
<$T>::leading_ones(self)
}
#[inline]
fn leading_zeros(self) -> u32 {
<$T>::leading_zeros(self)
}
#[inline]
fn trailing_ones(self) -> u32 {
<$T>::trailing_ones(self)
}
#[inline]
fn trailing_zeros(self) -> u32 {
<$T>::trailing_zeros(self)
}
#[inline]
fn rotate_left(self, n: u32) -> Self {
<$T>::rotate_left(self, n)
}
#[inline]
fn rotate_right(self, n: u32) -> Self {
<$T>::rotate_right(self, n)
}
#[inline]
fn signed_shl(self, n: u32) -> Self {
((self as $S) << n) as $T
}
#[inline]
fn signed_shr(self, n: u32) -> Self {
((self as $S) >> n) as $T
}
#[inline]
fn unsigned_shl(self, n: u32) -> Self {
((self as $U) << n) as $T
}
#[inline]
fn unsigned_shr(self, n: u32) -> Self {
((self as $U) >> n) as $T
}
#[inline]
fn swap_bytes(self) -> Self {
<$T>::swap_bytes(self)
}
#[inline]
fn reverse_bits(self) -> Self {
<$T>::reverse_bits(self)
}
#[inline]
fn from_be(x: Self) -> Self {
<$T>::from_be(x)
}
#[inline]
fn from_le(x: Self) -> Self {
<$T>::from_le(x)
}
#[inline]
fn to_be(self) -> Self {
<$T>::to_be(self)
}
#[inline]
fn to_le(self) -> Self {
<$T>::to_le(self)
}
#[inline]
fn pow(self, exp: u32) -> Self {
<$T>::pow(self, exp)
}
}
};
}
prim_int_impl!(u8, i8, u8);
prim_int_impl!(u16, i16, u16);
prim_int_impl!(u32, i32, u32);
prim_int_impl!(u64, i64, u64);
prim_int_impl!(u128, i128, u128);
prim_int_impl!(usize, isize, usize);
prim_int_impl!(i8, i8, u8);
prim_int_impl!(i16, i16, u16);
prim_int_impl!(i32, i32, u32);
prim_int_impl!(i64, i64, u64);
prim_int_impl!(i128, i128, u128);
prim_int_impl!(isize, isize, usize);
#[cfg(test)]
mod tests {
use crate::int::PrimInt;
#[test]
pub fn reverse_bits() {
use core::{i16, i32, i64, i8};
assert_eq!(
PrimInt::reverse_bits(0x0123_4567_89ab_cdefu64),
0xf7b3_d591_e6a2_c480
);
assert_eq!(PrimInt::reverse_bits(0i8), 0);
assert_eq!(PrimInt::reverse_bits(-1i8), -1);
assert_eq!(PrimInt::reverse_bits(1i8), i8::MIN);
assert_eq!(PrimInt::reverse_bits(i8::MIN), 1);
assert_eq!(PrimInt::reverse_bits(-2i8), i8::MAX);
assert_eq!(PrimInt::reverse_bits(i8::MAX), -2);
assert_eq!(PrimInt::reverse_bits(0i16), 0);
assert_eq!(PrimInt::reverse_bits(-1i16), -1);
assert_eq!(PrimInt::reverse_bits(1i16), i16::MIN);
assert_eq!(PrimInt::reverse_bits(i16::MIN), 1);
assert_eq!(PrimInt::reverse_bits(-2i16), i16::MAX);
assert_eq!(PrimInt::reverse_bits(i16::MAX), -2);
assert_eq!(PrimInt::reverse_bits(0i32), 0);
assert_eq!(PrimInt::reverse_bits(-1i32), -1);
assert_eq!(PrimInt::reverse_bits(1i32), i32::MIN);
assert_eq!(PrimInt::reverse_bits(i32::MIN), 1);
assert_eq!(PrimInt::reverse_bits(-2i32), i32::MAX);
assert_eq!(PrimInt::reverse_bits(i32::MAX), -2);
assert_eq!(PrimInt::reverse_bits(0i64), 0);
assert_eq!(PrimInt::reverse_bits(-1i64), -1);
assert_eq!(PrimInt::reverse_bits(1i64), i64::MIN);
assert_eq!(PrimInt::reverse_bits(i64::MIN), 1);
assert_eq!(PrimInt::reverse_bits(-2i64), i64::MAX);
assert_eq!(PrimInt::reverse_bits(i64::MAX), -2);
}
#[test]
pub fn reverse_bits_i128() {
use core::i128;
assert_eq!(PrimInt::reverse_bits(0i128), 0);
assert_eq!(PrimInt::reverse_bits(-1i128), -1);
assert_eq!(PrimInt::reverse_bits(1i128), i128::MIN);
assert_eq!(PrimInt::reverse_bits(i128::MIN), 1);
assert_eq!(PrimInt::reverse_bits(-2i128), i128::MAX);
assert_eq!(PrimInt::reverse_bits(i128::MAX), -2);
}
}