rippled
Loading...
Searching...
No Matches
FeeUnits.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 BASICS_FEES_H_INCLUDED
20#define BASICS_FEES_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 feeunit {
37
40struct dropTag;
44struct feeunitTag;
48struct feelevelTag;
51struct unitlessTag;
52
53template <class T>
57
65template <class T, class = enable_if_unit_t<T>>
66constexpr bool is_usable_unit_v =
71
72template <class UnitTag, class T>
73class TaggedFee : private boost::totally_ordered<TaggedFee<UnitTag, T>>,
74 private boost::additive<TaggedFee<UnitTag, T>>,
75 private boost::equality_comparable<TaggedFee<UnitTag, T>, T>,
76 private boost::dividable<TaggedFee<UnitTag, T>, T>,
77 private boost::modable<TaggedFee<UnitTag, T>, T>,
78 private boost::unit_steppable<TaggedFee<UnitTag, T>>
79{
80public:
81 using unit_type = UnitTag;
82 using value_type = T;
83
84private:
86
87protected:
88 template <class Other>
89 static constexpr bool is_compatible_v =
92
93 template <class OtherFee, class = enable_if_unit_t<OtherFee>>
94 static constexpr bool is_compatiblefee_v =
95 is_compatible_v<typename OtherFee::value_type> &&
97
98 template <class Other>
101
102 template <class OtherFee>
105
106public:
107 TaggedFee() = default;
108 constexpr TaggedFee(TaggedFee const& other) = default;
109 constexpr TaggedFee&
110 operator=(TaggedFee const& other) = default;
111
112 constexpr explicit TaggedFee(beast::Zero) : fee_(0)
113 {
114 }
115
116 constexpr TaggedFee&
118 {
119 fee_ = 0;
120 return *this;
121 }
122
123 constexpr explicit TaggedFee(value_type fee) : fee_(fee)
124 {
125 }
126
127 TaggedFee&
129 {
130 fee_ = fee;
131 return *this;
132 }
133
137 template <
138 class Other,
139 class = std::enable_if_t<
140 is_compatible_v<Other> &&
141 is_safetocasttovalue_v<value_type, Other>>>
146
147 constexpr TaggedFee
148 operator*(value_type const& rhs) const
149 {
150 return TaggedFee{fee_ * rhs};
151 }
152
153 friend constexpr TaggedFee
155 {
156 // multiplication is commutative
157 return rhs * lhs;
158 }
159
160 constexpr value_type
161 operator/(TaggedFee const& rhs) const
162 {
163 return fee_ / rhs.fee_;
164 }
165
166 TaggedFee&
167 operator+=(TaggedFee const& other)
168 {
169 fee_ += other.fee();
170 return *this;
171 }
172
173 TaggedFee&
174 operator-=(TaggedFee const& other)
175 {
176 fee_ -= other.fee();
177 return *this;
178 }
179
180 TaggedFee&
182 {
183 ++fee_;
184 return *this;
185 }
186
187 TaggedFee&
189 {
190 --fee_;
191 return *this;
192 }
193
194 TaggedFee&
196 {
197 fee_ *= rhs;
198 return *this;
199 }
200
201 TaggedFee&
203 {
204 fee_ /= rhs;
205 return *this;
206 }
207
208 template <class transparent = value_type>
211 {
212 fee_ %= rhs;
213 return *this;
214 }
215
217 operator-() const
218 {
219 static_assert(
220 std::is_signed_v<T>, "- operator illegal on unsigned fee types");
221 return TaggedFee{-fee_};
222 }
223
224 bool
225 operator==(TaggedFee const& other) const
226 {
227 return fee_ == other.fee_;
228 }
229
230 template <class Other, class = enable_if_compatible_t<Other>>
231 bool
233 {
234 return fee_ == other.fee();
235 }
236
237 bool
239 {
240 return fee_ == other;
241 }
242
243 template <class Other, class = enable_if_compatible_t<Other>>
244 bool
246 {
247 return !operator==(other);
248 }
249
250 bool
251 operator<(TaggedFee const& other) const
252 {
253 return fee_ < other.fee_;
254 }
255
257 explicit constexpr
258 operator bool() const noexcept
259 {
260 return fee_ != 0;
261 }
262
264 constexpr int
265 signum() const noexcept
266 {
267 return (fee_ < 0) ? -1 : (fee_ ? 1 : 0);
268 }
269
271 constexpr value_type
272 fee() const
273 {
274 return fee_;
275 }
276
277 template <class Other>
278 constexpr double
280 {
281 return static_cast<double>(fee_) / reference.fee();
282 }
283
284 // `is_usable_unit_v` is checked to ensure that only values with
285 // known valid type tags can be converted to JSON. At the time
286 // of implementation, that includes all known tags, but more may
287 // be added in the future.
290 {
291 if constexpr (std::is_integral_v<value_type>)
292 {
293 using jsontype = std::conditional_t<
295 Json::Int,
296 Json::UInt>;
297
298 constexpr auto min = std::numeric_limits<jsontype>::min();
299 constexpr auto max = std::numeric_limits<jsontype>::max();
300
301 if (fee_ < min)
302 return min;
303 if (fee_ > max)
304 return max;
305 return static_cast<jsontype>(fee_);
306 }
307 else
308 {
309 return fee_;
310 }
311 }
312
317 constexpr value_type
318 value() const
319 {
320 return fee_;
321 }
322
323 friend std::istream&
325 {
326 s >> val.fee_;
327 return s;
328 }
329};
330
331// Output Fees as just their numeric value.
332template <class Char, class Traits, class UnitTag, class T>
334operator<<(std::basic_ostream<Char, Traits>& os, TaggedFee<UnitTag, T> const& q)
335{
336 return os << q.value();
337}
338
339template <class UnitTag, class T>
342{
343 return std::to_string(amount.fee());
344}
345
346template <class Source, class = enable_if_unit_t<Source>>
347constexpr bool can_muldiv_source_v =
349
350template <class Dest, class = enable_if_unit_t<Dest>>
351constexpr bool can_muldiv_dest_v =
352 can_muldiv_source_v<Dest> && // Dest is also a source
354 sizeof(typename Dest::value_type) >= sizeof(std::uint64_t);
355
356template <
357 class Source1,
358 class Source2,
361constexpr bool can_muldiv_sources_v =
362 can_muldiv_source_v<Source1> && can_muldiv_source_v<Source2> &&
364
365template <
366 class Source1,
367 class Source2,
368 class Dest,
372constexpr bool can_muldiv_v =
373 can_muldiv_sources_v<Source1, Source2> && can_muldiv_dest_v<Dest>;
374// Source and Dest can be the same by default
375
376template <
377 class Source1,
378 class Source2,
379 class Dest,
383constexpr bool can_muldiv_commute_v = can_muldiv_v<Source1, Source2, Dest> &&
385
386template <class T>
389
390template <class T>
392
393template <class Source1, class Source2>
396
397template <class Source1, class Source2, class Dest>
400
401template <class Source1, class Source2, class Dest>
404
405template <class T>
407scalar(T value)
408{
409 return TaggedFee<unitlessTag, T>{value};
410}
411
412template <
413 class Source1,
414 class Source2,
415 class Dest,
416 class = enable_muldiv_t<Source1, Source2, Dest>>
418mulDivU(Source1 value, Dest mul, Source2 div)
419{
420 // Fees can never be negative in any context.
421 if (value.value() < 0 || mul.value() < 0 || div.value() < 0)
422 {
423 // split the asserts so if one hits, the user can tell which
424 // without a debugger.
425 XRPL_ASSERT(
426 value.value() >= 0,
427 "ripple::feeunit::mulDivU : minimum value input");
428 XRPL_ASSERT(
429 mul.value() >= 0, "ripple::feeunit::mulDivU : minimum mul input");
430 XRPL_ASSERT(
431 div.value() >= 0, "ripple::feeunit::mulDivU : minimum div input");
432 return std::nullopt;
433 }
434
435 using desttype = typename Dest::value_type;
436 constexpr auto max = std::numeric_limits<desttype>::max();
437
438 // Shortcuts, since these happen a lot in the real world
439 if (value == div)
440 return mul;
441 if (mul.value() == div.value())
442 {
443 if (value.value() > max)
444 return std::nullopt;
445 return Dest{static_cast<desttype>(value.value())};
446 }
447
448 using namespace boost::multiprecision;
449
450 uint128_t product;
451 product = multiply(
452 product,
453 static_cast<std::uint64_t>(value.value()),
454 static_cast<std::uint64_t>(mul.value()));
455
456 auto quotient = product / div.value();
457
458 if (quotient > max)
459 return std::nullopt;
460
461 return Dest{static_cast<desttype>(quotient)};
462}
463
464} // namespace feeunit
465
466template <class T>
470
471template <
472 class Source1,
473 class Source2,
474 class Dest,
477mulDiv(Source1 value, Dest mul, Source2 div)
478{
479 return feeunit::mulDivU(value, mul, div);
480}
481
482template <
483 class Source1,
484 class Source2,
485 class Dest,
486 class = feeunit::enable_muldiv_commute_t<Source1, Source2, Dest>>
488mulDiv(Dest value, Source1 mul, Source2 div)
489{
490 // Multiplication is commutative
491 return feeunit::mulDivU(mul, value, div);
492}
493
494template <class Dest, class = feeunit::enable_muldiv_dest_t<Dest>>
496mulDiv(std::uint64_t value, Dest mul, std::uint64_t div)
497{
498 // Give the scalars a non-tag so the
499 // unit-handling version gets called.
500 return feeunit::mulDivU(feeunit::scalar(value), mul, feeunit::scalar(div));
501}
502
503template <class Dest, class = feeunit::enable_muldiv_dest_t<Dest>>
505mulDiv(Dest value, std::uint64_t mul, std::uint64_t div)
506{
507 // Multiplication is commutative
508 return mulDiv(mul, value, div);
509}
510
511template <
512 class Source1,
513 class Source2,
514 class = feeunit::enable_muldiv_sources_t<Source1, Source2>>
516mulDiv(Source1 value, std::uint64_t mul, Source2 div)
517{
518 // Give the scalars a dimensionless unit so the
519 // unit-handling version gets called.
520 auto unitresult = feeunit::mulDivU(value, feeunit::scalar(mul), div);
521
522 if (!unitresult)
523 return std::nullopt;
524
525 return unitresult->value();
526}
527
528template <
529 class Source1,
530 class Source2,
531 class = feeunit::enable_muldiv_sources_t<Source1, Source2>>
533mulDiv(std::uint64_t value, Source1 mul, Source2 div)
534{
535 // Multiplication is commutative
536 return mulDiv(mul, value, div);
537}
538
539template <class Dest, class Src>
540constexpr std::enable_if_t<
544 Dest>
545safe_cast(Src s) noexcept
546{
547 // Dest may not have an explicit value constructor
548 return Dest{safe_cast<typename Dest::value_type>(s.value())};
549}
550
551template <class Dest, class Src>
552constexpr std::enable_if_t<
556 Dest>
557unsafe_cast(Src s) noexcept
558{
559 // Dest may not have an explicit value constructor
560 return Dest{unsafe_cast<typename Dest::value_type>(s.value())};
561}
562
563} // namespace ripple
564
565#endif // BASICS_FEES_H_INCLUDED
Represents a JSON value.
Definition json_value.h:149
constexpr TaggedFee(TaggedFee< unit_type, Other > const &fee)
Instances with the same unit, and a type that is "safe" to convert to this one can be converted impli...
Definition FeeUnits.h:142
std::enable_if_t< is_usable_unit_v< TaggedFee >, Json::Value > jsonClipped() const
Definition FeeUnits.h:289
constexpr TaggedFee & operator=(TaggedFee const &other)=default
TaggedFee & operator++()
Definition FeeUnits.h:181
TaggedFee & operator--()
Definition FeeUnits.h:188
TaggedFee & operator=(value_type fee)
Definition FeeUnits.h:128
bool operator==(value_type other) const
Definition FeeUnits.h:238
bool operator==(TaggedFee< unit_type, Other > const &other) const
Definition FeeUnits.h:232
constexpr value_type operator/(TaggedFee const &rhs) const
Definition FeeUnits.h:161
friend constexpr TaggedFee operator*(value_type lhs, TaggedFee const &rhs)
Definition FeeUnits.h:154
static constexpr bool is_compatiblefee_v
Definition FeeUnits.h:94
constexpr value_type value() const
Returns the underlying value.
Definition FeeUnits.h:318
friend std::istream & operator>>(std::istream &s, TaggedFee &val)
Definition FeeUnits.h:324
constexpr int signum() const noexcept
Return the sign of the amount.
Definition FeeUnits.h:265
std::enable_if_t< std::is_integral_v< transparent >, TaggedFee & > operator%=(value_type const &rhs)
Definition FeeUnits.h:210
typename std::enable_if_t< is_compatible_v< Other > > enable_if_compatible_t
Definition FeeUnits.h:100
constexpr TaggedFee & operator=(beast::Zero)
Definition FeeUnits.h:117
constexpr TaggedFee(value_type fee)
Definition FeeUnits.h:123
typename std::enable_if_t< is_compatiblefee_v< OtherFee > > enable_if_compatiblefee_t
Definition FeeUnits.h:104
constexpr TaggedFee(beast::Zero)
Definition FeeUnits.h:112
TaggedFee operator-() const
Definition FeeUnits.h:217
constexpr TaggedFee(TaggedFee const &other)=default
TaggedFee & operator-=(TaggedFee const &other)
Definition FeeUnits.h:174
TaggedFee & operator*=(value_type const &rhs)
Definition FeeUnits.h:195
constexpr double decimalFromReference(TaggedFee< unit_type, Other > reference) const
Definition FeeUnits.h:279
bool operator<(TaggedFee const &other) const
Definition FeeUnits.h:251
static constexpr bool is_compatible_v
Definition FeeUnits.h:89
constexpr value_type fee() const
Returns the number of drops.
Definition FeeUnits.h:272
TaggedFee & operator/=(value_type const &rhs)
Definition FeeUnits.h:202
constexpr TaggedFee operator*(value_type const &rhs) const
Definition FeeUnits.h:148
TaggedFee & operator+=(TaggedFee const &other)
Definition FeeUnits.h:167
bool operator!=(TaggedFee< unit_type, Other > const &other) const
Definition FeeUnits.h:245
bool operator==(TaggedFee const &other) const
Definition FeeUnits.h:225
T is_same_v
T max(T... args)
T min(T... args)
int Int
unsigned int UInt
typename std::enable_if_t< can_muldiv_sources_v< Source1, Source2 > > enable_muldiv_sources_t
Definition FeeUnits.h:395
constexpr bool is_usable_unit_v
is_usable_unit_v is checked to ensure that only values with known valid type tags can be used (someti...
Definition FeeUnits.h:66
std::string to_string(TaggedFee< UnitTag, T > const &amount)
Definition FeeUnits.h:341
constexpr bool can_muldiv_dest_v
Definition FeeUnits.h:351
std::optional< Dest > mulDivU(Source1 value, Dest mul, Source2 div)
Definition FeeUnits.h:418
constexpr bool can_muldiv_sources_v
Definition FeeUnits.h:361
typename std::enable_if_t< std::is_class_v< T > &&std::is_object_v< typename T::unit_type > &&std::is_object_v< typename T::value_type > > enable_if_unit_t
Definition FeeUnits.h:56
std::basic_ostream< Char, Traits > & operator<<(std::basic_ostream< Char, Traits > &os, TaggedFee< UnitTag, T > const &q)
Definition FeeUnits.h:334
constexpr bool can_muldiv_commute_v
Definition FeeUnits.h:383
typename std::enable_if_t< can_muldiv_v< Source1, Source2, Dest > > enable_muldiv_t
Definition FeeUnits.h:399
constexpr bool can_muldiv_v
Definition FeeUnits.h:372
typename std::enable_if_t< can_muldiv_source_v< T > > enable_muldiv_source_t
Definition FeeUnits.h:388
typename std::enable_if_t< can_muldiv_dest_v< T > > enable_muldiv_dest_t
Definition FeeUnits.h:391
typename std::enable_if_t< can_muldiv_commute_v< Source1, Source2, Dest > > enable_muldiv_commute_t
Definition FeeUnits.h:403
TaggedFee< unitlessTag, T > scalar(T value)
Definition FeeUnits.h:407
constexpr bool can_muldiv_source_v
Definition FeeUnits.h:347
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:42
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:78
Zero allows classes to offer efficient comparisons to zero.
Definition Zero.h:43
T to_string(T... args)