From abb51f9a0909839c5f4a4c25c7d65241c6b0dcd7 Mon Sep 17 00:00:00 2001 From: Ed McCardell Date: Sun, 2 Sep 2018 00:51:04 -0400 Subject: [PATCH] Add wrapping shifts Add traits `WrappingShl` and `WrappingShr` corresponding to the standard library `wrapping_shl` and `wrapping_shr` methods. Implement the trait on all primitive integer types as well as on `Wrapping`. --- src/lib.rs | 2 +- src/ops/wrapping.rs | 121 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 121 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c1c7327..5a25bab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -39,7 +39,7 @@ pub use ops::checked::{ pub use ops::inv::Inv; pub use ops::mul_add::{MulAdd, MulAddAssign}; pub use ops::saturating::Saturating; -pub use ops::wrapping::{WrappingAdd, WrappingMul, WrappingSub}; +pub use ops::wrapping::{WrappingAdd, WrappingMul, WrappingShl, WrappingShr, WrappingSub}; pub use pow::{checked_pow, pow, Pow}; pub use sign::{abs, abs_sub, signum, Signed, Unsigned}; diff --git a/src/ops/wrapping.rs b/src/ops/wrapping.rs index bab70b2..5ce16af 100644 --- a/src/ops/wrapping.rs +++ b/src/ops/wrapping.rs @@ -1,5 +1,5 @@ use core::num::Wrapping; -use core::ops::{Add, Mul, Sub}; +use core::ops::{Add, Mul, Shl, Shr, Sub}; macro_rules! wrapping_impl { ($trait_name:ident, $method:ident, $t:ty) => { @@ -89,6 +89,87 @@ wrapping_impl!(WrappingMul, wrapping_mul, isize); #[cfg(has_i128)] wrapping_impl!(WrappingMul, wrapping_mul, i128); +macro_rules! wrapping_shift_impl { + ($trait_name:ident, $method:ident, $t:ty) => { + impl $trait_name for $t { + #[inline] + fn $method(&self, rhs: u32) -> $t { + <$t>::$method(*self, rhs) + } + } + }; +} + +/// Performs a left shift that does not panic. +pub trait WrappingShl: Sized + Shl { + /// Panic-free bitwise shift-left; yields `self << mask(rhs)`, + /// where `mask` removes any high order bits of `rhs` that would + /// cause the shift to exceed the bitwidth of the type. + /// + /// ``` + /// use num_traits::WrappingShl; + /// + /// let x: u16 = 0x0001; + /// + /// assert_eq!(WrappingShl::wrapping_shl(&x, 0), 0x0001); + /// assert_eq!(WrappingShl::wrapping_shl(&x, 1), 0x0002); + /// assert_eq!(WrappingShl::wrapping_shl(&x, 15), 0x8000); + /// assert_eq!(WrappingShl::wrapping_shl(&x, 16), 0x0001); + /// ``` + fn wrapping_shl(&self, rhs: u32) -> Self; +} + +wrapping_shift_impl!(WrappingShl, wrapping_shl, u8); +wrapping_shift_impl!(WrappingShl, wrapping_shl, u16); +wrapping_shift_impl!(WrappingShl, wrapping_shl, u32); +wrapping_shift_impl!(WrappingShl, wrapping_shl, u64); +wrapping_shift_impl!(WrappingShl, wrapping_shl, usize); +#[cfg(has_i128)] +wrapping_shift_impl!(WrappingShl, wrapping_shl, u128); + +wrapping_shift_impl!(WrappingShl, wrapping_shl, i8); +wrapping_shift_impl!(WrappingShl, wrapping_shl, i16); +wrapping_shift_impl!(WrappingShl, wrapping_shl, i32); +wrapping_shift_impl!(WrappingShl, wrapping_shl, i64); +wrapping_shift_impl!(WrappingShl, wrapping_shl, isize); +#[cfg(has_i128)] +wrapping_shift_impl!(WrappingShl, wrapping_shl, i128); + +/// Performs a right shift that does not panic. +pub trait WrappingShr: Sized + Shr { + /// Panic-free bitwise shift-right; yields `self >> mask(rhs)`, + /// where `mask` removes any high order bits of `rhs` that would + /// cause the shift to exceed the bitwidth of the type. + /// + /// ``` + /// use num_traits::WrappingShr; + /// + /// let x: u16 = 0x8000; + /// + /// assert_eq!(WrappingShr::wrapping_shr(&x, 0), 0x8000); + /// assert_eq!(WrappingShr::wrapping_shr(&x, 1), 0x4000); + /// assert_eq!(WrappingShr::wrapping_shr(&x, 15), 0x0001); + /// assert_eq!(WrappingShr::wrapping_shr(&x, 16), 0x8000); + /// ``` + fn wrapping_shr(&self, rhs: u32) -> Self; +} + +wrapping_shift_impl!(WrappingShr, wrapping_shr, u8); +wrapping_shift_impl!(WrappingShr, wrapping_shr, u16); +wrapping_shift_impl!(WrappingShr, wrapping_shr, u32); +wrapping_shift_impl!(WrappingShr, wrapping_shr, u64); +wrapping_shift_impl!(WrappingShr, wrapping_shr, usize); +#[cfg(has_i128)] +wrapping_shift_impl!(WrappingShr, wrapping_shr, u128); + +wrapping_shift_impl!(WrappingShr, wrapping_shr, i8); +wrapping_shift_impl!(WrappingShr, wrapping_shr, i16); +wrapping_shift_impl!(WrappingShr, wrapping_shr, i32); +wrapping_shift_impl!(WrappingShr, wrapping_shr, i64); +wrapping_shift_impl!(WrappingShr, wrapping_shr, isize); +#[cfg(has_i128)] +wrapping_shift_impl!(WrappingShr, wrapping_shr, i128); + // Well this is a bit funny, but all the more appropriate. impl WrappingAdd for Wrapping where @@ -114,6 +195,22 @@ where Wrapping(self.0.wrapping_mul(&v.0)) } } +impl WrappingShl for Wrapping +where + Wrapping: Shl>, +{ + fn wrapping_shl(&self, rhs: u32) -> Self { + Wrapping(self.0.wrapping_shl(rhs)) + } +} +impl WrappingShr for Wrapping +where + Wrapping: Shr>, +{ + fn wrapping_shr(&self, rhs: u32) -> Self { + Wrapping(self.0.wrapping_shr(rhs)) + } +} #[test] fn test_wrapping_traits() { @@ -126,12 +223,22 @@ fn test_wrapping_traits() { fn wrapping_mul(a: T, b: T) -> T { a.wrapping_mul(&b) } + fn wrapping_shl(a: T, b: u32) -> T { + a.wrapping_shl(b) + } + fn wrapping_shr(a: T, b: u32) -> T { + a.wrapping_shr(b) + } assert_eq!(wrapping_add(255, 1), 0u8); assert_eq!(wrapping_sub(0, 1), 255u8); assert_eq!(wrapping_mul(255, 2), 254u8); + assert_eq!(wrapping_shl(255, 8), 255u8); + assert_eq!(wrapping_shr(255, 8), 255u8); assert_eq!(wrapping_add(255, 1), (Wrapping(255u8) + Wrapping(1u8)).0); assert_eq!(wrapping_sub(0, 1), (Wrapping(0u8) - Wrapping(1u8)).0); assert_eq!(wrapping_mul(255, 2), (Wrapping(255u8) * Wrapping(2u8)).0); + assert_eq!(wrapping_shl(255, 8), (Wrapping(255u8) << 8).0); + assert_eq!(wrapping_shr(255, 8), (Wrapping(255u8) >> 8).0); } #[test] @@ -151,3 +258,15 @@ fn wrapping_is_wrappingmul() { fn require_wrappingmul(_: &T) {} require_wrappingmul(&Wrapping(42)); } + +#[test] +fn wrapping_is_wrappingshl() { + fn require_wrappingshl(_: &T) {} + require_wrappingshl(&Wrapping(42)); +} + +#[test] +fn wrapping_is_wrappingshr() { + fn require_wrappingshr(_: &T) {} + require_wrappingshr(&Wrapping(42)); +}