rippled
Loading...
Searching...
No Matches
STNumber.cpp
1#include <xrpl/protocol/STNumber.h>
2// Do not remove. Keep STNumber.h first
3#include <xrpl/basics/Number.h>
4#include <xrpl/beast/core/LexicalCast.h>
5#include <xrpl/beast/utility/instrumentation.h>
6#include <xrpl/protocol/Rules.h>
7#include <xrpl/protocol/SField.h>
8#include <xrpl/protocol/STAmount.h>
9#include <xrpl/protocol/STBase.h>
10#include <xrpl/protocol/STIssue.h>
11#include <xrpl/protocol/Serializer.h>
12
13#include <boost/lexical_cast.hpp>
14#include <boost/regex.hpp>
15
16#include <cstddef>
17#include <ostream>
18#include <string>
19#include <utility>
20
21namespace xrpl {
22
23STNumber::STNumber(SField const& field, Number const& value) : STTakesAsset(field), value_(value)
24{
25}
26
28{
29 // We must call these methods in separate statements
30 // to guarantee their order of execution.
31 auto mantissa = sit.geti64();
32 auto exponent = sit.geti32();
33 value_ = Number{mantissa, exponent};
34}
35
38{
39 return STI_NUMBER;
40}
41
44{
45 return to_string(value_);
46}
47
48void
50{
52
53 XRPL_ASSERT_PARTS(getFName().shouldMeta(SField::sMD_NeedsAsset), "STNumber::associateAsset", "field needs asset");
54
56}
57
58void
60{
61 XRPL_ASSERT(getFName().isBinary(), "xrpl::STNumber::add : field is binary");
62 XRPL_ASSERT(getFName().fieldType == getSType(), "xrpl::STNumber::add : field type match");
63
64 auto value = value_;
65 auto const mantissa = value.mantissa();
66 auto const exponent = value.exponent();
67
68 SField const& field = getFName();
69 if (field.shouldMeta(SField::sMD_NeedsAsset))
70 {
71 // asset is defined in the STTakesAsset base class
72 if (asset_)
73 {
74 // The number should be rounded to the asset's precision, but round
75 // it here if it has an asset assigned.
77 XRPL_ASSERT_PARTS(value_ == value, "xrpl::STNumber::add", "value is already rounded");
78 }
79 else
80 {
81#if !NDEBUG
82 // There are circumstances where an already-rounded Number is
83 // serialized without being touched by a transactor, and thus
84 // without an asset. We can't know if it's rounded, because it could
85 // represent _anything_, particularly when serializing user-provided
86 // Json. Regardless, the only time we should be serializing an
87 // STNumber is when the scale is large.
88 XRPL_ASSERT_PARTS(
90 "xrpl::STNumber::add",
91 "STNumber only used with large mantissa scale");
92#endif
93 }
94 }
95
96 XRPL_ASSERT_PARTS(
98 "xrpl::STNumber::add",
99 "mantissa in valid range");
100 s.add64(mantissa);
101 s.add32(exponent);
102}
103
104Number const&
106{
107 return value_;
108}
109
110void
112{
113 value_ = v;
114}
115
116STBase*
117STNumber::copy(std::size_t n, void* buf) const
118{
119 return emplace(n, buf, *this);
120}
121
122STBase*
124{
125 return emplace(n, buf, std::move(*this));
126}
127
128bool
130{
131 XRPL_ASSERT(t.getSType() == this->getSType(), "xrpl::STNumber::isEquivalent : field type match");
132 STNumber const& v = dynamic_cast<STNumber const&>(t);
133 return value_ == v;
134}
135
136bool
138{
139 return value_ == Number();
140}
141
144{
145 return out << rhs.getText();
146}
147
148NumberParts
150{
151 static boost::regex const reNumber(
152 "^" // the beginning of the string
153 "([-+]?)" // (optional) + or - character
154 "(0|[1-9][0-9]*)" // a number (no leading zeroes, unless 0)
155 "(\\.([0-9]+))?" // (optional) period followed by any number
156 "([eE]([+-]?)([0-9]+))?" // (optional) E, optional + or -, any number
157 "$",
158 boost::regex_constants::optimize);
159
160 boost::smatch match;
161
162 if (!boost::regex_match(number, match, reNumber))
163 Throw<std::runtime_error>("'" + number + "' is not a number");
164
165 // Match fields:
166 // 0 = whole input
167 // 1 = sign
168 // 2 = integer portion
169 // 3 = whole fraction (with '.')
170 // 4 = fraction (without '.')
171 // 5 = whole exponent (with 'e')
172 // 6 = exponent sign
173 // 7 = exponent number
174
175 bool negative = (match[1].matched && (match[1] == "-"));
176
177 std::uint64_t mantissa;
178 int exponent;
179
180 if (!match[4].matched) // integer only
181 {
182 mantissa = boost::lexical_cast<std::uint64_t>(std::string(match[2]));
183 exponent = 0;
184 }
185 else
186 {
187 // integer and fraction
188 mantissa = boost::lexical_cast<std::uint64_t>(match[2] + match[4]);
189 exponent = -(match[4].length());
190 }
191
192 if (match[5].matched)
193 {
194 // we have an exponent
195 if (match[6].matched && (match[6] == "-"))
196 exponent -= boost::lexical_cast<int>(std::string(match[7]));
197 else
198 exponent += boost::lexical_cast<int>(std::string(match[7]));
199 }
200
201 return {mantissa, exponent, negative};
202}
203
204STNumber
205numberFromJson(SField const& field, Json::Value const& value)
206{
207 NumberParts parts;
208
209 if (value.isInt())
210 {
211 if (value.asInt() >= 0)
212 {
213 parts.mantissa = value.asInt();
214 }
215 else
216 {
217 parts.mantissa = value.asAbsUInt();
218 parts.negative = true;
219 }
220 }
221 else if (value.isUInt())
222 {
223 parts.mantissa = value.asUInt();
224 }
225 else if (value.isString())
226 {
227 parts = partsFromString(value.asString());
228
229 XRPL_ASSERT_PARTS(!getCurrentTransactionRules(), "xrpld::numberFromJson", "Not in a Transactor context");
230
231 // Number mantissas are much bigger than the allowable parsed values, so
232 // it can't be out of range.
233 static_assert(
235 }
236 else
237 {
238 Throw<std::runtime_error>("not a number");
239 }
240
241 return STNumber{field, Number{parts.negative, parts.mantissa, parts.exponent, Number::normalized{}}};
242}
243
244} // namespace xrpl
Represents a JSON value.
Definition json_value.h:131
Int asInt() const
UInt asAbsUInt() const
Correct absolute value from int or unsigned int.
bool isString() const
UInt asUInt() const
std::string asString() const
Returns the unquoted string value.
bool isUInt() const
bool isInt() const
Number is a floating point type that can represent a wide range of values.
Definition Number.h:208
constexpr rep mantissa() const noexcept
Returns the mantissa of the external view of the Number.
Definition Number.h:543
constexpr int exponent() const noexcept
Returns the exponent of the external view of the Number.
Definition Number.h:564
static MantissaRange::mantissa_scale getMantissaScale()
Returns which mantissa scale is currently in use for normalization.
Definition Number.cpp:45
Identifies fields.
Definition SField.h:127
@ sMD_NeedsAsset
Definition SField.h:139
A type which can be exported to a well known binary format.
Definition STBase.h:116
SField const & getFName() const
Definition STBase.cpp:122
static STBase * emplace(std::size_t n, void *buf, T &&val)
Definition STBase.h:214
virtual SerializedTypeID getSType() const
Definition STBase.cpp:56
A serializable number.
Definition STNumber.h:36
void add(Serializer &s) const override
Definition STNumber.cpp:59
bool isDefault() const override
Definition STNumber.cpp:137
void associateAsset(Asset const &a) override
Definition STNumber.cpp:49
void setValue(Number const &v)
Definition STNumber.cpp:111
STNumber()=default
std::string getText() const override
Definition STNumber.cpp:43
bool isEquivalent(STBase const &t) const override
Definition STNumber.cpp:129
STBase * move(std::size_t n, void *buf) override
Definition STNumber.cpp:123
SerializedTypeID getSType() const override
Definition STNumber.cpp:37
STBase * copy(std::size_t n, void *buf) const override
Definition STNumber.cpp:117
Number value_
Definition STNumber.h:38
Number const & value() const
Definition STNumber.cpp:105
Intermediate class for any STBase-derived class to store an Asset.
virtual void associateAsset(Asset const &a)
std::optional< Asset > asset_
std::int32_t geti32()
std::int64_t geti64()
T max(T... args)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:6
NumberParts partsFromString(std::string const &number)
Definition STNumber.cpp:149
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:598
std::ostream & operator<<(std::ostream &out, base_uint< Bits, Tag > const &u)
Definition base_uint.h:613
std::optional< Rules > const & getCurrentTransactionRules()
Definition Rules.cpp:31
SerializedTypeID
Definition SField.h:91
void roundToAsset(A const &asset, Number &value)
Round an arbitrary precision Number IN PLACE to the precision of a given Asset.
Definition STAmount.h:675
STNumber numberFromJson(SField const &field, Json::Value const &value)
Definition STNumber.cpp:205
std::uint64_t mantissa
Definition STNumber.h:91