]> git.lizzy.rs Git - rust.git/commitdiff
Add Bitwise::{swap_bytes, rotate_left, rotate_right} methods
authorBrendan Zabarauskas <bjzaba@yahoo.com.au>
Fri, 13 Jun 2014 04:19:17 +0000 (21:19 -0700)
committerBrendan Zabarauskas <bjzaba@yahoo.com.au>
Fri, 13 Jun 2014 16:28:32 +0000 (09:28 -0700)
src/libcore/num/int_macros.rs
src/libcore/num/mod.rs
src/libcore/num/uint_macros.rs

index 445ac248cd67f58431805cfc7f5c96f00a65e2f5..20bb12db694c0f1dcfbe5c1229ab26771829ffb0 100644 (file)
@@ -113,6 +113,33 @@ fn test_count_zeros() {
         assert!((0b1111001 as $T).count_zeros() == BITS as $T - 5);
     }
 
+    #[test]
+    fn test_swap_bytes() {
+        let n: $T = 0b0101100; assert_eq!(n.swap_bytes().swap_bytes(), n);
+        let n: $T = 0b0100001; assert_eq!(n.swap_bytes().swap_bytes(), n);
+        let n: $T = 0b1111001; assert_eq!(n.swap_bytes().swap_bytes(), n);
+
+        // Swapping these should make no difference
+        let n: $T = 0;   assert_eq!(n.swap_bytes(), n);
+        let n: $T = -1;  assert_eq!(n.swap_bytes(), n);
+    }
+
+    #[test]
+    fn test_rotate() {
+        let n: $T = 0b0101100; assert_eq!(n.rotate_left(6).rotate_right(2).rotate_right(4), n);
+        let n: $T = 0b0100001; assert_eq!(n.rotate_left(3).rotate_left(2).rotate_right(5),  n);
+        let n: $T = 0b1111001; assert_eq!(n.rotate_left(6).rotate_right(2).rotate_right(4), n);
+
+        // Rotating these should make no difference
+        //
+        // We test using 124 bits because to ensure that overlong bit shifts do
+        // not cause undefined behaviour. See #10183.
+        let n: $T = 0;   assert_eq!(n.rotate_left(124), n);
+        let n: $T = -1;  assert_eq!(n.rotate_left(124), n);
+        let n: $T = 0;   assert_eq!(n.rotate_right(124), n);
+        let n: $T = -1;  assert_eq!(n.rotate_right(124), n);
+    }
+
     #[test]
     fn test_signed_checked_div() {
         assert!(10i.checked_div(&2) == Some(5));
index 3a847004df909aa88bf2b761cc18f334ae5288dd..eaa632be6d04c42fe749f39c1b5267fe945890de 100644 (file)
@@ -436,57 +436,135 @@ fn count_zeros(&self) -> Self {
     /// assert_eq!(n.trailing_zeros(), 3);
     /// ```
     fn trailing_zeros(&self) -> Self;
+
+    /// Reverses the byte order of a binary number.
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// use std::num::Bitwise;
+    ///
+    /// let n = 0x0123456789ABCDEFu64;
+    /// let m = 0xEFCDAB8967452301u64;
+    /// assert_eq!(n.swap_bytes(), m);
+    /// ```
+    fn swap_bytes(&self) -> Self;
+
+    /// Shifts the bits to the left by a specified amount amount, `r`, wrapping
+    /// the truncated bits to the end of the resulting value.
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// use std::num::Bitwise;
+    ///
+    /// let n = 0x0123456789ABCDEFu64;
+    /// let m = 0x3456789ABCDEF012u64;
+    /// assert_eq!(n.rotate_left(12), m);
+    /// ```
+    fn rotate_left(&self, r: uint) -> Self;
+
+    /// Shifts the bits to the right by a specified amount amount, `r`, wrapping
+    /// the truncated bits to the beginning of the resulting value.
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// use std::num::Bitwise;
+    ///
+    /// let n = 0x0123456789ABCDEFu64;
+    /// let m = 0xDEF0123456789ABCu64;
+    /// assert_eq!(n.rotate_right(12), m);
+    /// ```
+    fn rotate_right(&self, r: uint) -> Self;
 }
 
+/// Swapping a single byte does nothing. This is unsafe to be consistent with
+/// the other `bswap` intrinsics.
+#[inline]
+unsafe fn bswap8(x: u8) -> u8 { x }
+
 macro_rules! bitwise_impl(
-    ($t:ty, $co:path, $lz:path, $tz:path) => {
+    ($t:ty, $bits:expr, $co:ident, $lz:ident, $tz:ident, $bs:path) => {
         impl Bitwise for $t {
             #[inline]
-            fn count_ones(&self) -> $t { unsafe { $co(*self) } }
+            fn count_ones(&self) -> $t { unsafe { intrinsics::$co(*self) } }
 
             #[inline]
-            fn leading_zeros(&self) -> $t { unsafe { $lz(*self) } }
+            fn leading_zeros(&self) -> $t { unsafe { intrinsics::$lz(*self) } }
 
             #[inline]
-            fn trailing_zeros(&self) -> $t { unsafe { $tz(*self) } }
+            fn trailing_zeros(&self) -> $t { unsafe { intrinsics::$tz(*self) } }
+
+            #[inline]
+            fn swap_bytes(&self) -> $t { unsafe { $bs(*self) } }
+
+            #[inline]
+            fn rotate_left(&self, r: uint) -> $t {
+                // Protect against undefined behaviour for overlong bit shifts
+                let r = r % $bits;
+                (*self << r) | (*self >> ($bits - r))
+            }
+
+            #[inline]
+            fn rotate_right(&self, r: uint) -> $t {
+                // Protect against undefined behaviour for overlong bit shifts
+                let r = r % $bits;
+                (*self >> r) | (*self << ($bits - r))
+            }
         }
     }
 )
 
 macro_rules! bitwise_cast_impl(
-    ($t:ty, $t_cast:ty,  $co:path, $lz:path, $tz:path) => {
+    ($t:ty, $t_cast:ty, $bits:expr,  $co:ident, $lz:ident, $tz:ident, $bs:path) => {
         impl Bitwise for $t {
             #[inline]
-            fn count_ones(&self) -> $t { unsafe { $co(*self as $t_cast) as $t } }
+            fn count_ones(&self) -> $t { unsafe { intrinsics::$co(*self as $t_cast) as $t } }
+
+            #[inline]
+            fn leading_zeros(&self) -> $t { unsafe { intrinsics::$lz(*self as $t_cast) as $t } }
+
+            #[inline]
+            fn trailing_zeros(&self) -> $t { unsafe { intrinsics::$tz(*self as $t_cast) as $t } }
 
             #[inline]
-            fn leading_zeros(&self) -> $t { unsafe { $lz(*self as $t_cast) as $t } }
+            fn swap_bytes(&self) -> $t { unsafe { $bs(*self as $t_cast) as $t } }
 
             #[inline]
-            fn trailing_zeros(&self) -> $t { unsafe { $tz(*self as $t_cast) as $t } }
+            fn rotate_left(&self, r: uint) -> $t {
+                // cast to prevent the sign bit from being corrupted
+                (*self as $t_cast).rotate_left(r) as $t
+            }
+
+            #[inline]
+            fn rotate_right(&self, r: uint) -> $t {
+                // cast to prevent the sign bit from being corrupted
+                (*self as $t_cast).rotate_right(r) as $t
+            }
         }
     }
 )
 
 #[cfg(target_word_size = "32")]
-bitwise_cast_impl!(uint, u32, intrinsics::ctpop32, intrinsics::ctlz32, intrinsics::cttz32)
+bitwise_cast_impl!(uint, u32, 32, ctpop32, ctlz32, cttz32, intrinsics::bswap32)
 #[cfg(target_word_size = "64")]
-bitwise_cast_impl!(uint, u64, intrinsics::ctpop64, intrinsics::ctlz64, intrinsics::cttz64)
+bitwise_cast_impl!(uint, u64, 64, ctpop64, ctlz64, cttz64, intrinsics::bswap64)
 
-bitwise_impl!(u8, intrinsics::ctpop8, intrinsics::ctlz8, intrinsics::cttz8)
-bitwise_impl!(u16, intrinsics::ctpop16, intrinsics::ctlz16, intrinsics::cttz16)
-bitwise_impl!(u32, intrinsics::ctpop32, intrinsics::ctlz32, intrinsics::cttz32)
-bitwise_impl!(u64, intrinsics::ctpop64, intrinsics::ctlz64, intrinsics::cttz64)
+bitwise_impl!(u8, 8, ctpop8, ctlz8, cttz8, bswap8)
+bitwise_impl!(u16, 16, ctpop16, ctlz16, cttz16, intrinsics::bswap16)
+bitwise_impl!(u32, 32, ctpop32, ctlz32, cttz32, intrinsics::bswap32)
+bitwise_impl!(u64, 64, ctpop64, ctlz64, cttz64, intrinsics::bswap64)
 
 #[cfg(target_word_size = "32")]
-bitwise_cast_impl!(int, u32, intrinsics::ctpop32, intrinsics::ctlz32, intrinsics::cttz32)
+bitwise_cast_impl!(int, u32, 32, ctpop32, ctlz32, cttz32, intrinsics::bswap32)
 #[cfg(target_word_size = "64")]
-bitwise_cast_impl!(int, u64, intrinsics::ctpop64, intrinsics::ctlz64, intrinsics::cttz64)
+bitwise_cast_impl!(int, u64, 64, ctpop64, ctlz64, cttz64, intrinsics::bswap64)
 
-bitwise_cast_impl!(i8, u8, intrinsics::ctpop8, intrinsics::ctlz8, intrinsics::cttz8)
-bitwise_cast_impl!(i16, u16, intrinsics::ctpop16, intrinsics::ctlz16, intrinsics::cttz16)
-bitwise_cast_impl!(i32, u32, intrinsics::ctpop32, intrinsics::ctlz32, intrinsics::cttz32)
-bitwise_cast_impl!(i64, u64, intrinsics::ctpop64, intrinsics::ctlz64, intrinsics::cttz64)
+bitwise_cast_impl!(i8, u8, 8, ctpop8, ctlz8, cttz8, bswap8)
+bitwise_cast_impl!(i16, u16, 16, ctpop16, ctlz16, cttz16, intrinsics::bswap16)
+bitwise_cast_impl!(i32, u32, 32, ctpop32, ctlz32, cttz32, intrinsics::bswap32)
+bitwise_cast_impl!(i64, u64, 64, ctpop64, ctlz64, cttz64, intrinsics::bswap64)
 
 /// Specifies the available operations common to all of Rust's core numeric primitives.
 /// These may not always make sense from a purely mathematical point of view, but
index 0e094b9ec31435ed453bcffb4f3b4ad9a27805cf..8e4ba10154244958dc6cef41e0c10af6f62e2c73 100644 (file)
@@ -64,6 +64,33 @@ fn test_count_zeros() {
         assert!((0b1111001 as $T).count_zeros() == BITS as $T - 5);
     }
 
+    #[test]
+    fn test_swap_bytes() {
+        let n: $T = 0b0101100; assert_eq!(n.swap_bytes().swap_bytes(), n);
+        let n: $T = 0b0100001; assert_eq!(n.swap_bytes().swap_bytes(), n);
+        let n: $T = 0b1111001; assert_eq!(n.swap_bytes().swap_bytes(), n);
+
+        // Swapping these should make no difference
+        let n: $T = 0;   assert_eq!(n.swap_bytes(), n);
+        let n: $T = MAX; assert_eq!(n.swap_bytes(), n);
+    }
+
+    #[test]
+    fn test_rotate() {
+        let n: $T = 0b0101100; assert_eq!(n.rotate_left(6).rotate_right(2).rotate_right(4), n);
+        let n: $T = 0b0100001; assert_eq!(n.rotate_left(3).rotate_left(2).rotate_right(5),  n);
+        let n: $T = 0b1111001; assert_eq!(n.rotate_left(6).rotate_right(2).rotate_right(4), n);
+
+        // Rotating these should make no difference
+        //
+        // We test using 124 bits because to ensure that overlong bit shifts do
+        // not cause undefined behaviour. See #10183.
+        let n: $T = 0;   assert_eq!(n.rotate_left(124), n);
+        let n: $T = MAX; assert_eq!(n.rotate_left(124), n);
+        let n: $T = 0;   assert_eq!(n.rotate_right(124), n);
+        let n: $T = MAX; assert_eq!(n.rotate_right(124), n);
+    }
+
     #[test]
     fn test_unsigned_checked_div() {
         assert!(10u.checked_div(&2) == Some(5));