From df1d2f6eb5e94e57180573a5096e37424df98035 Mon Sep 17 00:00:00 2001 From: yancy Date: Sat, 3 Feb 2024 12:03:49 +0100 Subject: [PATCH] Add unchecked variants to Amount and SignedAmount The checked variants have worse performance than the unchecked variants due to the additional branching operations. To improve performance where overflow is either not possible or not a concern, unchecked variants of Amount and SignedAmount are introduced. --- units/src/amount.rs | 57 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/units/src/amount.rs b/units/src/amount.rs index 92f6ef76..0b5979bb 100644 --- a/units/src/amount.rs +++ b/units/src/amount.rs @@ -864,6 +864,21 @@ impl Amount { /// Returns [None] if overflow occurred. pub fn checked_rem(self, rhs: u64) -> Option { self.0.checked_rem(rhs).map(Amount) } + /// Unchecked addition. + /// + /// + /// Computes `self + rhs`. Panics in debug mode, wraps in release mode. + pub fn unchecked_add(self, rhs: Amount) -> Amount { + Self(self.0 + rhs.0) + } + + /// Unchecked subtraction. + /// + /// Computes `self - rhs`. Panics in debug mode, wraps in release mode. + pub fn unchecked_sub(self, rhs: Amount) -> Amount { + Self(self.0 - rhs.0) + } + /// Convert to a signed amount. pub fn to_signed(self) -> Result { if self.to_sat() > SignedAmount::MAX.to_sat() as u64 { @@ -1229,6 +1244,20 @@ impl SignedAmount { self.0.checked_rem(rhs).map(SignedAmount) } + /// Unchecked addition. + /// + /// Computes `self + rhs`. Panics in debug mode, wraps in release mode. + pub fn unchecked_add(self, rhs: SignedAmount) -> SignedAmount { + Self(self.0 + rhs.0) + } + + /// Unchecked subtraction. + /// + /// Computes `self - rhs`. Panics in debug mode, wraps in release mode. + pub fn unchecked_sub(self, rhs: SignedAmount) -> SignedAmount { + Self(self.0 - rhs.0) + } + /// Subtraction that doesn't allow negative [SignedAmount]s. /// Returns [None] if either [self], `rhs` or the result is strictly negative. pub fn positive_sub(self, rhs: SignedAmount) -> Option { @@ -1878,6 +1907,34 @@ mod tests { assert_eq!(ssat(-6).checked_div(2), Some(ssat(-3))); } + #[test] + #[cfg(not(debug_assertions))] + fn unchecked_amount_add() { + let amt = Amount::MAX.unchecked_add(Amount::ONE_SAT); + assert_eq!(amt, Amount::ZERO); + } + + #[test] + #[cfg(not(debug_assertions))] + fn unchecked_signed_amount_add() { + let signed_amt = SignedAmount::MAX.unchecked_add(SignedAmount::ONE_SAT); + assert_eq!(signed_amt, SignedAmount::MIN); + } + + #[test] + #[cfg(not(debug_assertions))] + fn unchecked_amount_subtract() { + let amt = Amount::ZERO.unchecked_sub(Amount::ONE_SAT); + assert_eq!(amt, Amount::MAX); + } + + #[test] + #[cfg(not(debug_assertions))] + fn unchecked_signed_amount_subtract() { + let signed_amt = SignedAmount::MIN.unchecked_sub(SignedAmount::ONE_SAT); + assert_eq!(signed_amt, SignedAmount::MAX); + } + #[cfg(feature = "alloc")] #[test] fn floating_point() {