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