#include // Do not remove. Keep STNumber.h first #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace xrpl { STNumber::STNumber(SField const& field, Number const& value) : STTakesAsset(field), value_(value) { } STNumber::STNumber(SerialIter& sit, SField const& field) : STTakesAsset(field) { // We must call these methods in separate statements // to guarantee their order of execution. auto mantissa = sit.geti64(); auto exponent = sit.geti32(); value_ = Number{mantissa, exponent}; } SerializedTypeID STNumber::getSType() const { return STI_NUMBER; } std::string STNumber::getText() const { return to_string(value_); } void STNumber::associateAsset(Asset const& a) { STTakesAsset::associateAsset(a); XRPL_ASSERT_PARTS( getFName().shouldMeta(SField::sMD_NeedsAsset), "STNumber::associateAsset", "field needs asset"); roundToAsset(a, value_); } void STNumber::add(Serializer& s) const { XRPL_ASSERT(getFName().isBinary(), "xrpl::STNumber::add : field is binary"); XRPL_ASSERT( getFName().fieldType == getSType(), "xrpl::STNumber::add : field type match"); auto value = value_; auto const mantissa = value.mantissa(); auto const exponent = value.exponent(); SField const& field = getFName(); if (field.shouldMeta(SField::sMD_NeedsAsset)) { // asset is defined in the STTakesAsset base class if (asset_) { // The number should be rounded to the asset's precision, but round // it here if it has an asset assigned. roundToAsset(*asset_, value); XRPL_ASSERT_PARTS( value_ == value, "xrpl::STNumber::add", "value is already rounded"); } else { #if !NDEBUG // There are circumstances where an already-rounded Number is // serialized without being touched by a transactor, and thus // without an asset. We can't know if it's rounded, because it could // represent _anything_, particularly when serializing user-provided // Json. Regardless, the only time we should be serializing an // STNumber is when the scale is large. XRPL_ASSERT_PARTS( Number::getMantissaScale() == MantissaRange::large, "xrpl::STNumber::add", "STNumber only used with large mantissa scale"); #endif } } XRPL_ASSERT_PARTS( mantissa <= std::numeric_limits::max() && mantissa >= std::numeric_limits::min(), "xrpl::STNumber::add", "mantissa in valid range"); s.add64(mantissa); s.add32(exponent); } Number const& STNumber::value() const { return value_; } void STNumber::setValue(Number const& v) { value_ = v; } STBase* STNumber::copy(std::size_t n, void* buf) const { return emplace(n, buf, *this); } STBase* STNumber::move(std::size_t n, void* buf) { return emplace(n, buf, std::move(*this)); } bool STNumber::isEquivalent(STBase const& t) const { XRPL_ASSERT( t.getSType() == this->getSType(), "xrpl::STNumber::isEquivalent : field type match"); STNumber const& v = dynamic_cast(t); return value_ == v; } bool STNumber::isDefault() const { return value_ == Number(); } std::ostream& operator<<(std::ostream& out, STNumber const& rhs) { return out << rhs.getText(); } NumberParts partsFromString(std::string const& number) { static boost::regex const reNumber( "^" // the beginning of the string "([-+]?)" // (optional) + or - character "(0|[1-9][0-9]*)" // a number (no leading zeroes, unless 0) "(\\.([0-9]+))?" // (optional) period followed by any number "([eE]([+-]?)([0-9]+))?" // (optional) E, optional + or -, any number "$", boost::regex_constants::optimize); boost::smatch match; if (!boost::regex_match(number, match, reNumber)) Throw("'" + number + "' is not a number"); // Match fields: // 0 = whole input // 1 = sign // 2 = integer portion // 3 = whole fraction (with '.') // 4 = fraction (without '.') // 5 = whole exponent (with 'e') // 6 = exponent sign // 7 = exponent number bool negative = (match[1].matched && (match[1] == "-")); std::uint64_t mantissa; int exponent; if (!match[4].matched) // integer only { mantissa = boost::lexical_cast(std::string(match[2])); exponent = 0; } else { // integer and fraction mantissa = boost::lexical_cast(match[2] + match[4]); exponent = -(match[4].length()); } if (match[5].matched) { // we have an exponent if (match[6].matched && (match[6] == "-")) exponent -= boost::lexical_cast(std::string(match[7])); else exponent += boost::lexical_cast(std::string(match[7])); } return {mantissa, exponent, negative}; } STNumber numberFromJson(SField const& field, Json::Value const& value) { NumberParts parts; if (value.isInt()) { if (value.asInt() >= 0) { parts.mantissa = value.asInt(); } else { parts.mantissa = value.asAbsUInt(); parts.negative = true; } } else if (value.isUInt()) { parts.mantissa = value.asUInt(); } else if (value.isString()) { parts = partsFromString(value.asString()); XRPL_ASSERT_PARTS( !getCurrentTransactionRules(), "xrpld::numberFromJson", "Not in a Transactor context"); // Number mantissas are much bigger than the allowable parsed values, so // it can't be out of range. static_assert( std::numeric_limits::max() >= std::numeric_limits::max()); } else { Throw("not a number"); } return STNumber{ field, Number{ parts.negative, parts.mantissa, parts.exponent, Number::normalized{}}}; } } // namespace xrpl