diff --git a/include/xrpl/basics/Number.h b/include/xrpl/basics/Number.h index e34cc61b5b..070ee4a77c 100644 --- a/include/xrpl/basics/Number.h +++ b/include/xrpl/basics/Number.h @@ -13,12 +13,28 @@ class Number; std::string to_string(Number const& amount); +template +concept ArithmeticWithNumber = + std::is_arithmetic_v> && + std::is_convertible_v; + +template +concept OneNumberParam = + ArithmeticWithNumber || ArithmeticWithNumber; + class Number { using rep = std::int64_t; rep mantissa_{0}; int exponent_{std::numeric_limits::lowest()}; + using urep = std::make_unsigned_t; + + template + rep + utoi(T mantissa) + requires std::is_unsigned_v; + public: // The range for the mantissa when normalized constexpr static std::int64_t minMantissa = 1'000'000'000'000'000LL; @@ -35,7 +51,10 @@ public: explicit constexpr Number() = default; - Number(rep mantissa); + template + explicit Number(T mantissa) + requires std::is_unsigned_v; + explicit Number(rep mantissa); explicit Number(rep mantissa, int exponent); explicit constexpr Number(rep mantissa, int exponent, unchecked) noexcept; @@ -59,13 +78,39 @@ public: Number& operator+=(Number const& x); + template + Number& + operator+=(T x) + { + return operator+=(Number(x)); + } + Number& operator-=(Number const& x); + template + Number& + operator-=(T x) + { + return operator-=(Number(x)); + } Number& operator*=(Number const& x); + template + Number& + operator*=(T x) + { + return operator*=(Number(x)); + } + Number& operator/=(Number const& x); + template + Number& + operator/=(T x) + { + return operator/=(Number(x)); + } static constexpr Number min() noexcept; @@ -87,12 +132,26 @@ public: { return x.mantissa_ == y.mantissa_ && x.exponent_ == y.exponent_; } + template + friend constexpr bool + operator==(T1&& x, T2&& y) noexcept + requires OneNumberParam + { + return operator==(Number(x), Number(y)); + } friend constexpr bool operator!=(Number const& x, Number const& y) noexcept { return !(x == y); } + template + friend constexpr bool + operator!=(T1&& x, T2&& y) noexcept + requires OneNumberParam + { + return operator!=(Number(x), Number(y)); + } friend constexpr bool operator<(Number const& x, Number const& y) noexcept @@ -123,6 +182,13 @@ public: // If equal exponents, compare mantissas return x.mantissa_ < y.mantissa_; } + template + friend constexpr bool + operator<(T1&& x, T2&& y) noexcept + requires OneNumberParam + { + return operator<(Number(x), Number(y)); + } /** Return the sign of the amount */ constexpr int @@ -154,18 +220,39 @@ public: { return y < x; } + template + friend constexpr bool + operator>(T1&& x, T2&& y) noexcept + requires OneNumberParam + { + return operator>(Number(x), Number(y)); + } friend constexpr bool operator<=(Number const& x, Number const& y) noexcept { return !(y < x); } + template + friend constexpr bool + operator<=(T1&& x, T2&& y) noexcept + requires OneNumberParam + { + return operator<=(Number(x), Number(y)); + } friend constexpr bool operator>=(Number const& x, Number const& y) noexcept { return !(x < y); } + template + friend constexpr bool + operator>=(T1&& x, T2&& y) noexcept + requires OneNumberParam + { + return operator>=(Number(x), Number(y)); + } friend std::ostream& operator<<(std::ostream& os, Number const& x) @@ -192,6 +279,16 @@ private: class Guard; }; +template +Number::rep +Number::utoi(T mantissa) + requires std::is_unsigned_v +{ + if (mantissa > std::numeric_limits::max()) + throw std::overflow_error("too high"); + return static_cast(mantissa); +} + inline constexpr Number::Number(rep mantissa, int exponent, unchecked) noexcept : mantissa_{mantissa}, exponent_{exponent} { @@ -207,6 +304,13 @@ inline Number::Number(rep mantissa) : Number{mantissa, 0} { } +template +Number::Number(T mantissa) + requires std::is_unsigned_v + : Number{utoi(mantissa), 0} +{ +} + inline constexpr Number::rep Number::mantissa() const noexcept { @@ -277,6 +381,14 @@ operator+(Number const& x, Number const& y) return z; } +template +constexpr Number +operator+(T1&& x, T2&& y) + requires OneNumberParam +{ + return operator+(Number(x), Number(y)); +} + inline Number operator-(Number const& x, Number const& y) { @@ -285,6 +397,14 @@ operator-(Number const& x, Number const& y) return z; } +template +constexpr Number +operator-(T1&& x, T2&& y) + requires OneNumberParam +{ + return operator-(Number(x), Number(y)); +} + inline Number operator*(Number const& x, Number const& y) { @@ -293,6 +413,14 @@ operator*(Number const& x, Number const& y) return z; } +template +constexpr Number +operator*(T1&& x, T2&& y) + requires OneNumberParam +{ + return operator*(Number(x), Number(y)); +} + inline Number operator/(Number const& x, Number const& y) { @@ -301,6 +429,14 @@ operator/(Number const& x, Number const& y) return z; } +template +constexpr Number +operator/(T1&& x, T2&& y) + requires OneNumberParam +{ + return operator/(Number(x), Number(y)); +} + inline constexpr Number Number::min() noexcept { diff --git a/include/xrpl/protocol/Fees.h b/include/xrpl/protocol/Fees.h index 43ba6c9552..a58b98828f 100644 --- a/include/xrpl/protocol/Fees.h +++ b/include/xrpl/protocol/Fees.h @@ -29,7 +29,9 @@ struct Fees XRPAmount accountReserve(std::size_t ownerCount) const { - return reserve + ownerCount * increment; + auto const p = ownerCount * increment; + auto const s = reserve + p; + return s; } }; diff --git a/include/xrpl/protocol/IOUAmount.h b/include/xrpl/protocol/IOUAmount.h index da2dbb3fa7..9479469df3 100644 --- a/include/xrpl/protocol/IOUAmount.h +++ b/include/xrpl/protocol/IOUAmount.h @@ -42,7 +42,7 @@ public: IOUAmount() = default; explicit IOUAmount(Number const& other); IOUAmount(beast::Zero); - IOUAmount(std::int64_t mantissa, int exponent); + IOUAmount(std::int64_t mantissa, int exponent = 0); IOUAmount& operator=(beast::Zero); diff --git a/include/xrpl/protocol/MPTAmount.h b/include/xrpl/protocol/MPTAmount.h index af14786501..78118c4f9e 100644 --- a/include/xrpl/protocol/MPTAmount.h +++ b/include/xrpl/protocol/MPTAmount.h @@ -64,7 +64,7 @@ public: operator Number() const noexcept { - return value(); + return Number{value()}; } /** Return the sign of the amount */ diff --git a/include/xrpl/protocol/XRPAmount.h b/include/xrpl/protocol/XRPAmount.h index e102a3707f..2fd98c912e 100644 --- a/include/xrpl/protocol/XRPAmount.h +++ b/include/xrpl/protocol/XRPAmount.h @@ -20,7 +20,9 @@ namespace ripple { class XRPAmount : private boost::totally_ordered, private boost::additive, private boost::equality_comparable, - private boost::additive + private boost::equality_comparable, + private boost::additive, + private boost::additive { public: using unit_type = unit::dropTag; @@ -68,11 +70,13 @@ public: return XRPAmount{drops_ * rhs}; } + template friend constexpr XRPAmount - operator*(value_type lhs, XRPAmount const& rhs) + operator*(T lhs, XRPAmount const& rhs) + requires std::is_convertible_v { // multiplication is commutative - return rhs * lhs; + return rhs.operator*(lhs); } XRPAmount& @@ -127,6 +131,12 @@ public: { return drops_ == other; } + friend bool + operator==(value_type lhs, XRPAmount const& rhs) + { + // multiplication is commutative + return rhs.operator==(lhs); + } bool operator<(XRPAmount const& other) const @@ -143,7 +153,7 @@ public: operator Number() const noexcept { - return drops(); + return Number{drops()}; } /** Return the sign of the amount */ diff --git a/src/libxrpl/ledger/View.cpp b/src/libxrpl/ledger/View.cpp index 069bd3a4d8..e7865f4570 100644 --- a/src/libxrpl/ledger/View.cpp +++ b/src/libxrpl/ledger/View.cpp @@ -2884,7 +2884,7 @@ assetsToSharesDeposit( Number(assets.mantissa(), assets.exponent() + vault->at(sfScale)) .truncate()}; - Number const shareTotal = issuance->at(sfOutstandingAmount); + Number const shareTotal = Number{issuance->at(sfOutstandingAmount)}; shares = ((shareTotal * assets) / assetTotal).truncate(); return shares; } @@ -2913,7 +2913,7 @@ sharesToAssetsDeposit( shares.exponent() - vault->at(sfScale), false}; - Number const shareTotal = issuance->at(sfOutstandingAmount); + Number const shareTotal{issuance->at(sfOutstandingAmount)}; assets = (assetTotal * shares) / shareTotal; return assets; } @@ -2939,7 +2939,7 @@ assetsToSharesWithdraw( STAmount shares{vault->at(sfShareMPTID)}; if (assetTotal == 0) return shares; - Number const shareTotal = issuance->at(sfOutstandingAmount); + Number const shareTotal{issuance->at(sfOutstandingAmount)}; Number result = (shareTotal * assets) / assetTotal; if (truncate == TruncateShares::yes) result = result.truncate(); @@ -2967,7 +2967,7 @@ sharesToAssetsWithdraw( STAmount assets{vault->at(sfAsset)}; if (assetTotal == 0) return assets; - Number const shareTotal = issuance->at(sfOutstandingAmount); + Number const shareTotal{issuance->at(sfOutstandingAmount)}; assets = (assetTotal * shares) / shareTotal; return assets; } diff --git a/src/libxrpl/protocol/QualityFunction.cpp b/src/libxrpl/protocol/QualityFunction.cpp index 8273743cfa..ce715610d6 100644 --- a/src/libxrpl/protocol/QualityFunction.cpp +++ b/src/libxrpl/protocol/QualityFunction.cpp @@ -16,6 +16,12 @@ QualityFunction::QualityFunction( { if (quality.rate() <= beast::zero) Throw("QualityFunction quality rate is 0."); + + static_assert(std::is_arithmetic_v>); + static_assert(std::is_convertible_v); + static_assert(ripple::OneNumberParam); + static_assert(!ripple::OneNumberParam); + b_ = 1 / quality.rate(); } diff --git a/src/test/jtx/amount.h b/src/test/jtx/amount.h index 4d32ef2d1a..e5e8cca79c 100644 --- a/src/test/jtx/amount.h +++ b/src/test/jtx/amount.h @@ -142,6 +142,34 @@ public: } }; +/* +template +concept STAmountParams = + std::is_convertible_v && std::is_convertible_v; + +template +STAmount +operator-(T2&& lhs, T1&& rhs) + requires STAmountParams +{ + return STAmount(lhs) - STAmount(rhs); +} +*/ + +/* +STAmount +operator-(PrettyAmount&& lhs, STAmount const& rhs) +{ + return STAmount(lhs) - rhs; +} + +STAmount +operator-(STAmount const& lhs, PrettyAmount&& rhs) +{ + return lhs - STAmount(rhs); +} +*/ + inline bool operator==(PrettyAmount const& lhs, PrettyAmount const& rhs) { diff --git a/src/test/rpc/AccountSet_test.cpp b/src/test/rpc/AccountSet_test.cpp index 3df3606a03..9b5f23a52f 100644 --- a/src/test/rpc/AccountSet_test.cpp +++ b/src/test/rpc/AccountSet_test.cpp @@ -370,6 +370,7 @@ public: env(pay(alice, bob, USD(1)), sendmax(USD(10))); env.close(); + auto const ten = USD(10); env.require(balance(alice, USD(10) - amountWithRate)); env.require(balance(bob, USD(1))); } diff --git a/src/test/rpc/Simulate_test.cpp b/src/test/rpc/Simulate_test.cpp index d7018fdbbc..8210592b7e 100644 --- a/src/test/rpc/Simulate_test.cpp +++ b/src/test/rpc/Simulate_test.cpp @@ -731,6 +731,7 @@ class Simulate_test : public beast::unit_test::suite { auto validateOutput = [&](Json::Value const& resp, Json::Value const& tx) { + static_assert(ArithmeticWithNumber); auto result = resp[jss::result]; checkBasicReturnValidity( result,