@@ -250,6 +250,26 @@ pub trait PrimInt:
250
250
/// ```
251
251
fn swap_bytes ( self ) -> Self ;
252
252
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
+
253
273
/// Convert an integer from big endian to the target's endianness.
254
274
///
255
275
/// On big endian this is a no-op. On little endian the bytes are swapped.
@@ -338,6 +358,39 @@ pub trait PrimInt:
338
358
fn pow ( self , exp : u32 ) -> Self ;
339
359
}
340
360
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
+
341
394
macro_rules! prim_int_impl {
342
395
( $T: ty, $S: ty, $U: ty) => {
343
396
impl PrimInt for $T {
@@ -408,6 +461,12 @@ macro_rules! prim_int_impl {
408
461
<$T>:: swap_bytes( self )
409
462
}
410
463
464
+ #[ cfg( has_reverse_bits) ]
465
+ #[ inline]
466
+ fn reverse_bits( self ) -> Self {
467
+ <$T>:: reverse_bits( self )
468
+ }
469
+
411
470
#[ inline]
412
471
fn from_be( x: Self ) -> Self {
413
472
<$T>:: from_be( x)
@@ -451,3 +510,59 @@ prim_int_impl!(i64, i64, u64);
451
510
#[ cfg( has_i128) ]
452
511
prim_int_impl ! ( i128 , i128 , u128 ) ;
453
512
prim_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