rippled
Loading...
Searching...
No Matches
Units.h
1#pragma once
2
3#include <xrpl/basics/safe_cast.h>
4#include <xrpl/beast/utility/Zero.h>
5#include <xrpl/beast/utility/instrumentation.h>
6#include <xrpl/json/json_value.h>
7
8#include <boost/multiprecision/cpp_int.hpp>
9#include <boost/operators.hpp>
10
11#include <iosfwd>
12#include <limits>
13#include <optional>
14
15namespace xrpl {
16
17namespace unit {
18
21struct dropTag;
25struct feelevelTag;
28struct unitlessTag;
29
31class BipsTag;
32class TenthBipsTag;
33
34// These names don't have to be too descriptive, because we're in the "unit"
35// namespace.
36
37template <class T>
40
48template <class T>
49concept Usable = Valid<T> &&
55
56template <class Other, class VU>
57concept Compatible =
60
61template <class T>
63
64template <class VU>
66
67template <class VU1, class VU2>
70
71template <class UnitTag, class T>
72class ValueUnit : private boost::totally_ordered<ValueUnit<UnitTag, T>>,
73 private boost::additive<ValueUnit<UnitTag, T>>,
74 private boost::equality_comparable<ValueUnit<UnitTag, T>, T>,
75 private boost::dividable<ValueUnit<UnitTag, T>, T>,
76 private boost::modable<ValueUnit<UnitTag, T>, T>,
77 private boost::unit_steppable<ValueUnit<UnitTag, T>>
78{
79public:
80 using unit_type = UnitTag;
81 using value_type = T;
82
83private:
85
86public:
87 ValueUnit() = default;
88 constexpr ValueUnit(ValueUnit const& other) = default;
89 constexpr ValueUnit&
90 operator=(ValueUnit const& other) = default;
91
92 constexpr explicit ValueUnit(beast::Zero) : value_(0)
93 {
94 }
95
96 constexpr ValueUnit&
98 {
99 value_ = 0;
100 return *this;
101 }
102
103 constexpr explicit ValueUnit(value_type value) : value_(value)
104 {
105 }
106
107 constexpr ValueUnit&
109 {
110 value_ = value;
111 return *this;
112 }
113
117 template <Compatible<ValueUnit> Other>
120 : ValueUnit(safe_cast<value_type>(value.value()))
121 {
122 }
123
124 constexpr ValueUnit
125 operator+(value_type const& rhs) const
126 {
127 return ValueUnit{value_ + rhs};
128 }
129
130 friend constexpr ValueUnit
132 {
133 // addition is commutative
134 return rhs + lhs;
135 }
136
137 constexpr ValueUnit
138 operator-(value_type const& rhs) const
139 {
140 return ValueUnit{value_ - rhs};
141 }
142
143 friend constexpr ValueUnit
145 {
146 // subtraction is NOT commutative, but (lhs + (-rhs)) is addition, which
147 // is
148 return -rhs + lhs;
149 }
150
151 constexpr ValueUnit
152 operator*(value_type const& rhs) const
153 {
154 return ValueUnit{value_ * rhs};
155 }
156
157 friend constexpr ValueUnit
159 {
160 // multiplication is commutative
161 return rhs * lhs;
162 }
163
164 constexpr value_type
165 operator/(ValueUnit const& rhs) const
166 {
167 return value_ / rhs.value_;
168 }
169
170 ValueUnit&
171 operator+=(ValueUnit const& other)
172 {
173 value_ += other.value();
174 return *this;
175 }
176
177 ValueUnit&
178 operator-=(ValueUnit const& other)
179 {
180 value_ -= other.value();
181 return *this;
182 }
183
184 ValueUnit&
186 {
187 ++value_;
188 return *this;
189 }
190
191 ValueUnit&
193 {
194 --value_;
195 return *this;
196 }
197
198 ValueUnit&
200 {
201 value_ *= rhs;
202 return *this;
203 }
204
205 ValueUnit&
207 {
208 value_ /= rhs;
209 return *this;
210 }
211
212 template <Integral transparent = value_type>
213 ValueUnit&
215 {
216 value_ %= rhs;
217 return *this;
218 }
219
221 operator-() const
222 {
223 static_assert(std::is_signed_v<T>, "- operator illegal on unsigned value types");
224 return ValueUnit{-value_};
225 }
226
227 constexpr bool
228 operator==(ValueUnit const& other) const
229 {
230 return value_ == other.value_;
231 }
232
233 template <Compatible<ValueUnit> Other>
234 constexpr bool
236 {
237 return value_ == other.value();
238 }
239
240 constexpr bool
242 {
243 return value_ == other;
244 }
245
246 template <Compatible<ValueUnit> Other>
247 constexpr bool
249 {
250 return !operator==(other);
251 }
252
253 constexpr bool
254 operator<(ValueUnit const& other) const
255 {
256 return value_ < other.value_;
257 }
258
260 explicit constexpr
261 operator bool() const noexcept
262 {
263 return value_ != 0;
264 }
265
267 constexpr int
268 signum() const noexcept
269 {
270 return (value_ < 0) ? -1 : (value_ ? 1 : 0);
271 }
272
274 // TODO: Move this to a new class, maybe with the old "TaggedFee" name
275 constexpr value_type
276 fee() const
277 {
278 return value_;
279 }
280
281 template <class Other>
282 constexpr double
284 {
285 return static_cast<double>(value_) / reference.value();
286 }
287
288 // `Usable` is checked to ensure that only values with
289 // known valid type tags can be converted to JSON. At the time
290 // of implementation, that includes all known tags, but more may
291 // be added in the future.
294 requires Usable<ValueUnit>
295 {
296 if constexpr (std::is_integral_v<value_type>)
297 {
298 using jsontype =
300
301 constexpr auto min = std::numeric_limits<jsontype>::min();
302 constexpr auto max = std::numeric_limits<jsontype>::max();
303
304 if (value_ < min)
305 return min;
306 if (value_ > max)
307 return max;
308 return static_cast<jsontype>(value_);
309 }
310 else
311 {
312 return value_;
313 }
314 }
315
320 constexpr value_type
321 value() const
322 {
323 return value_;
324 }
325
326 friend std::istream&
328 {
329 s >> val.value_;
330 return s;
331 }
332};
333
334// Output Values as just their numeric value.
335template <class Char, class Traits, class UnitTag, class T>
337operator<<(std::basic_ostream<Char, Traits>& os, ValueUnit<UnitTag, T> const& q)
338{
339 return os << q.value();
340}
341
342template <class UnitTag, class T>
345{
346 return std::to_string(amount.value());
347}
348
349template <class Source>
352
353template <class Dest>
354concept muldivDest = muldivSource<Dest> && // Dest is also a source
356 sizeof(typename Dest::value_type) >= sizeof(std::uint64_t);
357
358template <class Source2, class Source1>
361
362template <class Dest, class Source1, class Source2>
364// Source and Dest can be the same by default
365
366template <class Dest, class Source1, class Source2>
369
370template <class T>
371ValueUnit<unitlessTag, T>
372scalar(T value)
373{
374 return ValueUnit<unitlessTag, T>{value};
375}
376
377template <class Source1, class Source2, unit::muldivable<Source1, Source2> Dest>
379mulDivU(Source1 value, Dest mul, Source2 div)
380{
381 // values can never be negative in any context.
382 if (value.value() < 0 || mul.value() < 0 || div.value() < 0)
383 {
384 // split the asserts so if one hits, the user can tell which
385 // without a debugger.
386 XRPL_ASSERT(value.value() >= 0, "xrpl::unit::mulDivU : minimum value input");
387 XRPL_ASSERT(mul.value() >= 0, "xrpl::unit::mulDivU : minimum mul input");
388 XRPL_ASSERT(div.value() > 0, "xrpl::unit::mulDivU : minimum div input");
389 return std::nullopt;
390 }
391
392 using desttype = typename Dest::value_type;
393 constexpr auto max = std::numeric_limits<desttype>::max();
394
395 // Shortcuts, since these happen a lot in the real world
396 if (value == div)
397 return mul;
398 if (mul.value() == div.value())
399 {
400 if (value.value() > max)
401 return std::nullopt;
402 return Dest{static_cast<desttype>(value.value())};
403 }
404
405 using namespace boost::multiprecision;
406
407 uint128_t product;
408 product = multiply(
409 product,
410 static_cast<std::uint64_t>(value.value()),
411 static_cast<std::uint64_t>(mul.value()));
412
413 auto quotient = product / div.value();
414
415 if (quotient > max)
416 return std::nullopt;
417
418 return Dest{static_cast<desttype>(quotient)};
419}
420
421} // namespace unit
422
423// Fee Levels
424template <class T>
428
429// Basis points (Bips)
430template <class T>
434template <class T>
438
439template <class Source1, class Source2, unit::muldivable<Source1, Source2> Dest>
441mulDiv(Source1 value, Dest mul, Source2 div)
442{
443 return unit::mulDivU(value, mul, div);
444}
445
446template <class Source1, class Source2, unit::muldivCommutable<Source1, Source2> Dest>
448mulDiv(Dest value, Source1 mul, Source2 div)
449{
450 // Multiplication is commutative
451 return unit::mulDivU(mul, value, div);
452}
453
454template <unit::muldivDest Dest>
456mulDiv(std::uint64_t value, Dest mul, std::uint64_t div)
457{
458 // Give the scalars a non-tag so the
459 // unit-handling version gets called.
460 return unit::mulDivU(unit::scalar(value), mul, unit::scalar(div));
461}
462
463template <unit::muldivDest Dest>
465mulDiv(Dest value, std::uint64_t mul, std::uint64_t div)
466{
467 // Multiplication is commutative
468 return mulDiv(mul, value, div);
469}
470
471template <unit::muldivSource Source1, unit::muldivSources<Source1> Source2>
473mulDiv(Source1 value, std::uint64_t mul, Source2 div)
474{
475 // Give the scalars a dimensionless unit so the
476 // unit-handling version gets called.
477 auto unitresult = unit::mulDivU(value, unit::scalar(mul), div);
478
479 if (!unitresult)
480 return std::nullopt;
481
482 return unitresult->value();
483}
484
485template <unit::muldivSource Source1, unit::muldivSources<Source1> Source2>
487mulDiv(std::uint64_t value, Source1 mul, Source2 div)
488{
489 // Multiplication is commutative
490 return mulDiv(mul, value, div);
491}
492
493template <unit::IntegralValue Dest, unit::CastableValue<Dest> Src>
494constexpr Dest
495safe_cast(Src s) noexcept
496{
497 // Dest may not have an explicit value constructor
498 return Dest{safe_cast<typename Dest::value_type>(s.value())};
499}
500
501template <unit::IntegralValue Dest, unit::Integral Src>
502constexpr Dest
503safe_cast(Src s) noexcept
504{
505 // Dest may not have an explicit value constructor
506 return Dest{safe_cast<typename Dest::value_type>(s)};
507}
508
509template <unit::IntegralValue Dest, unit::CastableValue<Dest> Src>
510constexpr Dest
511unsafe_cast(Src s) noexcept
512{
513 // Dest may not have an explicit value constructor
514 return Dest{unsafe_cast<typename Dest::value_type>(s.value())};
515}
516
517template <unit::IntegralValue Dest, unit::Integral Src>
518constexpr Dest
519unsafe_cast(Src s) noexcept
520{
521 // Dest may not have an explicit value constructor
522 return Dest{unsafe_cast<typename Dest::value_type>(s)};
523}
524
525} // namespace xrpl
Represents a JSON value.
Definition json_value.h:130
constexpr ValueUnit(value_type value)
Definition Units.h:103
constexpr int signum() const noexcept
Return the sign of the amount.
Definition Units.h:268
friend constexpr ValueUnit operator*(value_type lhs, ValueUnit const &rhs)
Definition Units.h:158
constexpr value_type value() const
Returns the underlying value.
Definition Units.h:321
constexpr bool operator<(ValueUnit const &other) const
Definition Units.h:254
friend std::istream & operator>>(std::istream &s, ValueUnit &val)
Definition Units.h:327
ValueUnit & operator+=(ValueUnit const &other)
Definition Units.h:171
constexpr bool operator==(value_type other) const
Definition Units.h:241
constexpr bool operator==(ValueUnit const &other) const
Definition Units.h:228
constexpr bool operator==(ValueUnit< unit_type, Other > const &other) const
Definition Units.h:235
constexpr ValueUnit & operator=(value_type value)
Definition Units.h:108
constexpr ValueUnit(ValueUnit const &other)=default
constexpr ValueUnit & operator=(beast::Zero)
Definition Units.h:97
ValueUnit & operator/=(value_type const &rhs)
Definition Units.h:206
constexpr ValueUnit operator*(value_type const &rhs) const
Definition Units.h:152
constexpr ValueUnit operator-(value_type const &rhs) const
Definition Units.h:138
ValueUnit & operator++()
Definition Units.h:185
constexpr bool operator!=(ValueUnit< unit_type, Other > const &other) const
Definition Units.h:248
ValueUnit & operator%=(value_type const &rhs)
Definition Units.h:214
constexpr ValueUnit & operator=(ValueUnit const &other)=default
ValueUnit operator-() const
Definition Units.h:221
constexpr ValueUnit(ValueUnit< unit_type, Other > const &value)
Instances with the same unit, and a type that is "safe" to convert to this one can be converted impli...
Definition Units.h:118
constexpr ValueUnit(beast::Zero)
Definition Units.h:92
UnitTag unit_type
Definition Units.h:80
ValueUnit & operator--()
Definition Units.h:192
constexpr value_type fee() const
Returns the number of drops.
Definition Units.h:276
friend constexpr ValueUnit operator-(value_type lhs, ValueUnit const &rhs)
Definition Units.h:144
ValueUnit & operator*=(value_type const &rhs)
Definition Units.h:199
constexpr value_type operator/(ValueUnit const &rhs) const
Definition Units.h:165
Json::Value jsonClipped() const
Definition Units.h:293
ValueUnit & operator-=(ValueUnit const &other)
Definition Units.h:178
constexpr ValueUnit operator+(value_type const &rhs) const
Definition Units.h:125
friend constexpr ValueUnit operator+(value_type lhs, ValueUnit const &rhs)
Definition Units.h:131
constexpr double decimalFromReference(ValueUnit< unit_type, Other > reference) const
Definition Units.h:283
value_type value_
Definition Units.h:84
Usable is checked to ensure that only values with known valid type tags can be used (sometimes transp...
Definition Units.h:49
T is_same_v
T max(T... args)
T min(T... args)
int Int
unsigned int UInt
std::optional< Dest > mulDivU(Source1 value, Dest mul, Source2 div)
Definition Units.h:379
std::basic_ostream< Char, Traits > & operator<<(std::basic_ostream< Char, Traits > &os, ValueUnit< UnitTag, T > const &q)
Definition Units.h:337
std::string to_string(ValueUnit< UnitTag, T > const &amount)
Definition Units.h:344
ValueUnit< unitlessTag, T > scalar(T value)
Definition Units.h:372
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
std::optional< std::uint64_t > mulDiv(std::uint64_t value, std::uint64_t mul, std::uint64_t div)
Return value*mul/div accurately.
STAmount multiply(STAmount const &amount, Rate const &rate)
Definition Rate2.cpp:34
constexpr std::enable_if_t< std::is_integral_v< Dest > &&std::is_integral_v< Src >, Dest > unsafe_cast(Src s) noexcept
Definition safe_cast.h:52
constexpr std::enable_if_t< std::is_integral_v< Dest > &&std::is_integral_v< Src >, Dest > safe_cast(Src s) noexcept
Definition safe_cast.h:21
Zero allows classes to offer efficient comparisons to zero.
Definition Zero.h:25
T to_string(T... args)