Skip to content

Commit

Permalink
Merge rust-bitcoin#2436: Add unchecked variants to Amount and SignedA…
Browse files Browse the repository at this point in the history
…mount

df1d2f6 Add unchecked variants to Amount and SignedAmount (yancy)

Pull request description:

  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 for addition, subtraction and multiplication.

  Note, it seems the default behavior for the test framework is to panic on overflow, so I haven't figured out a good way to add tests for this.  Marking as a draft for now.

  closes: rust-bitcoin#2434

ACKs for top commit:
  Kixunil:
    ACK df1d2f6
  apoelstra:
    ACK df1d2f6 gonna go ahead and merge this, we can revisit if necessary when we look at `units` overflow behavior in general

Tree-SHA512: 3fbb0ec81a758b350569226c44e25f6ca49e551566bee83c05c1c2b343874ef657d63a36b5f51c41582d8a8e36466275c574ebff6d363ed7c112ac8b4d5376fa
  • Loading branch information
apoelstra committed Feb 15, 2024
2 parents 668df1d + df1d2f6 commit bf29a76
Showing 1 changed file with 57 additions and 0 deletions.
57 changes: 57 additions & 0 deletions units/src/amount.rs
Original file line number Diff line number Diff line change
Expand Up @@ -864,6 +864,21 @@ impl Amount {
/// Returns [None] if overflow occurred.
pub fn checked_rem(self, rhs: u64) -> Option<Amount> { 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<SignedAmount, OutOfRangeError> {
if self.to_sat() > SignedAmount::MAX.to_sat() as u64 {
Expand Down Expand Up @@ -1237,6 +1252,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<SignedAmount> {
Expand Down Expand Up @@ -1934,6 +1963,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() {
Expand Down

0 comments on commit bf29a76

Please sign in to comment.