Compare commits

...

1 Commits

Author SHA1 Message Date
Ed Hennis
518f292c2b Damn consequences... 2025-11-15 22:32:22 -05:00
10 changed files with 196 additions and 12 deletions

View File

@@ -13,12 +13,28 @@ class Number;
std::string std::string
to_string(Number const& amount); to_string(Number const& amount);
template <class T1, class T2>
concept ArithmeticWithNumber =
std::is_arithmetic_v<std::remove_reference_t<T1>> &&
std::is_convertible_v<T2, Number>;
template <class T1, class T2>
concept OneNumberParam =
ArithmeticWithNumber<T1, T2> || ArithmeticWithNumber<T2, T1>;
class Number class Number
{ {
using rep = std::int64_t; using rep = std::int64_t;
rep mantissa_{0}; rep mantissa_{0};
int exponent_{std::numeric_limits<int>::lowest()}; int exponent_{std::numeric_limits<int>::lowest()};
using urep = std::make_unsigned_t<rep>;
template <class T>
rep
utoi(T mantissa)
requires std::is_unsigned_v<T>;
public: public:
// The range for the mantissa when normalized // The range for the mantissa when normalized
constexpr static std::int64_t minMantissa = 1'000'000'000'000'000LL; constexpr static std::int64_t minMantissa = 1'000'000'000'000'000LL;
@@ -35,7 +51,10 @@ public:
explicit constexpr Number() = default; explicit constexpr Number() = default;
Number(rep mantissa); template <class T>
explicit Number(T mantissa)
requires std::is_unsigned_v<T>;
explicit Number(rep mantissa);
explicit Number(rep mantissa, int exponent); explicit Number(rep mantissa, int exponent);
explicit constexpr Number(rep mantissa, int exponent, unchecked) noexcept; explicit constexpr Number(rep mantissa, int exponent, unchecked) noexcept;
@@ -59,13 +78,39 @@ public:
Number& Number&
operator+=(Number const& x); operator+=(Number const& x);
template <class T>
Number&
operator+=(T x)
{
return operator+=(Number(x));
}
Number& Number&
operator-=(Number const& x); operator-=(Number const& x);
template <class T>
Number&
operator-=(T x)
{
return operator-=(Number(x));
}
Number& Number&
operator*=(Number const& x); operator*=(Number const& x);
template <class T>
Number&
operator*=(T x)
{
return operator*=(Number(x));
}
Number& Number&
operator/=(Number const& x); operator/=(Number const& x);
template <class T>
Number&
operator/=(T x)
{
return operator/=(Number(x));
}
static constexpr Number static constexpr Number
min() noexcept; min() noexcept;
@@ -87,12 +132,26 @@ public:
{ {
return x.mantissa_ == y.mantissa_ && x.exponent_ == y.exponent_; return x.mantissa_ == y.mantissa_ && x.exponent_ == y.exponent_;
} }
template <class T1, class T2>
friend constexpr bool
operator==(T1&& x, T2&& y) noexcept
requires OneNumberParam<T1, T2>
{
return operator==(Number(x), Number(y));
}
friend constexpr bool friend constexpr bool
operator!=(Number const& x, Number const& y) noexcept operator!=(Number const& x, Number const& y) noexcept
{ {
return !(x == y); return !(x == y);
} }
template <class T1, class T2>
friend constexpr bool
operator!=(T1&& x, T2&& y) noexcept
requires OneNumberParam<T1, T2>
{
return operator!=(Number(x), Number(y));
}
friend constexpr bool friend constexpr bool
operator<(Number const& x, Number const& y) noexcept operator<(Number const& x, Number const& y) noexcept
@@ -123,6 +182,13 @@ public:
// If equal exponents, compare mantissas // If equal exponents, compare mantissas
return x.mantissa_ < y.mantissa_; return x.mantissa_ < y.mantissa_;
} }
template <class T1, class T2>
friend constexpr bool
operator<(T1&& x, T2&& y) noexcept
requires OneNumberParam<T1, T2>
{
return operator<(Number(x), Number(y));
}
/** Return the sign of the amount */ /** Return the sign of the amount */
constexpr int constexpr int
@@ -154,18 +220,39 @@ public:
{ {
return y < x; return y < x;
} }
template <class T1, class T2>
friend constexpr bool
operator>(T1&& x, T2&& y) noexcept
requires OneNumberParam<T1, T2>
{
return operator>(Number(x), Number(y));
}
friend constexpr bool friend constexpr bool
operator<=(Number const& x, Number const& y) noexcept operator<=(Number const& x, Number const& y) noexcept
{ {
return !(y < x); return !(y < x);
} }
template <class T1, class T2>
friend constexpr bool
operator<=(T1&& x, T2&& y) noexcept
requires OneNumberParam<T1, T2>
{
return operator<=(Number(x), Number(y));
}
friend constexpr bool friend constexpr bool
operator>=(Number const& x, Number const& y) noexcept operator>=(Number const& x, Number const& y) noexcept
{ {
return !(x < y); return !(x < y);
} }
template <class T1, class T2>
friend constexpr bool
operator>=(T1&& x, T2&& y) noexcept
requires OneNumberParam<T1, T2>
{
return operator>=(Number(x), Number(y));
}
friend std::ostream& friend std::ostream&
operator<<(std::ostream& os, Number const& x) operator<<(std::ostream& os, Number const& x)
@@ -192,6 +279,16 @@ private:
class Guard; class Guard;
}; };
template <class T>
Number::rep
Number::utoi(T mantissa)
requires std::is_unsigned_v<T>
{
if (mantissa > std::numeric_limits<rep>::max())
throw std::overflow_error("too high");
return static_cast<rep>(mantissa);
}
inline constexpr Number::Number(rep mantissa, int exponent, unchecked) noexcept inline constexpr Number::Number(rep mantissa, int exponent, unchecked) noexcept
: mantissa_{mantissa}, exponent_{exponent} : mantissa_{mantissa}, exponent_{exponent}
{ {
@@ -207,6 +304,13 @@ inline Number::Number(rep mantissa) : Number{mantissa, 0}
{ {
} }
template <class T>
Number::Number(T mantissa)
requires std::is_unsigned_v<T>
: Number{utoi(mantissa), 0}
{
}
inline constexpr Number::rep inline constexpr Number::rep
Number::mantissa() const noexcept Number::mantissa() const noexcept
{ {
@@ -277,6 +381,14 @@ operator+(Number const& x, Number const& y)
return z; return z;
} }
template <class T1, class T2>
constexpr Number
operator+(T1&& x, T2&& y)
requires OneNumberParam<T1, T2>
{
return operator+(Number(x), Number(y));
}
inline Number inline Number
operator-(Number const& x, Number const& y) operator-(Number const& x, Number const& y)
{ {
@@ -285,6 +397,14 @@ operator-(Number const& x, Number const& y)
return z; return z;
} }
template <class T1, class T2>
constexpr Number
operator-(T1&& x, T2&& y)
requires OneNumberParam<T1, T2>
{
return operator-(Number(x), Number(y));
}
inline Number inline Number
operator*(Number const& x, Number const& y) operator*(Number const& x, Number const& y)
{ {
@@ -293,6 +413,14 @@ operator*(Number const& x, Number const& y)
return z; return z;
} }
template <class T1, class T2>
constexpr Number
operator*(T1&& x, T2&& y)
requires OneNumberParam<T1, T2>
{
return operator*(Number(x), Number(y));
}
inline Number inline Number
operator/(Number const& x, Number const& y) operator/(Number const& x, Number const& y)
{ {
@@ -301,6 +429,14 @@ operator/(Number const& x, Number const& y)
return z; return z;
} }
template <class T1, class T2>
constexpr Number
operator/(T1&& x, T2&& y)
requires OneNumberParam<T1, T2>
{
return operator/(Number(x), Number(y));
}
inline constexpr Number inline constexpr Number
Number::min() noexcept Number::min() noexcept
{ {

View File

@@ -29,7 +29,9 @@ struct Fees
XRPAmount XRPAmount
accountReserve(std::size_t ownerCount) const accountReserve(std::size_t ownerCount) const
{ {
return reserve + ownerCount * increment; auto const p = ownerCount * increment;
auto const s = reserve + p;
return s;
} }
}; };

View File

@@ -42,7 +42,7 @@ public:
IOUAmount() = default; IOUAmount() = default;
explicit IOUAmount(Number const& other); explicit IOUAmount(Number const& other);
IOUAmount(beast::Zero); IOUAmount(beast::Zero);
IOUAmount(std::int64_t mantissa, int exponent); IOUAmount(std::int64_t mantissa, int exponent = 0);
IOUAmount& operator=(beast::Zero); IOUAmount& operator=(beast::Zero);

View File

@@ -64,7 +64,7 @@ public:
operator Number() const noexcept operator Number() const noexcept
{ {
return value(); return Number{value()};
} }
/** Return the sign of the amount */ /** Return the sign of the amount */

View File

@@ -20,7 +20,9 @@ namespace ripple {
class XRPAmount : private boost::totally_ordered<XRPAmount>, class XRPAmount : private boost::totally_ordered<XRPAmount>,
private boost::additive<XRPAmount>, private boost::additive<XRPAmount>,
private boost::equality_comparable<XRPAmount, std::int64_t>, private boost::equality_comparable<XRPAmount, std::int64_t>,
private boost::additive<XRPAmount, std::int64_t> private boost::equality_comparable<XRPAmount, int>,
private boost::additive<XRPAmount, std::int64_t>,
private boost::additive<XRPAmount, int>
{ {
public: public:
using unit_type = unit::dropTag; using unit_type = unit::dropTag;
@@ -68,11 +70,13 @@ public:
return XRPAmount{drops_ * rhs}; return XRPAmount{drops_ * rhs};
} }
template <class T>
friend constexpr XRPAmount friend constexpr XRPAmount
operator*(value_type lhs, XRPAmount const& rhs) operator*(T lhs, XRPAmount const& rhs)
requires std::is_convertible_v<T, value_type>
{ {
// multiplication is commutative // multiplication is commutative
return rhs * lhs; return rhs.operator*(lhs);
} }
XRPAmount& XRPAmount&
@@ -127,6 +131,12 @@ public:
{ {
return drops_ == other; return drops_ == other;
} }
friend bool
operator==(value_type lhs, XRPAmount const& rhs)
{
// multiplication is commutative
return rhs.operator==(lhs);
}
bool bool
operator<(XRPAmount const& other) const operator<(XRPAmount const& other) const
@@ -143,7 +153,7 @@ public:
operator Number() const noexcept operator Number() const noexcept
{ {
return drops(); return Number{drops()};
} }
/** Return the sign of the amount */ /** Return the sign of the amount */

View File

@@ -2884,7 +2884,7 @@ assetsToSharesDeposit(
Number(assets.mantissa(), assets.exponent() + vault->at(sfScale)) Number(assets.mantissa(), assets.exponent() + vault->at(sfScale))
.truncate()}; .truncate()};
Number const shareTotal = issuance->at(sfOutstandingAmount); Number const shareTotal = Number{issuance->at(sfOutstandingAmount)};
shares = ((shareTotal * assets) / assetTotal).truncate(); shares = ((shareTotal * assets) / assetTotal).truncate();
return shares; return shares;
} }
@@ -2913,7 +2913,7 @@ sharesToAssetsDeposit(
shares.exponent() - vault->at(sfScale), shares.exponent() - vault->at(sfScale),
false}; false};
Number const shareTotal = issuance->at(sfOutstandingAmount); Number const shareTotal{issuance->at(sfOutstandingAmount)};
assets = (assetTotal * shares) / shareTotal; assets = (assetTotal * shares) / shareTotal;
return assets; return assets;
} }
@@ -2939,7 +2939,7 @@ assetsToSharesWithdraw(
STAmount shares{vault->at(sfShareMPTID)}; STAmount shares{vault->at(sfShareMPTID)};
if (assetTotal == 0) if (assetTotal == 0)
return shares; return shares;
Number const shareTotal = issuance->at(sfOutstandingAmount); Number const shareTotal{issuance->at(sfOutstandingAmount)};
Number result = (shareTotal * assets) / assetTotal; Number result = (shareTotal * assets) / assetTotal;
if (truncate == TruncateShares::yes) if (truncate == TruncateShares::yes)
result = result.truncate(); result = result.truncate();
@@ -2967,7 +2967,7 @@ sharesToAssetsWithdraw(
STAmount assets{vault->at(sfAsset)}; STAmount assets{vault->at(sfAsset)};
if (assetTotal == 0) if (assetTotal == 0)
return assets; return assets;
Number const shareTotal = issuance->at(sfOutstandingAmount); Number const shareTotal{issuance->at(sfOutstandingAmount)};
assets = (assetTotal * shares) / shareTotal; assets = (assetTotal * shares) / shareTotal;
return assets; return assets;
} }

View File

@@ -16,6 +16,12 @@ QualityFunction::QualityFunction(
{ {
if (quality.rate() <= beast::zero) if (quality.rate() <= beast::zero)
Throw<std::runtime_error>("QualityFunction quality rate is 0."); Throw<std::runtime_error>("QualityFunction quality rate is 0.");
static_assert(std::is_arithmetic_v<std::remove_reference_t<int>>);
static_assert(std::is_convertible_v<ripple::STAmount, Number>);
static_assert(ripple::OneNumberParam<int, ripple::STAmount>);
static_assert(!ripple::OneNumberParam<Number, Number>);
b_ = 1 / quality.rate(); b_ = 1 / quality.rate();
} }

View File

@@ -142,6 +142,34 @@ public:
} }
}; };
/*
template <class T1, class T2>
concept STAmountParams =
std::is_convertible_v<T1, STAmount> && std::is_convertible_v<T2, STAmount>;
template <class T1, class T2>
STAmount
operator-(T2&& lhs, T1&& rhs)
requires STAmountParams<T1, T2>
{
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 inline bool
operator==(PrettyAmount const& lhs, PrettyAmount const& rhs) operator==(PrettyAmount const& lhs, PrettyAmount const& rhs)
{ {

View File

@@ -370,6 +370,7 @@ public:
env(pay(alice, bob, USD(1)), sendmax(USD(10))); env(pay(alice, bob, USD(1)), sendmax(USD(10)));
env.close(); env.close();
auto const ten = USD(10);
env.require(balance(alice, USD(10) - amountWithRate)); env.require(balance(alice, USD(10) - amountWithRate));
env.require(balance(bob, USD(1))); env.require(balance(bob, USD(1)));
} }

View File

@@ -731,6 +731,7 @@ class Simulate_test : public beast::unit_test::suite
{ {
auto validateOutput = [&](Json::Value const& resp, auto validateOutput = [&](Json::Value const& resp,
Json::Value const& tx) { Json::Value const& tx) {
static_assert(ArithmeticWithNumber<XRPAmount, int>);
auto result = resp[jss::result]; auto result = resp[jss::result];
checkBasicReturnValidity( checkBasicReturnValidity(
result, result,