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 ripple {
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, "ripple::unit::mulDivU : minimum value input");
392 XRPL_ASSERT(
393 mul.value() >= 0, "ripple::unit::mulDivU : minimum mul input");
394 XRPL_ASSERT(
395 div.value() > 0, "ripple::unit::mulDivU : minimum div input");
396 return std::nullopt;
397 }
398
399 using desttype = typename Dest::value_type;
400 constexpr auto max = std::numeric_limits<desttype>::max();
401
402 // Shortcuts, since these happen a lot in the real world
403 if (value == div)
404 return mul;
405 if (mul.value() == div.value())
406 {
407 if (value.value() > max)
408 return std::nullopt;
409 return Dest{static_cast<desttype>(value.value())};
410 }
411
412 using namespace boost::multiprecision;
413
414 uint128_t product;
415 product = multiply(
416 product,
417 static_cast<std::uint64_t>(value.value()),
418 static_cast<std::uint64_t>(mul.value()));
419
420 auto quotient = product / div.value();
421
422 if (quotient > max)
423 return std::nullopt;
424
425 return Dest{static_cast<desttype>(quotient)};
426}
427
428} // namespace unit
429
430// Fee Levels
431template <class T>
435
436// Basis points (Bips)
437template <class T>
441template <class T>
445
446template <class Source1, class Source2, unit::muldivable<Source1, Source2> Dest>
448mulDiv(Source1 value, Dest mul, Source2 div)
449{
450 return unit::mulDivU(value, mul, div);
451}
452
453template <
454 class Source1,
455 class Source2,
456 unit::muldivCommutable<Source1, Source2> Dest>
458mulDiv(Dest value, Source1 mul, Source2 div)
459{
460 // Multiplication is commutative
461 return unit::mulDivU(mul, value, div);
462}
463
464template <unit::muldivDest Dest>
466mulDiv(std::uint64_t value, Dest mul, std::uint64_t div)
467{
468 // Give the scalars a non-tag so the
469 // unit-handling version gets called.
470 return unit::mulDivU(unit::scalar(value), mul, unit::scalar(div));
471}
472
473template <unit::muldivDest Dest>
475mulDiv(Dest value, std::uint64_t mul, std::uint64_t div)
476{
477 // Multiplication is commutative
478 return mulDiv(mul, value, div);
479}
480
481template <unit::muldivSource Source1, unit::muldivSources<Source1> Source2>
483mulDiv(Source1 value, std::uint64_t mul, Source2 div)
484{
485 // Give the scalars a dimensionless unit so the
486 // unit-handling version gets called.
487 auto unitresult = unit::mulDivU(value, unit::scalar(mul), div);
488
489 if (!unitresult)
490 return std::nullopt;
491
492 return unitresult->value();
493}
494
495template <unit::muldivSource Source1, unit::muldivSources<Source1> Source2>
497mulDiv(std::uint64_t value, Source1 mul, Source2 div)
498{
499 // Multiplication is commutative
500 return mulDiv(mul, value, div);
501}
502
503template <unit::IntegralValue Dest, unit::CastableValue<Dest> Src>
504constexpr Dest
505safe_cast(Src s) noexcept
506{
507 // Dest may not have an explicit value constructor
508 return Dest{safe_cast<typename Dest::value_type>(s.value())};
509}
510
511template <unit::IntegralValue Dest, unit::Integral Src>
512constexpr Dest
513safe_cast(Src s) noexcept
514{
515 // Dest may not have an explicit value constructor
516 return Dest{safe_cast<typename Dest::value_type>(s)};
517}
518
519template <unit::IntegralValue Dest, unit::CastableValue<Dest> Src>
520constexpr Dest
521unsafe_cast(Src s) noexcept
522{
523 // Dest may not have an explicit value constructor
524 return Dest{unsafe_cast<typename Dest::value_type>(s.value())};
525}
526
527template <unit::IntegralValue Dest, unit::Integral Src>
528constexpr Dest
529unsafe_cast(Src s) noexcept
530{
531 // Dest may not have an explicit value constructor
532 return Dest{unsafe_cast<typename Dest::value_type>(s)};
533}
534
535} // namespace ripple
536
537#endif // PROTOCOL_UNITS_H_INCLUDED
Represents a JSON value.
Definition json_value.h:131
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:159
Json::Value jsonClipped() const
Definition Units.h:295
constexpr double decimalFromReference(ValueUnit< unit_type, Other > reference) const
Definition Units.h:285
friend std::istream & operator>>(std::istream &s, ValueUnit &val)
Definition Units.h:331
constexpr ValueUnit & operator=(beast::Zero)
Definition Units.h:98
constexpr int signum() const noexcept
Return the sign of the amount.
Definition Units.h:270
constexpr ValueUnit operator+(value_type const &rhs) const
Definition Units.h:126
constexpr bool operator!=(ValueUnit< unit_type, Other > const &other) const
Definition Units.h:250
ValueUnit & operator+=(ValueUnit const &other)
Definition Units.h:172
ValueUnit & operator-=(ValueUnit const &other)
Definition Units.h:179
constexpr bool operator<(ValueUnit const &other) const
Definition Units.h:256
constexpr value_type operator/(ValueUnit const &rhs) const
Definition Units.h:166
ValueUnit & operator%=(value_type const &rhs)
Definition Units.h:215
ValueUnit & operator++()
Definition Units.h:186
ValueUnit & operator*=(value_type const &rhs)
Definition Units.h:200
constexpr ValueUnit & operator=(value_type value)
Definition Units.h:109
constexpr bool operator==(ValueUnit< unit_type, Other > const &other) const
Definition Units.h:237
constexpr ValueUnit(value_type value)
Definition Units.h:104
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 & operator=(ValueUnit const &other)=default
constexpr ValueUnit operator*(value_type const &rhs) const
Definition Units.h:153
value_type value_
Definition Units.h:85
constexpr bool operator==(value_type other) const
Definition Units.h:243
ValueUnit operator-() const
Definition Units.h:222
constexpr ValueUnit(beast::Zero)
Definition Units.h:93
ValueUnit & operator/=(value_type const &rhs)
Definition Units.h:207
constexpr ValueUnit(ValueUnit const &other)=default
friend constexpr ValueUnit operator-(value_type lhs, ValueUnit const &rhs)
Definition Units.h:145
ValueUnit & operator--()
Definition Units.h:193
friend constexpr ValueUnit operator+(value_type lhs, ValueUnit const &rhs)
Definition Units.h:132
constexpr bool operator==(ValueUnit const &other) const
Definition Units.h:230
constexpr value_type value() const
Returns the underlying value.
Definition Units.h:325
constexpr ValueUnit operator-(value_type const &rhs) const
Definition Units.h:139
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
ValueUnit< unitlessTag, T > scalar(T value)
Definition Units.h:376
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
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 > safe_cast(Src s) noexcept
Definition safe_cast.h:22
STAmount multiply(STAmount const &amount, Rate const &rate)
Definition Rate2.cpp:34
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 > unsafe_cast(Src s) noexcept
Definition safe_cast.h:58
Zero allows classes to offer efficient comparisons to zero.
Definition Zero.h:26
T to_string(T... args)