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>
38concept Valid =
40
48template <class T>
49concept Usable = Valid<T> &&
53
54template <class Other, class VU>
57
58template <class T>
60
61template <class VU>
63
64template <class VU1, class VU2>
67
68template <class UnitTag, class T>
69class ValueUnit : private boost::totally_ordered<ValueUnit<UnitTag, T>>,
70 private boost::additive<ValueUnit<UnitTag, T>>,
71 private boost::equality_comparable<ValueUnit<UnitTag, T>, T>,
72 private boost::dividable<ValueUnit<UnitTag, T>, T>,
73 private boost::modable<ValueUnit<UnitTag, T>, T>,
74 private boost::unit_steppable<ValueUnit<UnitTag, T>>
75{
76public:
77 using unit_type = UnitTag;
78 using value_type = T;
79
80private:
82
83public:
84 ValueUnit() = default;
85 constexpr ValueUnit(ValueUnit const& other) = default;
86 constexpr ValueUnit&
87 operator=(ValueUnit const& other) = default;
88
89 constexpr explicit ValueUnit(beast::Zero) : value_(0)
90 {
91 }
92
93 constexpr ValueUnit&
95 {
96 value_ = 0;
97 return *this;
98 }
99
100 constexpr explicit ValueUnit(value_type value) : value_(value)
101 {
102 }
103
104 constexpr ValueUnit&
106 {
107 value_ = value;
108 return *this;
109 }
110
114 template <Compatible<ValueUnit> Other>
117 : ValueUnit(safe_cast<value_type>(value.value()))
118 {
119 }
120
121 constexpr ValueUnit
122 operator+(value_type const& rhs) const
123 {
124 return ValueUnit{value_ + rhs};
125 }
126
127 friend constexpr ValueUnit
129 {
130 // addition is commutative
131 return rhs + lhs;
132 }
133
134 constexpr ValueUnit
135 operator-(value_type const& rhs) const
136 {
137 return ValueUnit{value_ - rhs};
138 }
139
140 friend constexpr ValueUnit
142 {
143 // subtraction is NOT commutative, but (lhs + (-rhs)) is addition, which
144 // is
145 return -rhs + lhs;
146 }
147
148 constexpr ValueUnit
149 operator*(value_type const& rhs) const
150 {
151 return ValueUnit{value_ * rhs};
152 }
153
154 friend constexpr ValueUnit
156 {
157 // multiplication is commutative
158 return rhs * lhs;
159 }
160
161 constexpr value_type
162 operator/(ValueUnit const& rhs) const
163 {
164 return value_ / rhs.value_;
165 }
166
167 ValueUnit&
168 operator+=(ValueUnit const& other)
169 {
170 value_ += other.value();
171 return *this;
172 }
173
174 ValueUnit&
175 operator-=(ValueUnit const& other)
176 {
177 value_ -= other.value();
178 return *this;
179 }
180
181 ValueUnit&
183 {
184 ++value_;
185 return *this;
186 }
187
188 ValueUnit&
190 {
191 --value_;
192 return *this;
193 }
194
195 ValueUnit&
197 {
198 value_ *= rhs;
199 return *this;
200 }
201
202 ValueUnit&
204 {
205 value_ /= rhs;
206 return *this;
207 }
208
209 template <Integral transparent = value_type>
210 ValueUnit&
212 {
213 value_ %= rhs;
214 return *this;
215 }
216
218 operator-() const
219 {
220 static_assert(std::is_signed_v<T>, "- operator illegal on unsigned value types");
221 return ValueUnit{-value_};
222 }
223
224 constexpr bool
225 operator==(ValueUnit const& other) const
226 {
227 return value_ == other.value_;
228 }
229
230 template <Compatible<ValueUnit> Other>
231 constexpr bool
233 {
234 return value_ == other.value();
235 }
236
237 constexpr bool
239 {
240 return value_ == other;
241 }
242
243 template <Compatible<ValueUnit> Other>
244 constexpr bool
246 {
247 return !operator==(other);
248 }
249
250 constexpr bool
251 operator<(ValueUnit const& other) const
252 {
253 return value_ < other.value_;
254 }
255
257 explicit constexpr
258 operator bool() const noexcept
259 {
260 return value_ != 0;
261 }
262
264 constexpr int
265 signum() const noexcept
266 {
267 return (value_ < 0) ? -1 : (value_ ? 1 : 0);
268 }
269
271 // TODO: Move this to a new class, maybe with the old "TaggedFee" name
272 constexpr value_type
273 fee() const
274 {
275 return value_;
276 }
277
278 template <class Other>
279 constexpr double
281 {
282 return static_cast<double>(value_) / reference.value();
283 }
284
285 // `Usable` is checked to ensure that only values with
286 // known valid type tags can be converted to JSON. At the time
287 // of implementation, that includes all known tags, but more may
288 // be added in the future.
291 requires Usable<ValueUnit>
292 {
293 if constexpr (std::is_integral_v<value_type>)
294 {
296
297 constexpr auto min = std::numeric_limits<jsontype>::min();
298 constexpr auto max = std::numeric_limits<jsontype>::max();
299
300 if (value_ < min)
301 return min;
302 if (value_ > max)
303 return max;
304 return static_cast<jsontype>(value_);
305 }
306 else
307 {
308 return value_;
309 }
310 }
311
316 constexpr value_type
317 value() const
318 {
319 return value_;
320 }
321
322 friend std::istream&
324 {
325 s >> val.value_;
326 return s;
327 }
328};
329
330// Output Values as just their numeric value.
331template <class Char, class Traits, class UnitTag, class T>
333operator<<(std::basic_ostream<Char, Traits>& os, ValueUnit<UnitTag, T> const& q)
334{
335 return os << q.value();
336}
337
338template <class UnitTag, class T>
341{
342 return std::to_string(amount.value());
343}
344
345template <class Source>
347
348template <class Dest>
349concept muldivDest = muldivSource<Dest> && // Dest is also a source
351 sizeof(typename Dest::value_type) >= sizeof(std::uint64_t);
352
353template <class Source2, class Source1>
356
357template <class Dest, class Source1, class Source2>
359// Source and Dest can be the same by default
360
361template <class Dest, class Source1, class Source2>
364
365template <class T>
366ValueUnit<unitlessTag, T>
367scalar(T value)
368{
369 return ValueUnit<unitlessTag, T>{value};
370}
371
372template <class Source1, class Source2, unit::muldivable<Source1, Source2> Dest>
374mulDivU(Source1 value, Dest mul, Source2 div)
375{
376 // values can never be negative in any context.
377 if (value.value() < 0 || mul.value() < 0 || div.value() < 0)
378 {
379 // split the asserts so if one hits, the user can tell which
380 // without a debugger.
381 XRPL_ASSERT(value.value() >= 0, "xrpl::unit::mulDivU : minimum value input");
382 XRPL_ASSERT(mul.value() >= 0, "xrpl::unit::mulDivU : minimum mul input");
383 XRPL_ASSERT(div.value() > 0, "xrpl::unit::mulDivU : minimum div input");
384 return std::nullopt;
385 }
386
387 using desttype = typename Dest::value_type;
388 constexpr auto max = std::numeric_limits<desttype>::max();
389
390 // Shortcuts, since these happen a lot in the real world
391 if (value == div)
392 return mul;
393 if (mul.value() == div.value())
394 {
395 if (value.value() > max)
396 return std::nullopt;
397 return Dest{static_cast<desttype>(value.value())};
398 }
399
400 using namespace boost::multiprecision;
401
402 uint128_t product;
403 product = multiply(product, static_cast<std::uint64_t>(value.value()), static_cast<std::uint64_t>(mul.value()));
404
405 auto quotient = product / div.value();
406
407 if (quotient > max)
408 return std::nullopt;
409
410 return Dest{static_cast<desttype>(quotient)};
411}
412
413} // namespace unit
414
415// Fee Levels
416template <class T>
420
421// Basis points (Bips)
422template <class T>
426template <class T>
430
431template <class Source1, class Source2, unit::muldivable<Source1, Source2> Dest>
433mulDiv(Source1 value, Dest mul, Source2 div)
434{
435 return unit::mulDivU(value, mul, div);
436}
437
438template <class Source1, class Source2, unit::muldivCommutable<Source1, Source2> Dest>
440mulDiv(Dest value, Source1 mul, Source2 div)
441{
442 // Multiplication is commutative
443 return unit::mulDivU(mul, value, div);
444}
445
446template <unit::muldivDest Dest>
448mulDiv(std::uint64_t value, Dest mul, std::uint64_t div)
449{
450 // Give the scalars a non-tag so the
451 // unit-handling version gets called.
452 return unit::mulDivU(unit::scalar(value), mul, unit::scalar(div));
453}
454
455template <unit::muldivDest Dest>
457mulDiv(Dest value, std::uint64_t mul, std::uint64_t div)
458{
459 // Multiplication is commutative
460 return mulDiv(mul, value, div);
461}
462
463template <unit::muldivSource Source1, unit::muldivSources<Source1> Source2>
465mulDiv(Source1 value, std::uint64_t mul, Source2 div)
466{
467 // Give the scalars a dimensionless unit so the
468 // unit-handling version gets called.
469 auto unitresult = unit::mulDivU(value, unit::scalar(mul), div);
470
471 if (!unitresult)
472 return std::nullopt;
473
474 return unitresult->value();
475}
476
477template <unit::muldivSource Source1, unit::muldivSources<Source1> Source2>
479mulDiv(std::uint64_t value, Source1 mul, Source2 div)
480{
481 // Multiplication is commutative
482 return mulDiv(mul, value, div);
483}
484
485template <unit::IntegralValue Dest, unit::CastableValue<Dest> Src>
486constexpr Dest
487safe_cast(Src s) noexcept
488{
489 // Dest may not have an explicit value constructor
490 return Dest{safe_cast<typename Dest::value_type>(s.value())};
491}
492
493template <unit::IntegralValue Dest, unit::Integral 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)};
499}
500
501template <unit::IntegralValue Dest, unit::CastableValue<Dest> Src>
502constexpr Dest
503unsafe_cast(Src s) noexcept
504{
505 // Dest may not have an explicit value constructor
506 return Dest{unsafe_cast<typename Dest::value_type>(s.value())};
507}
508
509template <unit::IntegralValue Dest, unit::Integral 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)};
515}
516
517} // namespace xrpl
Represents a JSON value.
Definition json_value.h:130
constexpr ValueUnit(value_type value)
Definition Units.h:100
constexpr int signum() const noexcept
Return the sign of the amount.
Definition Units.h:265
friend constexpr ValueUnit operator*(value_type lhs, ValueUnit const &rhs)
Definition Units.h:155
constexpr value_type value() const
Returns the underlying value.
Definition Units.h:317
constexpr bool operator<(ValueUnit const &other) const
Definition Units.h:251
friend std::istream & operator>>(std::istream &s, ValueUnit &val)
Definition Units.h:323
ValueUnit & operator+=(ValueUnit const &other)
Definition Units.h:168
constexpr bool operator==(value_type other) const
Definition Units.h:238
constexpr bool operator==(ValueUnit const &other) const
Definition Units.h:225
constexpr bool operator==(ValueUnit< unit_type, Other > const &other) const
Definition Units.h:232
constexpr ValueUnit & operator=(value_type value)
Definition Units.h:105
constexpr ValueUnit(ValueUnit const &other)=default
constexpr ValueUnit & operator=(beast::Zero)
Definition Units.h:94
ValueUnit & operator/=(value_type const &rhs)
Definition Units.h:203
constexpr ValueUnit operator*(value_type const &rhs) const
Definition Units.h:149
constexpr ValueUnit operator-(value_type const &rhs) const
Definition Units.h:135
ValueUnit & operator++()
Definition Units.h:182
constexpr bool operator!=(ValueUnit< unit_type, Other > const &other) const
Definition Units.h:245
ValueUnit & operator%=(value_type const &rhs)
Definition Units.h:211
constexpr ValueUnit & operator=(ValueUnit const &other)=default
ValueUnit operator-() const
Definition Units.h:218
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:115
constexpr ValueUnit(beast::Zero)
Definition Units.h:89
UnitTag unit_type
Definition Units.h:77
ValueUnit & operator--()
Definition Units.h:189
constexpr value_type fee() const
Returns the number of drops.
Definition Units.h:273
friend constexpr ValueUnit operator-(value_type lhs, ValueUnit const &rhs)
Definition Units.h:141
ValueUnit & operator*=(value_type const &rhs)
Definition Units.h:196
constexpr value_type operator/(ValueUnit const &rhs) const
Definition Units.h:162
Json::Value jsonClipped() const
Definition Units.h:290
ValueUnit & operator-=(ValueUnit const &other)
Definition Units.h:175
constexpr ValueUnit operator+(value_type const &rhs) const
Definition Units.h:122
friend constexpr ValueUnit operator+(value_type lhs, ValueUnit const &rhs)
Definition Units.h:128
constexpr double decimalFromReference(ValueUnit< unit_type, Other > reference) const
Definition Units.h:280
value_type value_
Definition Units.h:81
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:374
std::basic_ostream< Char, Traits > & operator<<(std::basic_ostream< Char, Traits > &os, ValueUnit< UnitTag, T > const &q)
Definition Units.h:333
std::string to_string(ValueUnit< UnitTag, T > const &amount)
Definition Units.h:340
ValueUnit< unitlessTag, T > scalar(T value)
Definition Units.h:367
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:47
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:19
Zero allows classes to offer efficient comparisons to zero.
Definition Zero.h:25
T to_string(T... args)