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