use int::Int;
use std;
#[cfg(RUSTC_IS_NIGHTLY)]
#[allow(dead_code)]
extern "C" {
#[link_name="llvm.bitreverse.i8"]
fn bitrev_i8(i: i8) -> i8;
#[link_name="llvm.bitreverse.i16"]
fn bitrev_i16(i: i16) -> i16;
#[link_name="llvm.bitreverse.i32"]
fn bitrev_i32(i: i32) -> i32;
#[link_name="llvm.bitreverse.i64"]
fn bitrev_i64(i: i64) -> i64;
}
#[allow(dead_code)]
#[inline]
fn bitreverse_unsigned<T: Int>(y: T) -> T {
let mut x = y;
let width = T::byte_size();
let k = T::bit_size() - T::from_u32(1);
{
let mut up0 = |i, l, r| if k & i > T::from_u32(0) {
x = ((x & l).wrapping_shl(i)) | ((x & r).wrapping_shr(i));
};
up0(T::from_u32(1),
T::from_u64(0x5555555555555555u64),
T::from_u64(0xAAAAAAAAAAAAAAAAu64));
up0(T::from_u32(2),
T::from_u64(0x3333333333333333u64),
T::from_u64(0xCCCCCCCCCCCCCCCCu64));
up0(T::from_u32(4),
T::from_u64(0x0F0F0F0F0F0F0F0Fu64),
T::from_u64(0xF0F0F0F0F0F0F0F0u64));
}
{
let mut up1 = |i, s, l, r| if width > i && (k & s > T::from_u32(0)) {
x = ((x & l).wrapping_shl(s)) | ((x & r).wrapping_shr(s));
};
up1(T::from_u32(1),
T::from_u32(8),
T::from_u64(0x00FF00FF00FF00FFu64),
T::from_u64(0xFF00FF00FF00FF00u64));
up1(T::from_u32(2),
T::from_u32(16),
T::from_u64(0x0000FFFF0000FFFFu64),
T::from_u64(0xFFFF0000FFFF0000u64));
up1(T::from_u32(4),
T::from_u32(32),
T::from_u64(0x00000000FFFFFFFFu64),
T::from_u64(0xFFFFFFFF00000000u64));
}
x
}
#[allow(dead_code)]
#[inline]
fn bitreverse<T: Int>(y: T) -> T {
T::from_unsigned(bitreverse_unsigned(y.to_unsigned()))
}
#[allow(dead_code)]
#[inline]
fn bitreverse_u8(i: u8) -> u8 {
(((i as u64).wrapping_mul(0x80200802u64) & 0x0884422110u64)
.wrapping_mul(0x0101010101u64)
.wrapping_shr(32)) as u8
}
#[inline]
fn bitreverse_i8(i: i8) -> i8 {
#[cfg(RUSTC_IS_NIGHTLY)]
{
bitreverse_u8(i as u8) as i8
}
#[cfg(not(RUSTC_IS_NIGHTLY))]
{
bitreverse_u8(i as u8) as i8
}
}
#[inline]
fn bitreverse_i16(i: i16) -> i16 {
#[cfg(RUSTC_IS_NIGHTLY)]
{
unsafe { bitrev_i16(i) }
}
#[cfg(not(RUSTC_IS_NIGHTLY))]
{
bitreverse(i)
}
}
#[inline]
fn bitreverse_i32(i: i32) -> i32 {
#[cfg(RUSTC_IS_NIGHTLY)]
{
unsafe { bitrev_i32(i) }
}
#[cfg(not(RUSTC_IS_NIGHTLY))]
{
bitreverse(i)
}
}
#[inline]
fn bitreverse_i64(i: i64) -> i64 {
#[cfg(RUSTC_IS_NIGHTLY)]
{
unsafe { bitrev_i64(i) }
}
#[cfg(not(RUSTC_IS_NIGHTLY))]
{
bitreverse(i)
}
}
pub trait RBit: Sized {
#[inline]
fn rbit(self) -> Self;
}
impl RBit for i8 {
#[inline]
fn rbit(self) -> i8 {
bitreverse_i8(self)
}
}
impl RBit for i16 {
#[inline]
fn rbit(self) -> i16 {
bitreverse_i16(self)
}
}
impl RBit for i32 {
#[inline]
fn rbit(self) -> i32 {
bitreverse_i32(self)
}
}
impl RBit for i64 {
#[inline]
fn rbit(self) -> i64 {
bitreverse_i64(self)
}
}
impl RBit for isize {
#[inline]
fn rbit(self) -> isize {
match std::mem::size_of::<isize>() {
32 => bitreverse_i32(self as i32) as isize,
64 => bitreverse_i64(self as i64) as isize,
_ => unreachable!(),
}
}
}
impl RBit for u8 {
#[inline]
fn rbit(self) -> u8 {
(self as i8).rbit() as u8
}
}
impl RBit for u16 {
#[inline]
fn rbit(self) -> u16 {
(self as i16).rbit() as u16
}
}
impl RBit for u32 {
#[inline]
fn rbit(self) -> u32 {
(self as i32).rbit() as u32
}
}
impl RBit for u64 {
#[inline]
fn rbit(self) -> u64 {
(self as i64).rbit() as u64
}
}
impl RBit for usize {
#[inline]
fn rbit(self) -> usize {
(self as isize).rbit() as usize
}
}
#[inline]
pub fn rbit<T: RBit>(y: T) -> T {
y.rbit()
}
#[cfg(test)]
mod tests {
use arm;
use int::Int;
use std::fmt::Debug;
use alg::arm::v7::RBit;
#[cfg(RUSTC_IS_NIGHTLY)]
use super::bitreverse;
fn rbit_invariant<T: RBit + Int + Debug>(i: T) {
let j = arm::v7::rbit(i);
assert_eq!(i, arm::v7::rbit(j));
}
#[test]
fn rbit_u8() {
(0..u8::max_value())
.map(|x| {
rbit_invariant(x);
rbit_invariant(x as i8)
})
.count();
#[cfg(RUSTC_IS_NIGHTLY)]
{
(0..u8::max_value())
.map(|x| {
assert_eq!(arm::v7::rbit(x), bitreverse(x));
x
})
.count();
}
}
#[test]
fn rbit_u16() {
(0..u16::max_value())
.map(|x| {
rbit_invariant(x);
rbit_invariant(x as i16)
})
.count();
#[cfg(RUSTC_IS_NIGHTLY)]
{
(0..u16::max_value())
.map(|x| {
assert_eq!(arm::v7::rbit(x), bitreverse(x));
x
})
.count();
}
}
#[test]
fn rbit_u32() {
(0..u32::max_value())
.take(1000000)
.map(|x| {
rbit_invariant(x);
rbit_invariant(x as i32)
})
.count();
#[cfg(RUSTC_IS_NIGHTLY)]
{
(0..u32::max_value())
.take(1000000)
.map(|x| {
assert_eq!(arm::v7::rbit(x), bitreverse(x));
x
})
.count();
}
}
#[test]
fn rbit_u64() {
(0..u64::max_value())
.take(1000000)
.map(|x| {
rbit_invariant(x);
rbit_invariant(x as i64)
})
.count();
#[cfg(RUSTC_IS_NIGHTLY)]
{
(0..u64::max_value())
.take(1000000)
.map(|x| {
assert_eq!(arm::v7::rbit(x), bitreverse(x));
x
})
.count();
}
}
#[test]
fn rbit_tests() {
use arm::v7::rbit;
{
let o_u8 = 0b1101_0011u8;
let r_u8 = 0b1100_1011u8;
assert_eq!(o_u8, 211);
assert_eq!(r_u8, 203);
assert_eq!(rbit(o_u8), r_u8);
assert_eq!(rbit(o_u8 as i8), r_u8 as i8);
}
{
let o_u16 = 0b1101_0011_1110_1010u16;
let r_u16 = 0b0101_0111_1100_1011u16;
assert_eq!(rbit(o_u16), r_u16);
assert_eq!(rbit(o_u16 as i16), r_u16 as i16);
}
{
let o_u32 = 0b1101_0011_1110_1010_1101_0011_1010_1010u32;
let r_u32 = 0b0101_0101_1100_1011_0101_0111_1100_1011u32;
assert_eq!(rbit(o_u32), r_u32);
assert_eq!(rbit(o_u32 as i32), r_u32 as i32);
}
{
let o_u64 = 0b1101_0011_0010_1010_1111_0011_1010_1010_1101_0011_1110_1010_1101_0011_1010_1010u64;
let r_u64 = 0b0101_0101_1100_1011_0101_0111_1100_1011_0101_0101_1100_1111_0101_0100_1100_1011u64;
assert_eq!(rbit(o_u64), r_u64);
assert_eq!(rbit(o_u64 as i64), r_u64 as i64);
}
}
}