xrpld
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>
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 [[nodiscard]] constexpr int
268 signum() const noexcept
269 {
270 if (value_ < 0)
271 return -1;
272 return value_ ? 1 : 0;
273 }
274
276 // TODO: Move this to a new class, maybe with the old "TaggedFee" name
277 [[nodiscard]] constexpr value_type
278 fee() const
279 {
280 return value_;
281 }
282
283 template <class Other>
284 [[nodiscard]] constexpr double
286 {
287 return static_cast<double>(value_) / reference.value();
288 }
289
290 // `Usable` is checked to ensure that only values with
291 // known valid type tags can be converted to JSON. At the time
292 // of implementation, that includes all known tags, but more may
293 // be added in the future.
294 [[nodiscard]] json::Value
296 requires Usable<ValueUnit>
297 {
298 if constexpr (std::is_integral_v<value_type>)
299 {
300 using jsontype =
302
303 constexpr auto kMin = std::numeric_limits<jsontype>::min();
304 constexpr auto kMax = std::numeric_limits<jsontype>::max();
305
306 if (value_ < kMin)
307 return kMin;
308 if (value_ > kMax)
309 return kMax;
310 return static_cast<jsontype>(value_);
311 }
312 else
313 {
314 return value_;
315 }
316 }
317
322 [[nodiscard]] constexpr value_type
323 value() const
324 {
325 return value_;
326 }
327
328 friend std::istream&
330 {
331 s >> val.value_;
332 return s;
333 }
334};
335
336// Output Values as just their numeric value.
337template <class Char, class Traits, class UnitTag, class T>
339operator<<(std::basic_ostream<Char, Traits>& os, ValueUnit<UnitTag, T> const& q)
340{
341 return os << q.value();
342}
343
344template <class UnitTag, class T>
347{
348 return std::to_string(amount.value());
349}
350
351template <class Source>
354
355template <class Dest>
356concept muldivDest = muldivSource<Dest> && // Dest is also a source
358 sizeof(typename Dest::value_type) >= sizeof(std::uint64_t);
359
360template <class Source2, class Source1>
363
364template <class Dest, class Source1, class Source2>
366// Source and Dest can be the same by default
367
368template <class Dest, class Source1, class Source2>
371
372template <class T>
374scalar(T value)
375{
376 return ValueUnit<unitlessTag, T>{value};
377}
378
379template <class Source1, class Source2, unit::muldivable<Source1, Source2> Dest>
381mulDivU(Source1 value, Dest mul, Source2 div)
382{
383 // values can never be negative in any context.
384 if (value.value() < 0 || mul.value() < 0 || div.value() < 0)
385 {
386 // split the asserts so if one hits, the user can tell which
387 // without a debugger.
388 XRPL_ASSERT(value.value() >= 0, "xrpl::unit::mulDivU : minimum value input");
389 XRPL_ASSERT(mul.value() >= 0, "xrpl::unit::mulDivU : minimum mul input");
390 XRPL_ASSERT(div.value() > 0, "xrpl::unit::mulDivU : minimum div input");
391 return std::nullopt;
392 }
393
394 using desttype = Dest::value_type;
395 constexpr auto kMax = std::numeric_limits<desttype>::max();
396
397 // Shortcuts, since these happen a lot in the real world
398 if (value == div)
399 return mul;
400 if (mul.value() == div.value())
401 {
402 if (value.value() > kMax)
403 return std::nullopt;
404 return Dest{static_cast<desttype>(value.value())};
405 }
406
407 using namespace boost::multiprecision;
408
409 uint128_t product;
410 product = multiply(
411 product,
412 static_cast<std::uint64_t>(value.value()),
413 static_cast<std::uint64_t>(mul.value()));
414
415 auto quotient = product / div.value();
416
417 if (quotient > kMax)
418 return std::nullopt;
419
420 return Dest{static_cast<desttype>(quotient)};
421}
422
423} // namespace unit
424
425// Fee Levels
426template <class T>
430
431// Basis points (Bips)
432template <class T>
436template <class T>
440
441template <class Source1, class Source2, unit::muldivable<Source1, Source2> Dest>
443mulDiv(Source1 value, Dest mul, Source2 div)
444{
445 return unit::mulDivU(value, mul, div);
446}
447
448template <class Source1, class Source2, unit::muldivCommutable<Source1, Source2> Dest>
450mulDiv(Dest value, Source1 mul, Source2 div)
451{
452 // Multiplication is commutative
453 return unit::mulDivU(mul, value, div);
454}
455
456template <unit::muldivDest Dest>
458mulDiv(std::uint64_t value, Dest mul, std::uint64_t div)
459{
460 // Give the scalars a non-tag so the
461 // unit-handling version gets called.
462 return unit::mulDivU(unit::scalar(value), mul, unit::scalar(div));
463}
464
465template <unit::muldivDest Dest>
467mulDiv(Dest value, std::uint64_t mul, std::uint64_t div)
468{
469 // Multiplication is commutative
470 return mulDiv(mul, value, div);
471}
472
473template <unit::muldivSource Source1, unit::muldivSources<Source1> Source2>
475mulDiv(Source1 value, std::uint64_t mul, Source2 div)
476{
477 // Give the scalars a dimensionless unit so the
478 // unit-handling version gets called.
479 auto unitresult = unit::mulDivU(value, unit::scalar(mul), div);
480
481 if (!unitresult)
482 return std::nullopt;
483
484 return unitresult->value();
485}
486
487template <unit::muldivSource Source1, unit::muldivSources<Source1> Source2>
489mulDiv(std::uint64_t value, Source1 mul, Source2 div)
490{
491 // Multiplication is commutative
492 return mulDiv(mul, value, div);
493}
494
495template <unit::IntegralValue Dest, unit::CastableValue<Dest> Src>
496constexpr Dest
497safeCast(Src s) noexcept
498{
499 // Dest may not have an explicit value constructor
500 return Dest{safeCast<typename Dest::value_type>(s.value())};
501}
502
503template <unit::IntegralValue Dest, unit::Integral Src>
504constexpr Dest
505safeCast(Src s) noexcept
506{
507 // Dest may not have an explicit value constructor
509}
510
511template <unit::IntegralValue Dest, unit::CastableValue<Dest> Src>
512constexpr Dest
513unsafeCast(Src s) noexcept
514{
515 // Dest may not have an explicit value constructor
516 return Dest{unsafeCast<typename Dest::value_type>(s.value())};
517}
518
519template <unit::IntegralValue Dest, unit::Integral Src>
520constexpr Dest
521unsafeCast(Src s) noexcept
522{
523 // Dest may not have an explicit value constructor
525}
526
527} // 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
Definition Units.h:268
friend constexpr ValueUnit operator*(value_type lhs, ValueUnit const &rhs)
Definition Units.h:158
constexpr bool operator<(ValueUnit const &other) const
Definition Units.h:254
friend std::istream & operator>>(std::istream &s, ValueUnit &val)
Definition Units.h:329
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
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
constexpr ValueUnit(ValueUnit< unit_type, Other > const &value)
Definition Units.h:118
UnitTag unit_type
Definition Units.h:80
constexpr value_type fee() const
Definition Units.h:278
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
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:285
Usable is checked to ensure that only values with known valid type tags can be used (sometimes transp...
Definition Units.h:49
T is_arithmetic_v
T is_class_v
T is_convertible_v
T is_integral_v
T is_object_v
T is_same_v
T is_signed_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:381
std::basic_ostream< Char, Traits > & operator<<(std::basic_ostream< Char, Traits > &os, ValueUnit< UnitTag, T > const &q)
Definition Units.h:339
std::string to_string(ValueUnit< UnitTag, T > const &amount)
Definition Units.h:346
ValueUnit< unitlessTag, T > scalar(T value)
Definition Units.h:374
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.
constexpr std::enable_if_t< std::is_integral_v< Dest > &&std::is_integral_v< Src >, Dest > safeCast(Src s) noexcept
Definition safe_cast.h:21
Bips< std::uint32_t > Bips32
Definition Units.h:435
constexpr std::enable_if_t< std::is_integral_v< Dest > &&std::is_integral_v< Src >, Dest > unsafeCast(Src s) noexcept
Definition safe_cast.h:52
TenthBips< std::uint32_t > TenthBips32
Definition Units.h:439
TenthBips< std::uint16_t > TenthBips16
Definition Units.h:438
FeeLevel< std::uint64_t > FeeLevel64
Definition Units.h:428
unit::ValueUnit< unit::BipsTag, T > Bips
Definition Units.h:433
FeeLevel< double > FeeLevelDouble
Definition Units.h:429
unit::ValueUnit< unit::feelevelTag, T > FeeLevel
Definition Units.h:427
STAmount multiply(STAmount const &amount, Number const &frac, Number::RoundingMode rm)
unit::ValueUnit< unit::TenthBipsTag, T > TenthBips
Definition Units.h:437
Bips< std::uint16_t > Bips16
Definition Units.h:434
Zero allows classes to offer efficient comparisons to zero.
Definition Zero.h:25
T to_string(T... args)