rippled
Loading...
Searching...
No Matches
STNumber.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2023 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#include <xrpl/basics/Number.h>
21#include <xrpl/beast/core/LexicalCast.h>
22#include <xrpl/beast/utility/instrumentation.h>
23#include <xrpl/protocol/SField.h>
24#include <xrpl/protocol/STBase.h>
25#include <xrpl/protocol/STNumber.h>
26#include <xrpl/protocol/Serializer.h>
27
28#include <boost/lexical_cast.hpp>
29#include <boost/regex.hpp>
30
31#include <cstddef>
32#include <ostream>
33#include <string>
34#include <utility>
35
36namespace ripple {
37
38STNumber::STNumber(SField const& field, Number const& value)
39 : STBase(field), value_(value)
40{
41}
42
43STNumber::STNumber(SerialIter& sit, SField const& field) : STBase(field)
44{
45 // We must call these methods in separate statements
46 // to guarantee their order of execution.
47 auto mantissa = sit.geti64();
48 auto exponent = sit.geti32();
49 value_ = Number{mantissa, exponent};
50}
51
54{
55 return STI_NUMBER;
56}
57
60{
61 return to_string(value_);
62}
63
64void
66{
67 XRPL_ASSERT(
68 getFName().isBinary(), "ripple::STNumber::add : field is binary");
69 XRPL_ASSERT(
70 getFName().fieldType == getSType(),
71 "ripple::STNumber::add : field type match");
74}
75
76Number const&
78{
79 return value_;
80}
81
82void
84{
85 value_ = v;
86}
87
88STBase*
89STNumber::copy(std::size_t n, void* buf) const
90{
91 return emplace(n, buf, *this);
92}
93
94STBase*
96{
97 return emplace(n, buf, std::move(*this));
98}
99
100bool
102{
103 XRPL_ASSERT(
104 t.getSType() == this->getSType(),
105 "ripple::STNumber::isEquivalent : field type match");
106 STNumber const& v = dynamic_cast<STNumber const&>(t);
107 return value_ == v;
108}
109
110bool
112{
113 return value_ == Number();
114}
115
118{
119 return out << rhs.getText();
120}
121
122NumberParts
124{
125 static boost::regex const reNumber(
126 "^" // the beginning of the string
127 "([-+]?)" // (optional) + or - character
128 "(0|[1-9][0-9]*)" // a number (no leading zeroes, unless 0)
129 "(\\.([0-9]+))?" // (optional) period followed by any number
130 "([eE]([+-]?)([0-9]+))?" // (optional) E, optional + or -, any number
131 "$",
132 boost::regex_constants::optimize);
133
134 boost::smatch match;
135
136 if (!boost::regex_match(number, match, reNumber))
137 Throw<std::runtime_error>("'" + number + "' is not a number");
138
139 // Match fields:
140 // 0 = whole input
141 // 1 = sign
142 // 2 = integer portion
143 // 3 = whole fraction (with '.')
144 // 4 = fraction (without '.')
145 // 5 = whole exponent (with 'e')
146 // 6 = exponent sign
147 // 7 = exponent number
148
149 bool negative = (match[1].matched && (match[1] == "-"));
150
151 std::uint64_t mantissa;
152 int exponent;
153
154 if (!match[4].matched) // integer only
155 {
156 mantissa = boost::lexical_cast<std::uint64_t>(std::string(match[2]));
157 exponent = 0;
158 }
159 else
160 {
161 // integer and fraction
162 mantissa = boost::lexical_cast<std::uint64_t>(match[2] + match[4]);
163 exponent = -(match[4].length());
164 }
165
166 if (match[5].matched)
167 {
168 // we have an exponent
169 if (match[6].matched && (match[6] == "-"))
170 exponent -= boost::lexical_cast<int>(std::string(match[7]));
171 else
172 exponent += boost::lexical_cast<int>(std::string(match[7]));
173 }
174
175 return {mantissa, exponent, negative};
176}
177
178STNumber
179numberFromJson(SField const& field, Json::Value const& value)
180{
181 NumberParts parts;
182
183 if (value.isInt())
184 {
185 if (value.asInt() >= 0)
186 {
187 parts.mantissa = value.asInt();
188 }
189 else
190 {
191 parts.mantissa = -value.asInt();
192 parts.negative = true;
193 }
194 }
195 else if (value.isUInt())
196 {
197 parts.mantissa = value.asUInt();
198 }
199 else if (value.isString())
200 {
201 parts = partsFromString(value.asString());
202 // Only strings can represent out-of-range values.
204 Throw<std::range_error>("too high");
205 }
206 else
207 {
208 Throw<std::runtime_error>("not a number");
209 }
210
211 std::int64_t mantissa = parts.mantissa;
212 if (parts.negative)
213 mantissa = -mantissa;
214
215 return STNumber{field, Number{mantissa, parts.exponent}};
216}
217
218} // namespace ripple
Represents a JSON value.
Definition json_value.h:149
Int asInt() const
bool isString() const
UInt asUInt() const
std::string asString() const
Returns the unquoted string value.
bool isUInt() const
bool isInt() const
constexpr int exponent() const noexcept
Definition Number.h:236
constexpr rep mantissa() const noexcept
Definition Number.h:230
Identifies fields.
Definition SField.h:146
A type which can be exported to a well known binary format.
Definition STBase.h:135
virtual SerializedTypeID getSType() const
Definition STBase.cpp:75
SField const & getFName() const
Definition STBase.cpp:143
static STBase * emplace(std::size_t n, void *buf, T &&val)
Definition STBase.h:233
A serializable number.
Definition STNumber.h:43
SerializedTypeID getSType() const override
Definition STNumber.cpp:53
bool isDefault() const override
Definition STNumber.cpp:111
void add(Serializer &s) const override
Definition STNumber.cpp:65
STNumber()=default
std::string getText() const override
Definition STNumber.cpp:59
void setValue(Number const &v)
Definition STNumber.cpp:83
STBase * move(std::size_t n, void *buf) override
Definition STNumber.cpp:95
Number const & value() const
Definition STNumber.cpp:77
STBase * copy(std::size_t n, void *buf) const override
Definition STNumber.cpp:89
bool isEquivalent(STBase const &t) const override
Definition STNumber.cpp:101
std::int64_t geti64()
std::int32_t geti32()
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:25
NumberParts partsFromString(std::string const &number)
Definition STNumber.cpp:123
SerializedTypeID
Definition SField.h:110
std::ostream & operator<<(std::ostream &out, base_uint< Bits, Tag > const &u)
Definition base_uint.h:647
STNumber numberFromJson(SField const &field, Json::Value const &value)
Definition STNumber.cpp:179
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:630
std::uint64_t mantissa
Definition STNumber.h:95