From 5c01e93ead23363926ff9899b4d452ed56bc2c24 Mon Sep 17 00:00:00 2001 From: Daniel Lehmann Date: Mon, 23 Oct 2023 20:27:43 -0700 Subject: [PATCH] Addressed comments --- src/lib.rs | 72 ++++++++++++------------------------------------------ 1 file changed, 16 insertions(+), 56 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 6e8aa80..fe985e3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -378,6 +378,10 @@ macro_rules! uint_impl { }; Self { + // We could use wrapping_shl here to make Debug builds slightly smaller; + // the downside would be that on weird CPUs that don't do wrapping_shl by + // default release builds would get slightly worse. Using << should give + // good release performance everywere value: (self.value << shift_amount) & Self::MASK, } } @@ -422,7 +426,8 @@ macro_rules! uint_impl { pub const fn saturating_mul(self, rhs: Self) -> Self { let product = if BITS << 1 <= (core::mem::size_of::<$type>() << 3) { // We have half the bits (e.g. u4 * u4) of the base type, so we can't overflow the base type - self.value * rhs.value + // wrapping_mul likely provides the best performance on all cpus + self.value.wrapping_mul(rhs.value) } else { // We have more than half the bits (e.g. u6 * u6) self.value.saturating_mul(rhs.value) @@ -533,10 +538,7 @@ where + BitAnd + Not + Add - + Sub - + Shr - + Shl - + From, + + Sub, { type Output = UInt; @@ -562,9 +564,6 @@ where + AddAssign + BitAnd + BitAndAssign - + Sub - + Shr - + Shl + From, { fn add_assign(&mut self, rhs: Self) { @@ -580,12 +579,7 @@ where impl Sub for UInt where Self: Number, - T: Copy - + BitAnd - + Sub - + Shl - + Shr - + From, + T: Copy + BitAnd + Sub, { type Output = UInt; @@ -600,14 +594,7 @@ where impl SubAssign for UInt where Self: Number, - T: Copy - + SubAssign - + BitAnd - + BitAndAssign - + Sub - + Shl - + Shr - + From, + T: Copy + SubAssign + BitAnd + BitAndAssign + Sub, { fn sub_assign(&mut self, rhs: Self) { // No need for extra overflow checking as the regular minus operator already handles it for us @@ -619,19 +606,14 @@ where impl Mul for UInt where Self: Number, - T: PartialEq - + Copy - + BitAnd - + Not - + Mul - + Sub - + Shr - + Shl - + From, + T: PartialEq + Copy + BitAnd + Not + Mul, { type Output = UInt; fn mul(self, rhs: Self) -> Self::Output { + // In debug builds, this will perform two bounds checks: Initial multiplication, followed by + // our bounds check. As wrapping_mul isn't available as a trait bound (in regular Rust), this + // is unavoidable let product = self.value * rhs.value; #[cfg(debug_assertions)] if (product & !Self::MASK) != T::from(0) { @@ -652,11 +634,7 @@ where + Copy + MulAssign + BitAnd - + BitAndAssign - + Sub - + Shr - + Shl - + From, + + BitAndAssign, { fn mul_assign(&mut self, rhs: Self) { self.value *= rhs.value; @@ -671,15 +649,7 @@ where impl Div for UInt where Self: Number, - T: PartialEq - + Copy - + BitAnd - + Not - + Div - + Sub - + Shr - + Shl - + From, + T: PartialEq + Div, { type Output = UInt; @@ -695,17 +665,7 @@ where impl DivAssign for UInt where Self: Number, - T: PartialEq - + Eq - + Not - + Copy - + DivAssign - + BitAnd - + BitAndAssign - + Sub - + Shr - + Shl - + From, + T: PartialEq + DivAssign, { fn div_assign(&mut self, rhs: Self) { self.value /= rhs.value;