Skip to content

Commit 502426f

Browse files
committed
PrimInt: add fallback for reverse_bits on rustc<1.37
1 parent 9c6f148 commit 502426f

File tree

2 files changed

+39
-1
lines changed

2 files changed

+39
-1
lines changed

build.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,7 @@ fn main() {
1616
"has_to_int_unchecked",
1717
);
1818

19+
ac.emit_expression_cfg("1u32.reverse_bits()", "has_reverse_bits");
20+
1921
autocfg::rerun_path("build.rs");
2022
}

src/int.rs

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,9 @@ pub trait PrimInt:
234234
/// assert_eq!(n.reverse_bits(), m);
235235
/// assert_eq!(0u32.reverse_bits(), 0);
236236
/// ```
237-
fn reverse_bits(self) -> Self;
237+
fn reverse_bits(self) -> Self {
238+
reverse_bits_fallback(self)
239+
}
238240

239241
/// Convert an integer from big endian to the target's endianness.
240242
///
@@ -324,6 +326,39 @@ pub trait PrimInt:
324326
fn pow(self, exp: u32) -> Self;
325327
}
326328

329+
fn one_per_byte<P: PrimInt>() -> P {
330+
// i8, u8: return 0x01
331+
// i16, u16: return 0x0101 = (0x01 << 8) | 0x01
332+
// i32, u32: return 0x01010101 = (0x0101 << 16) | 0x0101
333+
// ...
334+
let mut ret = P::one();
335+
let mut shift = 8;
336+
let mut b = ret.count_zeros() >> 3;
337+
while b != 0 {
338+
ret = (ret << shift) | ret;
339+
shift <<= 1;
340+
b >>= 1;
341+
}
342+
ret
343+
}
344+
345+
fn reverse_bits_fallback<P: PrimInt>(i: P) -> P {
346+
let rep_01: P = one_per_byte();
347+
let rep_03 = (rep_01 << 1) | rep_01;
348+
let rep_05 = (rep_01 << 2) | rep_01;
349+
let rep_0f = (rep_03 << 2) | rep_03;
350+
let rep_33 = (rep_03 << 4) | rep_03;
351+
let rep_55 = (rep_05 << 4) | rep_05;
352+
353+
// code above only used to determine rep_0f, rep_33, rep_55;
354+
// optimizer should be able to do it in compile time
355+
let mut ret = i.swap_bytes();
356+
ret = ((ret & rep_0f) << 4) | ((ret >> 4) & rep_0f);
357+
ret = ((ret & rep_33) << 2) | ((ret >> 2) & rep_33);
358+
ret = ((ret & rep_55) << 1) | ((ret >> 1) & rep_55);
359+
ret
360+
}
361+
327362
macro_rules! prim_int_impl {
328363
($T:ty, $S:ty, $U:ty) => {
329364
impl PrimInt for $T {
@@ -382,6 +417,7 @@ macro_rules! prim_int_impl {
382417
<$T>::swap_bytes(self)
383418
}
384419

420+
#[cfg(has_reverse_bits)]
385421
#[inline]
386422
fn reverse_bits(self) -> Self {
387423
<$T>::reverse_bits(self)

0 commit comments

Comments
 (0)