Ver Fonte

Add saturating_mul() and refactor Saturating into subtraits. Fixes #40.

Tom Repetti há 5 anos atrás
pai
commit
052e765df0
3 ficheiros alterados com 109 adições e 22 exclusões
  1. 4 2
      src/int.rs
  2. 3 1
      src/lib.rs
  3. 102 19
      src/ops/saturating.rs

+ 4 - 2
src/int.rs

@@ -2,7 +2,7 @@ use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr};
 
 use bounds::Bounded;
 use ops::checked::*;
-use ops::saturating::Saturating;
+use ops::saturating::*;
 use {Num, NumCast};
 
 /// Generic trait for primitive integers.
@@ -50,7 +50,9 @@ pub trait PrimInt:
     + CheckedSub<Output = Self>
     + CheckedMul<Output = Self>
     + CheckedDiv<Output = Self>
-    + Saturating
+    + SaturatingAdd
+    + SaturatingSub
+    + SaturatingMul
 {
     /// Returns the number of ones in the binary representation of `self`.
     ///

+ 3 - 1
src/lib.rs

@@ -42,7 +42,9 @@ pub use ops::checked::{
 };
 pub use ops::inv::Inv;
 pub use ops::mul_add::{MulAdd, MulAddAssign};
-pub use ops::saturating::Saturating;
+pub use ops::saturating::{
+    SaturatingAdd, SaturatingMul, SaturatingSub,
+};
 pub use ops::wrapping::{
     WrappingAdd, WrappingMul, WrappingNeg, WrappingShl, WrappingShr, WrappingSub,
 };

+ 102 - 19
src/ops/saturating.rs

@@ -1,30 +1,113 @@
-/// Saturating math operations
-pub trait Saturating {
-    /// Saturating addition operator.
-    /// Returns a+b, saturating at the numeric bounds instead of overflowing.
-    fn saturating_add(self, v: Self) -> Self;
-
-    /// Saturating subtraction operator.
-    /// Returns a-b, saturating at the numeric bounds instead of overflowing.
-    fn saturating_sub(self, v: Self) -> Self;
-}
+use core::ops::{Add, Mul, Sub};
 
 macro_rules! saturating_impl {
-    ($trait_name:ident for $($t:ty)*) => {$(
+    ($trait_name:ident, $method:ident, $t:ty) => {
         impl $trait_name for $t {
             #[inline]
-            fn saturating_add(self, v: Self) -> Self {
-                Self::saturating_add(self, v)
+            fn $method(&self, v: &Self) -> Self {
+                <$t>::$method(*self, *v)
             }
-
+        }
+    };
+    ($trait_name:ident, $method:ident, $t:ty, $rhs:ty) => {
+        impl $trait_name<$rhs> for $t {
             #[inline]
-            fn saturating_sub(self, v: Self) -> Self {
-                Self::saturating_sub(self, v)
+            fn $method(&self, v: &$rhs) -> Self {
+                <$t>::$method(*self, *v)
             }
         }
-    )*}
+    };
+}
+
+/// Performs addition that saturates high on overflow and low on underflow.
+pub trait SaturatingAdd: Sized + Add<Self, Output = Self> {
+    /// Saturating addition. Computes `self + other`, saturating at the relevant high or low boundary of
+    /// the type.
+    fn saturating_add(&self, v: &Self) -> Self;
+}
+
+saturating_impl!(SaturatingAdd, saturating_add, u8);
+saturating_impl!(SaturatingAdd, saturating_add, u16);
+saturating_impl!(SaturatingAdd, saturating_add, u32);
+saturating_impl!(SaturatingAdd, saturating_add, u64);
+saturating_impl!(SaturatingAdd, saturating_add, usize);
+#[cfg(has_i128)]
+saturating_impl!(SaturatingAdd, saturating_add, u128);
+
+saturating_impl!(SaturatingAdd, saturating_add, i8);
+saturating_impl!(SaturatingAdd, saturating_add, i16);
+saturating_impl!(SaturatingAdd, saturating_add, i32);
+saturating_impl!(SaturatingAdd, saturating_add, i64);
+saturating_impl!(SaturatingAdd, saturating_add, isize);
+#[cfg(has_i128)]
+saturating_impl!(SaturatingAdd, saturating_add, i128);
+
+/// Performs subtraction that saturates high on overflow and low on underflow.
+pub trait SaturatingSub: Sized + Sub<Self, Output = Self> {
+    /// Saturating subtraction. Computes `self - other`, saturating at the relevant high or low boundary of
+    /// the type.
+    fn saturating_sub(&self, v: &Self) -> Self;
 }
 
-saturating_impl!(Saturating for isize usize i8 u8 i16 u16 i32 u32 i64 u64);
+saturating_impl!(SaturatingSub, saturating_sub, u8);
+saturating_impl!(SaturatingSub, saturating_sub, u16);
+saturating_impl!(SaturatingSub, saturating_sub, u32);
+saturating_impl!(SaturatingSub, saturating_sub, u64);
+saturating_impl!(SaturatingSub, saturating_sub, usize);
 #[cfg(has_i128)]
-saturating_impl!(Saturating for i128 u128);
+saturating_impl!(SaturatingSub, saturating_sub, u128);
+
+saturating_impl!(SaturatingSub, saturating_sub, i8);
+saturating_impl!(SaturatingSub, saturating_sub, i16);
+saturating_impl!(SaturatingSub, saturating_sub, i32);
+saturating_impl!(SaturatingSub, saturating_sub, i64);
+saturating_impl!(SaturatingSub, saturating_sub, isize);
+#[cfg(has_i128)]
+saturating_impl!(SaturatingSub, saturating_sub, i128);
+
+/// Performs subtraction that saturates high on overflow and low on underflow.
+pub trait SaturatingMul: Sized + Mul<Self, Output = Self> {
+    /// Saturating multiplication. Computes `self * other`, saturating at the relevant high or low boundary of
+    /// the type.
+    fn saturating_mul(&self, v: &Self) -> Self;
+}
+
+saturating_impl!(SaturatingMul, saturating_mul, u8);
+saturating_impl!(SaturatingMul, saturating_mul, u16);
+saturating_impl!(SaturatingMul, saturating_mul, u32);
+saturating_impl!(SaturatingMul, saturating_mul, u64);
+saturating_impl!(SaturatingMul, saturating_mul, usize);
+#[cfg(has_i128)]
+saturating_impl!(SaturatingMul, saturating_mul, u128);
+
+saturating_impl!(SaturatingMul, saturating_mul, i8);
+saturating_impl!(SaturatingMul, saturating_mul, i16);
+saturating_impl!(SaturatingMul, saturating_mul, i32);
+saturating_impl!(SaturatingMul, saturating_mul, i64);
+saturating_impl!(SaturatingMul, saturating_mul, isize);
+#[cfg(has_i128)]
+saturating_impl!(SaturatingMul, saturating_mul, i128);
+
+// TODO: add SaturatingNeg for signed integer primitives once the saturating_neg() API is stable.
+
+#[test]
+fn test_saturating_traits() {
+    fn saturating_add<T: SaturatingAdd>(a: T, b: T) -> T {
+        a.saturating_add(&b)
+    }
+    fn saturating_sub<T: SaturatingSub>(a: T, b: T) -> T {
+        a.saturating_sub(&b)
+    }
+    fn saturating_mul<T: SaturatingMul>(a: T, b: T) -> T {
+        a.saturating_mul(&b)
+    }
+    assert_eq!(saturating_add(255, 1), 255u8);
+    assert_eq!(saturating_add(127, 1), 127i8);
+    assert_eq!(saturating_add(-128, -1), -128i8);
+    assert_eq!(saturating_sub(0, 1), 0u8);
+    assert_eq!(saturating_sub(-128, 1), -128i8);
+    assert_eq!(saturating_sub(127, -1), 127i8);
+    assert_eq!(saturating_mul(255, 2), 255u8);
+    assert_eq!(saturating_mul(127, 2), 127i8);
+    assert_eq!(saturating_mul(-128, 2), -128i8);
+}