#include #include #include #include #include namespace xrpl { Quality::Quality(std::uint64_t value) : m_value(value) { } Quality::Quality(Amounts const& amount) : m_value(getRate(amount.out, amount.in)) { } Quality& Quality::operator++() { XRPL_ASSERT(m_value > 0, "xrpl::Quality::operator++() : minimum value"); --m_value; return *this; } Quality Quality::operator++(int) { Quality prev(*this); ++*this; return prev; } Quality& Quality::operator--() { XRPL_ASSERT( m_value < std::numeric_limits::max(), "xrpl::Quality::operator--() : maximum value"); ++m_value; return *this; } Quality Quality::operator--(int) { Quality prev(*this); --*this; return prev; } template static Amounts ceil_in_impl(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::ceil_in_impl : result matches limit"); return result; } XRPL_ASSERT(amount.in <= limit, "xrpl::ceil_in_impl : result inside limit"); return amount; } Amounts Quality::ceil_in(Amounts const& amount, STAmount const& limit) const { return ceil_in_impl(amount, limit, /* roundUp */ true, *this); } Amounts Quality::ceil_in_strict(Amounts const& amount, STAmount const& limit, bool roundUp) const { return ceil_in_impl(amount, limit, roundUp, *this); } template static Amounts ceil_out_impl(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::ceil_out_impl : result matches limit"); return result; } XRPL_ASSERT(amount.out <= limit, "xrpl::ceil_out_impl : result inside limit"); return amount; } Amounts Quality::ceil_out(Amounts const& amount, STAmount const& limit) const { return ceil_out_impl(amount, limit, /* roundUp */ true, *this); } Amounts Quality::ceil_out_strict(Amounts const& amount, STAmount const& limit, bool roundUp) const { return ceil_out_impl(amount, limit, roundUp, *this); } Quality composed_quality(Quality const& lhs, Quality const& rhs) { STAmount const lhs_rate(lhs.rate()); XRPL_ASSERT(lhs_rate != beast::zero, "xrpl::composed_quality : nonzero left input"); STAmount const rhs_rate(rhs.rate()); XRPL_ASSERT(rhs_rate != beast::zero, "xrpl::composed_quality : nonzero right input"); STAmount const rate(mulRound(lhs_rate, rhs_rate, lhs_rate.asset(), true)); std::uint64_t const stored_exponent(rate.exponent() + 100); std::uint64_t const stored_mantissa(rate.mantissa()); XRPL_ASSERT( (stored_exponent > 0) && (stored_exponent <= 255), "xrpl::composed_quality : valid exponent"); return Quality((stored_exponent << (64 - 8)) | stored_mantissa); } Quality Quality::round(int digits) const { // Modulus for mantissa static std::uint64_t const mod[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 = m_value >> (64 - 8); auto mantissa = m_value & 0x00ffffffffffffffULL; mantissa += mod[digits] - 1; mantissa -= (mantissa % mod[digits]); return Quality{(exponent << (64 - 8)) | mantissa}; } } // namespace xrpl