#ifndef XRPL_PROTOCOL_XRPAMOUNT_H_INCLUDED #define XRPL_PROTOCOL_XRPAMOUNT_H_INCLUDED #include #include #include #include #include #include #include #include #include #include #include namespace ripple { class XRPAmount : private boost::totally_ordered, private boost::additive, private boost::equality_comparable, private boost::additive { public: using unit_type = unit::dropTag; using value_type = std::int64_t; private: value_type drops_; public: XRPAmount() = default; constexpr XRPAmount(XRPAmount const& other) = default; constexpr XRPAmount& operator=(XRPAmount const& other) = default; // Round to nearest, even on tie. explicit XRPAmount(Number const& x) : XRPAmount(static_cast(x)) { } constexpr XRPAmount(beast::Zero) : drops_(0) { } constexpr XRPAmount& operator=(beast::Zero) { drops_ = 0; return *this; } constexpr explicit XRPAmount(value_type drops) : drops_(drops) { } XRPAmount& operator=(value_type drops) { drops_ = drops; return *this; } constexpr XRPAmount operator*(value_type const& rhs) const { return XRPAmount{drops_ * rhs}; } friend constexpr XRPAmount operator*(value_type lhs, XRPAmount const& rhs) { // multiplication is commutative return rhs * lhs; } XRPAmount& operator+=(XRPAmount const& other) { drops_ += other.drops(); return *this; } XRPAmount& operator-=(XRPAmount const& other) { drops_ -= other.drops(); return *this; } XRPAmount& operator+=(value_type const& rhs) { drops_ += rhs; return *this; } XRPAmount& operator-=(value_type const& rhs) { drops_ -= rhs; return *this; } XRPAmount& operator*=(value_type const& rhs) { drops_ *= rhs; return *this; } XRPAmount operator-() const { return XRPAmount{-drops_}; } bool operator==(XRPAmount const& other) const { return drops_ == other.drops_; } bool operator==(value_type other) const { return drops_ == other; } bool operator<(XRPAmount const& other) const { return drops_ < other.drops_; } /** Returns true if the amount is not zero */ explicit constexpr operator bool() const noexcept { return drops_ != 0; } operator Number() const noexcept { return drops(); } /** Return the sign of the amount */ constexpr int signum() const noexcept { return (drops_ < 0) ? -1 : (drops_ ? 1 : 0); } /** Returns the number of drops */ constexpr value_type drops() const { return drops_; } constexpr double decimalXRP() const; template std::optional dropsAs() const { if ((drops_ > std::numeric_limits::max()) || (!std::numeric_limits::is_signed && drops_ < 0) || (std::numeric_limits::is_signed && drops_ < std::numeric_limits::lowest())) { return std::nullopt; } return static_cast(drops_); } template Dest dropsAs(Dest defaultValue) const { return dropsAs().value_or(defaultValue); } template Dest dropsAs(XRPAmount defaultValue) const { return dropsAs().value_or(defaultValue.drops()); } /* Clips a 64-bit value to a 32-bit JSON number. It is only used * in contexts that don't expect the value to ever approach * the 32-bit limits (i.e. fees and reserves). */ Json::Value jsonClipped() const { static_assert( std::is_signed_v && std::is_integral_v, "Expected XRPAmount to be a signed integral type"); constexpr auto min = std::numeric_limits::min(); constexpr auto max = std::numeric_limits::max(); if (drops_ < min) return min; if (drops_ > max) return max; return static_cast(drops_); } /** Returns the underlying value. Code SHOULD NOT call this function unless the type has been abstracted away, e.g. in a templated function. */ constexpr value_type value() const { return drops_; } friend std::istream& operator>>(std::istream& s, XRPAmount& val) { s >> val.drops_; return s; } static XRPAmount minPositiveAmount() { return XRPAmount{1}; } }; /** Number of drops per 1 XRP */ constexpr XRPAmount DROPS_PER_XRP{1'000'000}; constexpr double XRPAmount::decimalXRP() const { return static_cast(drops_) / DROPS_PER_XRP.drops(); } // Output XRPAmount as just the drops value. template std::basic_ostream& operator<<(std::basic_ostream& os, XRPAmount const& q) { return os << q.drops(); } inline std::string to_string(XRPAmount const& amount) { return std::to_string(amount.drops()); } inline XRPAmount mulRatio( XRPAmount const& amt, std::uint32_t num, std::uint32_t den, bool roundUp) { using namespace boost::multiprecision; if (!den) Throw("division by zero"); int128_t const amt128(amt.drops()); auto const neg = amt.drops() < 0; auto const m = amt128 * num; auto r = m / den; if (m % den) { if (!neg && roundUp) r += 1; if (neg && !roundUp) r -= 1; } if (r > std::numeric_limits::max()) Throw("XRP mulRatio overflow"); return XRPAmount(r.convert_to()); } } // namespace ripple #endif // XRPL_BASICS_XRPAMOUNT_H_INCLUDED