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