#include #include #include #include #include #include #include namespace xrpl { Quality::Quality(std::uint64_t value) : value_(value) { } Quality::Quality(Amounts const& amount) : value_(getRate(amount.out, amount.in)) { } Quality& Quality::operator++() { XRPL_ASSERT(value_ > 0, "xrpl::Quality::operator++() : minimum value"); --value_; return *this; } Quality Quality::operator++(int) { Quality prev(*this); ++*this; return prev; } Quality& Quality::operator--() { XRPL_ASSERT( value_ < std::numeric_limits::max(), "xrpl::Quality::operator--() : maximum value"); ++value_; return *this; } Quality Quality::operator--(int) { Quality prev(*this); --*this; return prev; } template static Amounts ceilInImpl(Amounts const& amount, STAmount const& limit, bool roundUp, Quality const& quality) { if (amount.in > limit) { Amounts result(limit, DivRoundFunc(limit, quality.rate(), amount.out.asset(), roundUp)); // Clamp out if (result.out > amount.out) result.out = amount.out; XRPL_ASSERT(result.in == limit, "xrpl::ceilInImpl : result matches limit"); return result; } XRPL_ASSERT(amount.in <= limit, "xrpl::ceilInImpl : result inside limit"); return amount; } Amounts Quality::ceilIn(Amounts const& amount, STAmount const& limit) const { return ceilInImpl(amount, limit, /* roundUp */ true, *this); } Amounts Quality::ceilInStrict(Amounts const& amount, STAmount const& limit, bool roundUp) const { return ceilInImpl(amount, limit, roundUp, *this); } template static Amounts ceilOutImpl(Amounts const& amount, STAmount const& limit, bool roundUp, Quality const& quality) { if (amount.out > limit) { Amounts result(MulRoundFunc(limit, quality.rate(), amount.in.asset(), roundUp), limit); // Clamp in if (result.in > amount.in) result.in = amount.in; XRPL_ASSERT(result.out == limit, "xrpl::ceilOutImpl : result matches limit"); return result; } XRPL_ASSERT(amount.out <= limit, "xrpl::ceilOutImpl : result inside limit"); return amount; } Amounts Quality::ceilOut(Amounts const& amount, STAmount const& limit) const { return ceilOutImpl(amount, limit, /* roundUp */ true, *this); } Amounts Quality::ceilOutStrict(Amounts const& amount, STAmount const& limit, bool roundUp) const { return ceilOutImpl(amount, limit, roundUp, *this); } Quality composedQuality(Quality const& lhs, Quality const& rhs) { STAmount const lhsRate(lhs.rate()); XRPL_ASSERT(lhsRate != beast::kZero, "xrpl::composedQuality : nonzero left input"); STAmount const rhsRate(rhs.rate()); XRPL_ASSERT(rhsRate != beast::kZero, "xrpl::composedQuality : nonzero right input"); STAmount const rate(mulRound(lhsRate, rhsRate, lhsRate.asset(), true)); std::uint64_t const storedExponent(rate.exponent() + 100); std::uint64_t const storedMantissa(rate.mantissa()); XRPL_ASSERT( (storedExponent > 0) && (storedExponent <= 255), "xrpl::composedQuality : valid exponent"); return Quality((storedExponent << (64 - 8)) | storedMantissa); } Quality Quality::round(int digits) const { // Modulus for mantissa static std::uint64_t const kMod[17] = { /* 0 */ 10000000000000000, /* 1 */ 1000000000000000, /* 2 */ 100000000000000, /* 3 */ 10000000000000, /* 4 */ 1000000000000, /* 5 */ 100000000000, /* 6 */ 10000000000, /* 7 */ 1000000000, /* 8 */ 100000000, /* 9 */ 10000000, /* 10 */ 1000000, /* 11 */ 100000, /* 12 */ 10000, /* 13 */ 1000, /* 14 */ 100, /* 15 */ 10, /* 16 */ 1, }; auto exponent = value_ >> (64 - 8); auto mantissa = value_ & 0x00ffffffffffffffULL; mantissa += kMod[digits] - 1; mantissa -= (mantissa % kMod[digits]); return Quality{(exponent << (64 - 8)) | mantissa}; } } // namespace xrpl