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_forwards.h>
7#include <xrpl/json/json_value.h>
8
9#include <boost/multiprecision/cpp_int.hpp>
10#include <boost/operators.hpp>
11
12#include <cstdint>
13#include <iosfwd>
14#include <limits>
15#include <optional>
16#include <string>
17#include <type_traits>
18
19namespace xrpl {
20
21namespace unit {
22
27struct dropTag;
33struct feelevelTag;
38struct unitlessTag;
39
43class BipsTag;
44class TenthBipsTag;
45
46// These names don't have to be too descriptive, because we're in the "unit"
47// namespace.
48
49template <class T>
52
61template <class T>
62concept Usable = Valid<T> &&
68
69template <class Other, class VU>
70concept Compatible =
73
74template <class T>
76
77template <class VU>
79
80template <class VU1, class VU2>
83
84template <class UnitTag, class T>
85class ValueUnit : private boost::totally_ordered<ValueUnit<UnitTag, T>>,
86 private boost::additive<ValueUnit<UnitTag, T>>,
87 private boost::equality_comparable<ValueUnit<UnitTag, T>, T>,
88 private boost::dividable<ValueUnit<UnitTag, T>, T>,
89 private boost::modable<ValueUnit<UnitTag, T>, T>,
90 private boost::unit_steppable<ValueUnit<UnitTag, T>>
91{
92public:
93 using unit_type = UnitTag;
94 using value_type = T;
95
96private:
98
99public:
100 ValueUnit() = default;
101 constexpr ValueUnit(ValueUnit const& other) = default;
102 constexpr ValueUnit&
103 operator=(ValueUnit const& other) = default;
104
105 constexpr explicit ValueUnit(beast::Zero) : value_(0)
106 {
107 }
108
109 constexpr ValueUnit&
111 {
112 value_ = 0;
113 return *this;
114 }
115
116 constexpr explicit ValueUnit(value_type value) : value_(value)
117 {
118 }
119
120 constexpr ValueUnit&
122 {
123 value_ = value;
124 return *this;
125 }
126
132 template <Compatible<ValueUnit> Other>
138
139 constexpr ValueUnit
140 operator+(value_type const& rhs) const
141 {
142 return ValueUnit{value_ + rhs};
143 }
144
145 friend constexpr ValueUnit
147 {
148 // addition is commutative
149 return rhs + lhs;
150 }
151
152 constexpr ValueUnit
153 operator-(value_type const& rhs) const
154 {
155 return ValueUnit{value_ - rhs};
156 }
157
158 friend constexpr ValueUnit
160 {
161 // subtraction is NOT commutative, but (lhs + (-rhs)) is addition, which
162 // is
163 return -rhs + lhs;
164 }
165
166 constexpr ValueUnit
167 operator*(value_type const& rhs) const
168 {
169 return ValueUnit{value_ * rhs};
170 }
171
172 friend constexpr ValueUnit
174 {
175 // multiplication is commutative
176 return rhs * lhs;
177 }
178
179 constexpr value_type
180 operator/(ValueUnit const& rhs) const
181 {
182 return value_ / rhs.value_;
183 }
184
185 ValueUnit&
186 operator+=(ValueUnit const& other)
187 {
188 value_ += other.value();
189 return *this;
190 }
191
192 ValueUnit&
193 operator-=(ValueUnit const& other)
194 {
195 value_ -= other.value();
196 return *this;
197 }
198
199 ValueUnit&
201 {
202 ++value_;
203 return *this;
204 }
205
206 ValueUnit&
208 {
209 --value_;
210 return *this;
211 }
212
213 ValueUnit&
215 {
216 value_ *= rhs;
217 return *this;
218 }
219
220 ValueUnit&
222 {
223 value_ /= rhs;
224 return *this;
225 }
226
227 template <Integral Transparent = value_type>
228 ValueUnit&
230 {
231 value_ %= rhs;
232 return *this;
233 }
234
236 operator-() const
237 {
238 static_assert(std::is_signed_v<T>, "- operator illegal on unsigned value types");
239 return ValueUnit{-value_};
240 }
241
242 constexpr bool
243 operator==(ValueUnit const& other) const
244 {
245 return value_ == other.value_;
246 }
247
248 template <Compatible<ValueUnit> Other>
249 constexpr bool
251 {
252 return value_ == other.value();
253 }
254
255 constexpr bool
257 {
258 return value_ == other;
259 }
260
261 constexpr bool
262 operator<(ValueUnit const& other) const
263 {
264 return value_ < other.value_;
265 }
266
270 explicit constexpr
271 operator bool() const noexcept
272 {
273 return value_ != 0;
274 }
275
279 [[nodiscard]] constexpr int
280 signum() const noexcept
281 {
282 if (value_ < 0)
283 return -1;
284 return value_ ? 1 : 0;
285 }
286
290 // TODO: Move this to a new class, maybe with the old "TaggedFee" name
291 [[nodiscard]] constexpr value_type
292 fee() const
293 {
294 return value_;
295 }
296
297 template <class Other>
298 [[nodiscard]] constexpr double
300 {
301 return static_cast<double>(value_) / reference.value();
302 }
303
304 // `Usable` is checked to ensure that only values with
305 // known valid type tags can be converted to JSON. At the time
306 // of implementation, that includes all known tags, but more may
307 // be added in the future.
308 [[nodiscard]] json::Value
310 requires Usable<ValueUnit>
311 {
312 if constexpr (std::is_integral_v<value_type>)
313 {
314 using jsontype =
316
317 constexpr auto kMin = std::numeric_limits<jsontype>::min();
318 constexpr auto kMax = std::numeric_limits<jsontype>::max();
319
320 if (value_ < kMin)
321 return kMin;
322 if (value_ > kMax)
323 return kMax;
324 return static_cast<jsontype>(value_);
325 }
326 else
327 {
328 return value_;
329 }
330 }
331
337 [[nodiscard]] constexpr value_type
338 value() const
339 {
340 return value_;
341 }
342
343 friend std::istream&
345 {
346 s >> val.value_;
347 return s;
348 }
349};
350
351// Output Values as just their numeric value.
352template <class Char, class Traits, class UnitTag, class T>
354operator<<(std::basic_ostream<Char, Traits>& os, ValueUnit<UnitTag, T> const& q)
355{
356 return os << q.value();
357}
358
359template <class UnitTag, class T>
362{
363 return std::to_string(amount.value());
364}
365
366template <class Source>
369
370template <class Dest>
371concept muldivDest = muldivSource<Dest> && // Dest is also a source
373 sizeof(typename Dest::value_type) >= sizeof(std::uint64_t);
374
375template <class Source2, class Source1>
378
379template <class Dest, class Source1, class Source2>
381// Source and Dest can be the same by default
382
383template <class Dest, class Source1, class Source2>
386
387template <class T>
389scalar(T value)
390{
391 return ValueUnit<unitlessTag, T>{value};
392}
393
394template <class Source1, class Source2, unit::muldivable<Source1, Source2> Dest>
396mulDivU(Source1 value, Dest mul, Source2 div)
397{
398 // values can never be negative in any context.
399 if (value.value() < 0 || mul.value() < 0 || div.value() < 0)
400 {
401 // split the asserts so if one hits, the user can tell which
402 // without a debugger.
403 XRPL_ASSERT(value.value() >= 0, "xrpl::unit::mulDivU : minimum value input");
404 XRPL_ASSERT(mul.value() >= 0, "xrpl::unit::mulDivU : minimum mul input");
405 XRPL_ASSERT(div.value() > 0, "xrpl::unit::mulDivU : minimum div input");
406 return std::nullopt;
407 }
408
409 using desttype = Dest::value_type;
410 constexpr auto kMax = std::numeric_limits<desttype>::max();
411
412 // Shortcuts, since these happen a lot in the real world
413 if (value == div)
414 return mul;
415 if (mul.value() == div.value())
416 {
417 if (value.value() > kMax)
418 return std::nullopt;
419 return Dest{static_cast<desttype>(value.value())};
420 }
421
422 using namespace boost::multiprecision;
423
424 uint128_t product;
425 product = multiply(
426 product,
427 static_cast<std::uint64_t>(value.value()),
428 static_cast<std::uint64_t>(mul.value()));
429
430 auto quotient = product / div.value();
431
432 if (quotient > kMax)
433 return std::nullopt;
434
435 return Dest{static_cast<desttype>(quotient)};
436}
437
438} // namespace unit
439
440// Fee Levels
441template <class T>
445
446// Basis points (Bips)
447template <class T>
451template <class T>
455
456template <class Source1, class Source2, unit::muldivable<Source1, Source2> Dest>
458mulDiv(Source1 value, Dest mul, Source2 div)
459{
460 return unit::mulDivU(value, mul, div);
461}
462
463template <class Source1, class Source2, unit::muldivCommutable<Source1, Source2> Dest>
465mulDiv(Dest value, Source1 mul, Source2 div)
466{
467 // Multiplication is commutative
468 return unit::mulDivU(mul, value, div);
469}
470
471template <unit::muldivDest Dest>
473mulDiv(std::uint64_t value, Dest mul, std::uint64_t div)
474{
475 // Give the scalars a non-tag so the
476 // unit-handling version gets called.
477 return unit::mulDivU(unit::scalar(value), mul, unit::scalar(div));
478}
479
480template <unit::muldivDest Dest>
482mulDiv(Dest value, std::uint64_t mul, std::uint64_t div)
483{
484 // Multiplication is commutative
485 return mulDiv(mul, value, div);
486}
487
488template <unit::muldivSource Source1, unit::muldivSources<Source1> Source2>
490mulDiv(Source1 value, std::uint64_t mul, Source2 div)
491{
492 // Give the scalars a dimensionless unit so the
493 // unit-handling version gets called.
494 auto unitresult = unit::mulDivU(value, unit::scalar(mul), div);
495
496 if (!unitresult)
497 return std::nullopt;
498
499 return unitresult->value();
500}
501
502template <unit::muldivSource Source1, unit::muldivSources<Source1> Source2>
504mulDiv(std::uint64_t value, Source1 mul, Source2 div)
505{
506 // Multiplication is commutative
507 return mulDiv(mul, value, div);
508}
509
510template <unit::IntegralValue Dest, unit::CastableValue<Dest> Src>
511constexpr Dest
512safeCast(Src s) noexcept
513{
514 // Dest may not have an explicit value constructor
515 return Dest{safeCast<typename Dest::value_type>(s.value())};
516}
517
518template <unit::IntegralValue Dest, unit::Integral Src>
519constexpr Dest
520safeCast(Src s) noexcept
521{
522 // Dest may not have an explicit value constructor
524}
525
526template <unit::IntegralValue Dest, unit::CastableValue<Dest> Src>
527constexpr Dest
528unsafeCast(Src s) noexcept
529{
530 // Dest may not have an explicit value constructor
531 return Dest{unsafeCast<typename Dest::value_type>(s.value())};
532}
533
534template <unit::IntegralValue Dest, unit::Integral Src>
535constexpr Dest
536unsafeCast(Src s) noexcept
537{
538 // Dest may not have an explicit value constructor
540}
541
542} // namespace xrpl
Represents a JSON value.
Definition json_value.h:117
constexpr ValueUnit(value_type value)
Definition Units.h:116
constexpr int signum() const noexcept
Definition Units.h:280
friend constexpr ValueUnit operator*(value_type lhs, ValueUnit const &rhs)
Definition Units.h:173
constexpr bool operator<(ValueUnit const &other) const
Definition Units.h:262
friend std::istream & operator>>(std::istream &s, ValueUnit &val)
Definition Units.h:344
ValueUnit & operator+=(ValueUnit const &other)
Definition Units.h:186
constexpr bool operator==(value_type other) const
Definition Units.h:256
constexpr bool operator==(ValueUnit const &other) const
Definition Units.h:243
constexpr bool operator==(ValueUnit< unit_type, Other > const &other) const
Definition Units.h:250
constexpr ValueUnit & operator=(value_type value)
Definition Units.h:121
constexpr ValueUnit(ValueUnit const &other)=default
constexpr ValueUnit & operator=(beast::Zero)
Definition Units.h:110
ValueUnit & operator/=(value_type const &rhs)
Definition Units.h:221
constexpr ValueUnit operator*(value_type const &rhs) const
Definition Units.h:167
constexpr ValueUnit operator-(value_type const &rhs) const
Definition Units.h:153
ValueUnit & operator%=(value_type const &rhs)
Definition Units.h:229
constexpr ValueUnit & operator=(ValueUnit const &other)=default
constexpr ValueUnit(ValueUnit< unit_type, Other > const &value)
Definition Units.h:133
UnitTag unit_type
Definition Units.h:93
constexpr value_type fee() const
Definition Units.h:292
friend constexpr ValueUnit operator-(value_type lhs, ValueUnit const &rhs)
Definition Units.h:159
ValueUnit & operator*=(value_type const &rhs)
Definition Units.h:214
constexpr value_type operator/(ValueUnit const &rhs) const
Definition Units.h:180
ValueUnit & operator-=(ValueUnit const &other)
Definition Units.h:193
constexpr ValueUnit operator+(value_type const &rhs) const
Definition Units.h:140
friend constexpr ValueUnit operator+(value_type lhs, ValueUnit const &rhs)
Definition Units.h:146
constexpr double decimalFromReference(ValueUnit< unit_type, Other > reference) const
Definition Units.h:299
Usable is checked to ensure that only values with known valid type tags can be used (sometimes transp...
Definition Units.h:62
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:396
std::basic_ostream< Char, Traits > & operator<<(std::basic_ostream< Char, Traits > &os, ValueUnit< UnitTag, T > const &q)
Definition Units.h:354
std::string to_string(ValueUnit< UnitTag, T > const &amount)
Definition Units.h:361
ValueUnit< unitlessTag, T > scalar(T value)
Definition Units.h:389
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.
Bips< std::uint32_t > Bips32
Definition Units.h:450
TenthBips< std::uint32_t > TenthBips32
Definition Units.h:454
TenthBips< std::uint16_t > TenthBips16
Definition Units.h:453
constexpr Dest safeCast(Src s) noexcept
Definition safe_cast.h:21
constexpr Dest unsafeCast(Src s) noexcept
Definition safe_cast.h:55
FeeLevel< std::uint64_t > FeeLevel64
Definition Units.h:443
unit::ValueUnit< unit::BipsTag, T > Bips
Definition Units.h:448
FeeLevel< double > FeeLevelDouble
Definition Units.h:444
unit::ValueUnit< unit::feelevelTag, T > FeeLevel
Definition Units.h:442
STAmount multiply(STAmount const &amount, Number const &frac, Number::RoundingMode rm)
unit::ValueUnit< unit::TenthBipsTag, T > TenthBips
Definition Units.h:452
Bips< std::uint16_t > Bips16
Definition Units.h:449
Zero allows classes to offer efficient comparisons to zero.
Definition Zero.h:26
T to_string(T... args)