rippled
Loading...
Searching...
No Matches
Units.h
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2019 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18
19#ifndef PROTOCOL_UNITS_H_INCLUDED
20#define PROTOCOL_UNITS_H_INCLUDED
21
22#include <xrpl/basics/safe_cast.h>
23#include <xrpl/beast/utility/Zero.h>
24#include <xrpl/beast/utility/instrumentation.h>
25#include <xrpl/json/json_value.h>
26
27#include <boost/multiprecision/cpp_int.hpp>
28#include <boost/operators.hpp>
29
30#include <iosfwd>
31#include <limits>
32#include <optional>
33
34namespace ripple {
35
36namespace unit {
37
40struct dropTag;
44struct feelevelTag;
47struct unitlessTag;
48
50class BipsTag;
51class TenthBipsTag;
52
53// These names don't have to be too descriptive, because we're in the "unit"
54// namespace.
55
56template <class T>
59
67template <class T>
68concept Usable = Valid<T> &&
74
75template <class Other, class VU>
79
80template <class T>
82
83template <class VU>
85
86template <class VU1, class VU2>
89
90template <class UnitTag, class T>
91class ValueUnit : private boost::totally_ordered<ValueUnit<UnitTag, T>>,
92 private boost::additive<ValueUnit<UnitTag, T>>,
93 private boost::equality_comparable<ValueUnit<UnitTag, T>, T>,
94 private boost::dividable<ValueUnit<UnitTag, T>, T>,
95 private boost::modable<ValueUnit<UnitTag, T>, T>,
96 private boost::unit_steppable<ValueUnit<UnitTag, T>>
97{
98public:
99 using unit_type = UnitTag;
100 using value_type = T;
101
102private:
104
105public:
106 ValueUnit() = default;
107 constexpr ValueUnit(ValueUnit const& other) = default;
108 constexpr ValueUnit&
109 operator=(ValueUnit const& other) = default;
110
111 constexpr explicit ValueUnit(beast::Zero) : value_(0)
112 {
113 }
114
115 constexpr ValueUnit&
117 {
118 value_ = 0;
119 return *this;
120 }
121
122 constexpr explicit ValueUnit(value_type value) : value_(value)
123 {
124 }
125
126 constexpr ValueUnit&
128 {
129 value_ = value;
130 return *this;
131 }
132
136 template <Compatible<ValueUnit> Other>
139 : ValueUnit(safe_cast<value_type>(value.value()))
140 {
141 }
142
143 constexpr ValueUnit
144 operator+(value_type const& rhs) const
145 {
146 return ValueUnit{value_ + rhs};
147 }
148
149 friend constexpr ValueUnit
151 {
152 // addition is commutative
153 return rhs + lhs;
154 }
155
156 constexpr ValueUnit
157 operator-(value_type const& rhs) const
158 {
159 return ValueUnit{value_ - rhs};
160 }
161
162 friend constexpr ValueUnit
164 {
165 // subtraction is NOT commutative, but (lhs + (-rhs)) is addition, which
166 // is
167 return -rhs + lhs;
168 }
169
170 constexpr ValueUnit
171 operator*(value_type const& rhs) const
172 {
173 return ValueUnit{value_ * rhs};
174 }
175
176 friend constexpr ValueUnit
178 {
179 // multiplication is commutative
180 return rhs * lhs;
181 }
182
183 constexpr value_type
184 operator/(ValueUnit const& rhs) const
185 {
186 return value_ / rhs.value_;
187 }
188
189 ValueUnit&
190 operator+=(ValueUnit const& other)
191 {
192 value_ += other.value();
193 return *this;
194 }
195
196 ValueUnit&
197 operator-=(ValueUnit const& other)
198 {
199 value_ -= other.value();
200 return *this;
201 }
202
203 ValueUnit&
205 {
206 ++value_;
207 return *this;
208 }
209
210 ValueUnit&
212 {
213 --value_;
214 return *this;
215 }
216
217 ValueUnit&
219 {
220 value_ *= rhs;
221 return *this;
222 }
223
224 ValueUnit&
226 {
227 value_ /= rhs;
228 return *this;
229 }
230
231 template <Integral transparent = value_type>
232 ValueUnit&
234 {
235 value_ %= rhs;
236 return *this;
237 }
238
240 operator-() const
241 {
242 static_assert(
243 std::is_signed_v<T>, "- operator illegal on unsigned value types");
244 return ValueUnit{-value_};
245 }
246
247 constexpr bool
248 operator==(ValueUnit const& other) const
249 {
250 return value_ == other.value_;
251 }
252
253 template <Compatible<ValueUnit> Other>
254 constexpr bool
256 {
257 return value_ == other.value();
258 }
259
260 constexpr bool
262 {
263 return value_ == other;
264 }
265
266 template <Compatible<ValueUnit> Other>
267 constexpr bool
269 {
270 return !operator==(other);
271 }
272
273 constexpr bool
274 operator<(ValueUnit const& other) const
275 {
276 return value_ < other.value_;
277 }
278
280 explicit constexpr
281 operator bool() const noexcept
282 {
283 return value_ != 0;
284 }
285
287 constexpr int
288 signum() const noexcept
289 {
290 return (value_ < 0) ? -1 : (value_ ? 1 : 0);
291 }
292
294 // TODO: Move this to a new class, maybe with the old "TaggedFee" name
295 constexpr value_type
296 fee() const
297 {
298 return value_;
299 }
300
301 template <class Other>
302 constexpr double
304 {
305 return static_cast<double>(value_) / reference.value();
306 }
307
308 // `Usable` is checked to ensure that only values with
309 // known valid type tags can be converted to JSON. At the time
310 // of implementation, that includes all known tags, but more may
311 // be added in the future.
314 requires Usable<ValueUnit>
315 {
316 if constexpr (std::is_integral_v<value_type>)
317 {
318 using jsontype = std::conditional_t<
320 Json::Int,
321 Json::UInt>;
322
323 constexpr auto min = std::numeric_limits<jsontype>::min();
324 constexpr auto max = std::numeric_limits<jsontype>::max();
325
326 if (value_ < min)
327 return min;
328 if (value_ > max)
329 return max;
330 return static_cast<jsontype>(value_);
331 }
332 else
333 {
334 return value_;
335 }
336 }
337
342 constexpr value_type
343 value() const
344 {
345 return value_;
346 }
347
348 friend std::istream&
350 {
351 s >> val.value_;
352 return s;
353 }
354};
355
356// Output Values as just their numeric value.
357template <class Char, class Traits, class UnitTag, class T>
359operator<<(std::basic_ostream<Char, Traits>& os, ValueUnit<UnitTag, T> const& q)
360{
361 return os << q.value();
362}
363
364template <class UnitTag, class T>
367{
368 return std::to_string(amount.value());
369}
370
371template <class Source>
374
375template <class Dest>
376concept muldivDest = muldivSource<Dest> && // Dest is also a source
378 sizeof(typename Dest::value_type) >= sizeof(std::uint64_t);
379
380template <class Source2, class Source1>
383
384template <class Dest, class Source1, class Source2>
386// Source and Dest can be the same by default
387
388template <class Dest, class Source1, class Source2>
391
392template <class T>
393ValueUnit<unitlessTag, T>
394scalar(T value)
395{
396 return ValueUnit<unitlessTag, T>{value};
397}
398
399template <class Source1, class Source2, unit::muldivable<Source1, Source2> Dest>
401mulDivU(Source1 value, Dest mul, Source2 div)
402{
403 // values can never be negative in any context.
404 if (value.value() < 0 || mul.value() < 0 || div.value() < 0)
405 {
406 // split the asserts so if one hits, the user can tell which
407 // without a debugger.
408 XRPL_ASSERT(
409 value.value() >= 0, "ripple::unit::mulDivU : minimum value input");
410 XRPL_ASSERT(
411 mul.value() >= 0, "ripple::unit::mulDivU : minimum mul input");
412 XRPL_ASSERT(
413 div.value() > 0, "ripple::unit::mulDivU : minimum div input");
414 return std::nullopt;
415 }
416
417 using desttype = typename Dest::value_type;
418 constexpr auto max = std::numeric_limits<desttype>::max();
419
420 // Shortcuts, since these happen a lot in the real world
421 if (value == div)
422 return mul;
423 if (mul.value() == div.value())
424 {
425 if (value.value() > max)
426 return std::nullopt;
427 return Dest{static_cast<desttype>(value.value())};
428 }
429
430 using namespace boost::multiprecision;
431
432 uint128_t product;
433 product = multiply(
434 product,
435 static_cast<std::uint64_t>(value.value()),
436 static_cast<std::uint64_t>(mul.value()));
437
438 auto quotient = product / div.value();
439
440 if (quotient > max)
441 return std::nullopt;
442
443 return Dest{static_cast<desttype>(quotient)};
444}
445
446} // namespace unit
447
448// Fee Levels
449template <class T>
453
454// Basis points (Bips)
455template <class T>
459template <class T>
463
464template <class Source1, class Source2, unit::muldivable<Source1, Source2> Dest>
466mulDiv(Source1 value, Dest mul, Source2 div)
467{
468 return unit::mulDivU(value, mul, div);
469}
470
471template <
472 class Source1,
473 class Source2,
474 unit::muldivCommutable<Source1, Source2> Dest>
476mulDiv(Dest value, Source1 mul, Source2 div)
477{
478 // Multiplication is commutative
479 return unit::mulDivU(mul, value, div);
480}
481
482template <unit::muldivDest Dest>
484mulDiv(std::uint64_t value, Dest mul, std::uint64_t div)
485{
486 // Give the scalars a non-tag so the
487 // unit-handling version gets called.
488 return unit::mulDivU(unit::scalar(value), mul, unit::scalar(div));
489}
490
491template <unit::muldivDest Dest>
493mulDiv(Dest value, std::uint64_t mul, std::uint64_t div)
494{
495 // Multiplication is commutative
496 return mulDiv(mul, value, div);
497}
498
499template <unit::muldivSource Source1, unit::muldivSources<Source1> Source2>
501mulDiv(Source1 value, std::uint64_t mul, Source2 div)
502{
503 // Give the scalars a dimensionless unit so the
504 // unit-handling version gets called.
505 auto unitresult = unit::mulDivU(value, unit::scalar(mul), div);
506
507 if (!unitresult)
508 return std::nullopt;
509
510 return unitresult->value();
511}
512
513template <unit::muldivSource Source1, unit::muldivSources<Source1> Source2>
515mulDiv(std::uint64_t value, Source1 mul, Source2 div)
516{
517 // Multiplication is commutative
518 return mulDiv(mul, value, div);
519}
520
521template <unit::IntegralValue Dest, unit::CastableValue<Dest> Src>
522constexpr Dest
523safe_cast(Src s) noexcept
524{
525 // Dest may not have an explicit value constructor
526 return Dest{safe_cast<typename Dest::value_type>(s.value())};
527}
528
529template <unit::IntegralValue Dest, unit::Integral Src>
530constexpr Dest
531safe_cast(Src s) noexcept
532{
533 // Dest may not have an explicit value constructor
534 return Dest{safe_cast<typename Dest::value_type>(s)};
535}
536
537template <unit::IntegralValue Dest, unit::CastableValue<Dest> Src>
538constexpr Dest
539unsafe_cast(Src s) noexcept
540{
541 // Dest may not have an explicit value constructor
542 return Dest{unsafe_cast<typename Dest::value_type>(s.value())};
543}
544
545template <unit::IntegralValue Dest, unit::Integral Src>
546constexpr Dest
547unsafe_cast(Src s) noexcept
548{
549 // Dest may not have an explicit value constructor
550 return Dest{unsafe_cast<typename Dest::value_type>(s)};
551}
552
553} // namespace ripple
554
555#endif // PROTOCOL_UNITS_H_INCLUDED
Represents a JSON value.
Definition json_value.h:149
constexpr value_type fee() const
Returns the number of drops.
Definition Units.h:296
friend constexpr ValueUnit operator*(value_type lhs, ValueUnit const &rhs)
Definition Units.h:177
Json::Value jsonClipped() const
Definition Units.h:313
constexpr double decimalFromReference(ValueUnit< unit_type, Other > reference) const
Definition Units.h:303
friend std::istream & operator>>(std::istream &s, ValueUnit &val)
Definition Units.h:349
constexpr ValueUnit & operator=(beast::Zero)
Definition Units.h:116
constexpr int signum() const noexcept
Return the sign of the amount.
Definition Units.h:288
constexpr ValueUnit operator+(value_type const &rhs) const
Definition Units.h:144
constexpr bool operator!=(ValueUnit< unit_type, Other > const &other) const
Definition Units.h:268
ValueUnit & operator+=(ValueUnit const &other)
Definition Units.h:190
ValueUnit & operator-=(ValueUnit const &other)
Definition Units.h:197
constexpr bool operator<(ValueUnit const &other) const
Definition Units.h:274
constexpr value_type operator/(ValueUnit const &rhs) const
Definition Units.h:184
ValueUnit & operator%=(value_type const &rhs)
Definition Units.h:233
ValueUnit & operator++()
Definition Units.h:204
ValueUnit & operator*=(value_type const &rhs)
Definition Units.h:218
constexpr ValueUnit & operator=(value_type value)
Definition Units.h:127
constexpr bool operator==(ValueUnit< unit_type, Other > const &other) const
Definition Units.h:255
constexpr ValueUnit(value_type value)
Definition Units.h:122
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:137
constexpr ValueUnit & operator=(ValueUnit const &other)=default
constexpr ValueUnit operator*(value_type const &rhs) const
Definition Units.h:171
value_type value_
Definition Units.h:103
constexpr bool operator==(value_type other) const
Definition Units.h:261
ValueUnit operator-() const
Definition Units.h:240
constexpr ValueUnit(beast::Zero)
Definition Units.h:111
ValueUnit & operator/=(value_type const &rhs)
Definition Units.h:225
constexpr ValueUnit(ValueUnit const &other)=default
friend constexpr ValueUnit operator-(value_type lhs, ValueUnit const &rhs)
Definition Units.h:163
ValueUnit & operator--()
Definition Units.h:211
friend constexpr ValueUnit operator+(value_type lhs, ValueUnit const &rhs)
Definition Units.h:150
constexpr bool operator==(ValueUnit const &other) const
Definition Units.h:248
constexpr value_type value() const
Returns the underlying value.
Definition Units.h:343
constexpr ValueUnit operator-(value_type const &rhs) const
Definition Units.h:157
Usable is checked to ensure that only values with known valid type tags can be used (sometimes transp...
Definition Units.h:68
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:401
ValueUnit< unitlessTag, T > scalar(T value)
Definition Units.h:394
std::basic_ostream< Char, Traits > & operator<<(std::basic_ostream< Char, Traits > &os, ValueUnit< UnitTag, T > const &q)
Definition Units.h:359
std::string to_string(ValueUnit< UnitTag, T > const &amount)
Definition Units.h:366
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:25
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:41
STAmount multiply(STAmount const &amount, Rate const &rate)
Definition Rate2.cpp:53
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:77
Zero allows classes to offer efficient comparisons to zero.
Definition Zero.h:43
T to_string(T... args)