@@ -250,6 +250,26 @@ pub trait PrimInt:
250250 /// ```
251251 fn swap_bytes ( self ) -> Self ;
252252
253+ /// Reverses the order of bits in the integer.
254+ ///
255+ /// The least significant bit becomes the most significant bit, second least-significant bit
256+ /// becomes second most-significant bit, etc.
257+ ///
258+ /// # Examples
259+ ///
260+ /// ```
261+ /// use num_traits::PrimInt;
262+ ///
263+ /// let n = 0x12345678u32;
264+ /// let m = 0x1e6a2c48u32;
265+ ///
266+ /// assert_eq!(n.reverse_bits(), m);
267+ /// assert_eq!(0u32.reverse_bits(), 0);
268+ /// ```
269+ fn reverse_bits ( self ) -> Self {
270+ reverse_bits_fallback ( self )
271+ }
272+
253273 /// Convert an integer from big endian to the target's endianness.
254274 ///
255275 /// On big endian this is a no-op. On little endian the bytes are swapped.
@@ -338,6 +358,39 @@ pub trait PrimInt:
338358 fn pow ( self , exp : u32 ) -> Self ;
339359}
340360
361+ fn one_per_byte < P : PrimInt > ( ) -> P {
362+ // i8, u8: return 0x01
363+ // i16, u16: return 0x0101 = (0x01 << 8) | 0x01
364+ // i32, u32: return 0x01010101 = (0x0101 << 16) | 0x0101
365+ // ...
366+ let mut ret = P :: one ( ) ;
367+ let mut shift = 8 ;
368+ let mut b = ret. count_zeros ( ) >> 3 ;
369+ while b != 0 {
370+ ret = ( ret << shift) | ret;
371+ shift <<= 1 ;
372+ b >>= 1 ;
373+ }
374+ ret
375+ }
376+
377+ fn reverse_bits_fallback < P : PrimInt > ( i : P ) -> P {
378+ let rep_01: P = one_per_byte ( ) ;
379+ let rep_03 = ( rep_01 << 1 ) | rep_01;
380+ let rep_05 = ( rep_01 << 2 ) | rep_01;
381+ let rep_0f = ( rep_03 << 2 ) | rep_03;
382+ let rep_33 = ( rep_03 << 4 ) | rep_03;
383+ let rep_55 = ( rep_05 << 4 ) | rep_05;
384+
385+ // code above only used to determine rep_0f, rep_33, rep_55;
386+ // optimizer should be able to do it in compile time
387+ let mut ret = i. swap_bytes ( ) ;
388+ ret = ( ( ret & rep_0f) << 4 ) | ( ( ret >> 4 ) & rep_0f) ;
389+ ret = ( ( ret & rep_33) << 2 ) | ( ( ret >> 2 ) & rep_33) ;
390+ ret = ( ( ret & rep_55) << 1 ) | ( ( ret >> 1 ) & rep_55) ;
391+ ret
392+ }
393+
341394macro_rules! prim_int_impl {
342395 ( $T: ty, $S: ty, $U: ty) => {
343396 impl PrimInt for $T {
@@ -408,6 +461,12 @@ macro_rules! prim_int_impl {
408461 <$T>:: swap_bytes( self )
409462 }
410463
464+ #[ cfg( has_reverse_bits) ]
465+ #[ inline]
466+ fn reverse_bits( self ) -> Self {
467+ <$T>:: reverse_bits( self )
468+ }
469+
411470 #[ inline]
412471 fn from_be( x: Self ) -> Self {
413472 <$T>:: from_be( x)
@@ -451,3 +510,59 @@ prim_int_impl!(i64, i64, u64);
451510#[ cfg( has_i128) ]
452511prim_int_impl ! ( i128 , i128 , u128 ) ;
453512prim_int_impl ! ( isize , isize , usize ) ;
513+
514+ #[ cfg( test) ]
515+ mod tests {
516+ use int:: PrimInt ;
517+
518+ #[ test]
519+ pub fn reverse_bits ( ) {
520+ use core:: { i16, i32, i64, i8} ;
521+
522+ assert_eq ! (
523+ PrimInt :: reverse_bits( 0x0123_4567_89ab_cdefu64 ) ,
524+ 0xf7b3_d591_e6a2_c480
525+ ) ;
526+
527+ assert_eq ! ( PrimInt :: reverse_bits( 0i8 ) , 0 ) ;
528+ assert_eq ! ( PrimInt :: reverse_bits( -1i8 ) , -1 ) ;
529+ assert_eq ! ( PrimInt :: reverse_bits( 1i8 ) , i8 :: MIN ) ;
530+ assert_eq ! ( PrimInt :: reverse_bits( i8 :: MIN ) , 1 ) ;
531+ assert_eq ! ( PrimInt :: reverse_bits( -2i8 ) , i8 :: MAX ) ;
532+ assert_eq ! ( PrimInt :: reverse_bits( i8 :: MAX ) , -2 ) ;
533+
534+ assert_eq ! ( PrimInt :: reverse_bits( 0i16 ) , 0 ) ;
535+ assert_eq ! ( PrimInt :: reverse_bits( -1i16 ) , -1 ) ;
536+ assert_eq ! ( PrimInt :: reverse_bits( 1i16 ) , i16 :: MIN ) ;
537+ assert_eq ! ( PrimInt :: reverse_bits( i16 :: MIN ) , 1 ) ;
538+ assert_eq ! ( PrimInt :: reverse_bits( -2i16 ) , i16 :: MAX ) ;
539+ assert_eq ! ( PrimInt :: reverse_bits( i16 :: MAX ) , -2 ) ;
540+
541+ assert_eq ! ( PrimInt :: reverse_bits( 0i32 ) , 0 ) ;
542+ assert_eq ! ( PrimInt :: reverse_bits( -1i32 ) , -1 ) ;
543+ assert_eq ! ( PrimInt :: reverse_bits( 1i32 ) , i32 :: MIN ) ;
544+ assert_eq ! ( PrimInt :: reverse_bits( i32 :: MIN ) , 1 ) ;
545+ assert_eq ! ( PrimInt :: reverse_bits( -2i32 ) , i32 :: MAX ) ;
546+ assert_eq ! ( PrimInt :: reverse_bits( i32 :: MAX ) , -2 ) ;
547+
548+ assert_eq ! ( PrimInt :: reverse_bits( 0i64 ) , 0 ) ;
549+ assert_eq ! ( PrimInt :: reverse_bits( -1i64 ) , -1 ) ;
550+ assert_eq ! ( PrimInt :: reverse_bits( 1i64 ) , i64 :: MIN ) ;
551+ assert_eq ! ( PrimInt :: reverse_bits( i64 :: MIN ) , 1 ) ;
552+ assert_eq ! ( PrimInt :: reverse_bits( -2i64 ) , i64 :: MAX ) ;
553+ assert_eq ! ( PrimInt :: reverse_bits( i64 :: MAX ) , -2 ) ;
554+ }
555+
556+ #[ test]
557+ #[ cfg( has_i128) ]
558+ pub fn reverse_bits_i128 ( ) {
559+ use core:: i128;
560+
561+ assert_eq ! ( PrimInt :: reverse_bits( 0i128 ) , 0 ) ;
562+ assert_eq ! ( PrimInt :: reverse_bits( -1i128 ) , -1 ) ;
563+ assert_eq ! ( PrimInt :: reverse_bits( 1i128 ) , i128 :: MIN ) ;
564+ assert_eq ! ( PrimInt :: reverse_bits( i128 :: MIN ) , 1 ) ;
565+ assert_eq ! ( PrimInt :: reverse_bits( -2i128 ) , i128 :: MAX ) ;
566+ assert_eq ! ( PrimInt :: reverse_bits( i128 :: MAX ) , -2 ) ;
567+ }
568+ }
0 commit comments