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)
24 : STTakesAsset(field), value_(value)
25{
26}
27
29{
30 // We must call these methods in separate statements
31 // to guarantee their order of execution.
32 auto mantissa = sit.geti64();
33 auto exponent = sit.geti32();
34 value_ = Number{mantissa, exponent};
35}
36
39{
40 return STI_NUMBER;
41}
42
45{
46 return to_string(value_);
47}
48
49void
51{
53
54 XRPL_ASSERT_PARTS(
55 getFName().shouldMeta(SField::sMD_NeedsAsset),
56 "STNumber::associateAsset",
57 "field needs asset");
58
60}
61
62void
64{
65 XRPL_ASSERT(getFName().isBinary(), "xrpl::STNumber::add : field is binary");
66 XRPL_ASSERT(
67 getFName().fieldType == getSType(),
68 "xrpl::STNumber::add : field type match");
69
70 auto value = value_;
71 auto const mantissa = value.mantissa();
72 auto const exponent = value.exponent();
73
74 SField const& field = getFName();
75 if (field.shouldMeta(SField::sMD_NeedsAsset))
76 {
77 // asset is defined in the STTakesAsset base class
78 if (asset_)
79 {
80 // The number should be rounded to the asset's precision, but round
81 // it here if it has an asset assigned.
83 XRPL_ASSERT_PARTS(
84 value_ == value,
85 "xrpl::STNumber::add",
86 "value is already rounded");
87 }
88 else
89 {
90#if !NDEBUG
91 // There are circumstances where an already-rounded Number is
92 // serialized without being touched by a transactor, and thus
93 // without an asset. We can't know if it's rounded, because it could
94 // represent _anything_, particularly when serializing user-provided
95 // Json. Regardless, the only time we should be serializing an
96 // STNumber is when the scale is large.
97 XRPL_ASSERT_PARTS(
99 "xrpl::STNumber::add",
100 "STNumber only used with large mantissa scale");
101#endif
102 }
103 }
104
105 XRPL_ASSERT_PARTS(
108 "xrpl::STNumber::add",
109 "mantissa in valid range");
110 s.add64(mantissa);
111 s.add32(exponent);
112}
113
114Number const&
116{
117 return value_;
118}
119
120void
122{
123 value_ = v;
124}
125
126STBase*
127STNumber::copy(std::size_t n, void* buf) const
128{
129 return emplace(n, buf, *this);
130}
131
132STBase*
134{
135 return emplace(n, buf, std::move(*this));
136}
137
138bool
140{
141 XRPL_ASSERT(
142 t.getSType() == this->getSType(),
143 "xrpl::STNumber::isEquivalent : field type match");
144 STNumber const& v = dynamic_cast<STNumber const&>(t);
145 return value_ == v;
146}
147
148bool
150{
151 return value_ == Number();
152}
153
156{
157 return out << rhs.getText();
158}
159
160NumberParts
162{
163 static boost::regex const reNumber(
164 "^" // the beginning of the string
165 "([-+]?)" // (optional) + or - character
166 "(0|[1-9][0-9]*)" // a number (no leading zeroes, unless 0)
167 "(\\.([0-9]+))?" // (optional) period followed by any number
168 "([eE]([+-]?)([0-9]+))?" // (optional) E, optional + or -, any number
169 "$",
170 boost::regex_constants::optimize);
171
172 boost::smatch match;
173
174 if (!boost::regex_match(number, match, reNumber))
175 Throw<std::runtime_error>("'" + number + "' is not a number");
176
177 // Match fields:
178 // 0 = whole input
179 // 1 = sign
180 // 2 = integer portion
181 // 3 = whole fraction (with '.')
182 // 4 = fraction (without '.')
183 // 5 = whole exponent (with 'e')
184 // 6 = exponent sign
185 // 7 = exponent number
186
187 bool negative = (match[1].matched && (match[1] == "-"));
188
189 std::uint64_t mantissa;
190 int exponent;
191
192 if (!match[4].matched) // integer only
193 {
194 mantissa = boost::lexical_cast<std::uint64_t>(std::string(match[2]));
195 exponent = 0;
196 }
197 else
198 {
199 // integer and fraction
200 mantissa = boost::lexical_cast<std::uint64_t>(match[2] + match[4]);
201 exponent = -(match[4].length());
202 }
203
204 if (match[5].matched)
205 {
206 // we have an exponent
207 if (match[6].matched && (match[6] == "-"))
208 exponent -= boost::lexical_cast<int>(std::string(match[7]));
209 else
210 exponent += boost::lexical_cast<int>(std::string(match[7]));
211 }
212
213 return {mantissa, exponent, negative};
214}
215
216STNumber
217numberFromJson(SField const& field, Json::Value const& value)
218{
219 NumberParts parts;
220
221 if (value.isInt())
222 {
223 if (value.asInt() >= 0)
224 {
225 parts.mantissa = value.asInt();
226 }
227 else
228 {
229 parts.mantissa = value.asAbsUInt();
230 parts.negative = true;
231 }
232 }
233 else if (value.isUInt())
234 {
235 parts.mantissa = value.asUInt();
236 }
237 else if (value.isString())
238 {
239 parts = partsFromString(value.asString());
240
241 XRPL_ASSERT_PARTS(
243 "xrpld::numberFromJson",
244 "Not in a Transactor context");
245
246 // Number mantissas are much bigger than the allowable parsed values, so
247 // it can't be out of range.
248 static_assert(
250 std::numeric_limits<decltype(parts.mantissa)>::max());
251 }
252 else
253 {
254 Throw<std::runtime_error>("not a number");
255 }
256
257 return STNumber{
258 field,
259 Number{
260 parts.negative,
261 parts.mantissa,
262 parts.exponent,
264}
265
266} // 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:212
constexpr rep mantissa() const noexcept
Returns the mantissa of the external view of the Number.
Definition Number.h:571
constexpr int exponent() const noexcept
Returns the exponent of the external view of the Number.
Definition Number.h:592
static MantissaRange::mantissa_scale getMantissaScale()
Returns which mantissa scale is currently in use for normalization.
Definition Number.cpp:46
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:124
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:63
bool isDefault() const override
Definition STNumber.cpp:149
void associateAsset(Asset const &a) override
Definition STNumber.cpp:50
void setValue(Number const &v)
Definition STNumber.cpp:121
STNumber()=default
std::string getText() const override
Definition STNumber.cpp:44
bool isEquivalent(STBase const &t) const override
Definition STNumber.cpp:139
STBase * move(std::size_t n, void *buf) override
Definition STNumber.cpp:133
SerializedTypeID getSType() const override
Definition STNumber.cpp:38
STBase * copy(std::size_t n, void *buf) const override
Definition STNumber.cpp:127
Number value_
Definition STNumber.h:38
Number const & value() const
Definition STNumber.cpp:115
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:161
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:611
std::ostream & operator<<(std::ostream &out, base_uint< Bits, Tag > const &u)
Definition base_uint.h:628
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:741
STNumber numberFromJson(SField const &field, Json::Value const &value)
Definition STNumber.cpp:217
std::uint64_t mantissa
Definition STNumber.h:91