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 <cmath>
31#include <ios>
32#include <iosfwd>
33#include <limits>
34#include <optional>
35#include <sstream>
36#include <string>
37#include <utility>
38
39namespace ripple {
40
41namespace feeunit {
42
45struct dropTag;
49struct feeunitTag;
53struct feelevelTag;
56struct unitlessTag;
57
58template <class T>
60 std::is_class_v<T> && std::is_object_v<typename T::unit_type> &&
61 std::is_object_v<typename T::value_type>>;
62
70template <class T, class = enable_if_unit_t<T>>
71constexpr bool is_usable_unit_v =
72 std::is_same_v<typename T::unit_type, feeunitTag> ||
73 std::is_same_v<typename T::unit_type, feelevelTag> ||
74 std::is_same_v<typename T::unit_type, unitlessTag> ||
75 std::is_same_v<typename T::unit_type, dropTag>;
76
77template <class UnitTag, class T>
78class TaggedFee : private boost::totally_ordered<TaggedFee<UnitTag, T>>,
79 private boost::additive<TaggedFee<UnitTag, T>>,
80 private boost::equality_comparable<TaggedFee<UnitTag, T>, T>,
81 private boost::dividable<TaggedFee<UnitTag, T>, T>,
82 private boost::modable<TaggedFee<UnitTag, T>, T>,
83 private boost::unit_steppable<TaggedFee<UnitTag, T>>
84{
85public:
86 using unit_type = UnitTag;
87 using value_type = T;
88
89private:
91
92protected:
93 template <class Other>
94 static constexpr bool is_compatible_v =
95 std::is_arithmetic_v<Other> && std::is_arithmetic_v<value_type> &&
96 std::is_convertible_v<Other, value_type>;
97
98 template <class OtherFee, class = enable_if_unit_t<OtherFee>>
99 static constexpr bool is_compatiblefee_v =
100 is_compatible_v<typename OtherFee::value_type> &&
101 std::is_same_v<UnitTag, typename OtherFee::unit_type>;
102
103 template <class Other>
106
107 template <class OtherFee>
110
111public:
112 TaggedFee() = default;
113 constexpr TaggedFee(TaggedFee const& other) = default;
114 constexpr TaggedFee&
115 operator=(TaggedFee const& other) = default;
116
117 constexpr explicit TaggedFee(beast::Zero) : fee_(0)
118 {
119 }
120
121 constexpr TaggedFee&
123 {
124 fee_ = 0;
125 return *this;
126 }
127
128 constexpr explicit TaggedFee(value_type fee) : fee_(fee)
129 {
130 }
131
132 TaggedFee&
134 {
135 fee_ = fee;
136 return *this;
137 }
138
142 template <
143 class Other,
144 class = std::enable_if_t<
145 is_compatible_v<Other> &&
146 is_safetocasttovalue_v<value_type, Other>>>
149 {
150 }
151
152 constexpr TaggedFee
153 operator*(value_type const& rhs) const
154 {
155 return TaggedFee{fee_ * rhs};
156 }
157
158 friend constexpr TaggedFee
160 {
161 // multiplication is commutative
162 return rhs * lhs;
163 }
164
165 constexpr value_type
166 operator/(TaggedFee const& rhs) const
167 {
168 return fee_ / rhs.fee_;
169 }
170
171 TaggedFee&
172 operator+=(TaggedFee const& other)
173 {
174 fee_ += other.fee();
175 return *this;
176 }
177
178 TaggedFee&
179 operator-=(TaggedFee const& other)
180 {
181 fee_ -= other.fee();
182 return *this;
183 }
184
185 TaggedFee&
187 {
188 ++fee_;
189 return *this;
190 }
191
192 TaggedFee&
194 {
195 --fee_;
196 return *this;
197 }
198
199 TaggedFee&
201 {
202 fee_ *= rhs;
203 return *this;
204 }
205
206 TaggedFee&
208 {
209 fee_ /= rhs;
210 return *this;
211 }
212
213 template <class transparent = value_type>
216 {
217 fee_ %= rhs;
218 return *this;
219 }
220
222 operator-() const
223 {
224 static_assert(
225 std::is_signed_v<T>, "- operator illegal on unsigned fee types");
226 return TaggedFee{-fee_};
227 }
228
229 bool
230 operator==(TaggedFee const& other) const
231 {
232 return fee_ == other.fee_;
233 }
234
235 template <class Other, class = enable_if_compatible_t<Other>>
236 bool
238 {
239 return fee_ == other.fee();
240 }
241
242 bool
244 {
245 return fee_ == other;
246 }
247
248 template <class Other, class = enable_if_compatible_t<Other>>
249 bool
251 {
252 return !operator==(other);
253 }
254
255 bool
256 operator<(TaggedFee const& other) const
257 {
258 return fee_ < other.fee_;
259 }
260
262 explicit constexpr
263 operator bool() const noexcept
264 {
265 return fee_ != 0;
266 }
267
269 constexpr int
270 signum() const noexcept
271 {
272 return (fee_ < 0) ? -1 : (fee_ ? 1 : 0);
273 }
274
276 constexpr value_type
277 fee() const
278 {
279 return fee_;
280 }
281
282 template <class Other>
283 constexpr double
285 {
286 return static_cast<double>(fee_) / reference.fee();
287 }
288
289 // `is_usable_unit_v` is checked to ensure that only values with
290 // known valid type tags can be converted to JSON. At the time
291 // of implementation, that includes all known tags, but more may
292 // be added in the future.
295 {
296 if constexpr (std::is_integral_v<value_type>)
297 {
298 using jsontype = std::conditional_t<
299 std::is_signed_v<value_type>,
300 Json::Int,
301 Json::UInt>;
302
303 constexpr auto min = std::numeric_limits<jsontype>::min();
304 constexpr auto max = std::numeric_limits<jsontype>::max();
305
306 if (fee_ < min)
307 return min;
308 if (fee_ > max)
309 return max;
310 return static_cast<jsontype>(fee_);
311 }
312 else
313 {
314 return fee_;
315 }
316 }
317
322 constexpr value_type
323 value() const
324 {
325 return fee_;
326 }
327
328 friend std::istream&
330 {
331 s >> val.fee_;
332 return s;
333 }
334};
335
336// Output Fees as just their numeric value.
337template <class Char, class Traits, class UnitTag, class T>
339operator<<(std::basic_ostream<Char, Traits>& os, TaggedFee<UnitTag, T> const& q)
340{
341 return os << q.value();
342}
343
344template <class UnitTag, class T>
347{
348 return std::to_string(amount.fee());
349}
350
351template <class Source, class = enable_if_unit_t<Source>>
352constexpr bool can_muldiv_source_v =
353 std::is_convertible_v<typename Source::value_type, std::uint64_t>;
354
355template <class Dest, class = enable_if_unit_t<Dest>>
356constexpr bool can_muldiv_dest_v =
357 can_muldiv_source_v<Dest> && // Dest is also a source
358 std::is_convertible_v<std::uint64_t, typename Dest::value_type> &&
359 sizeof(typename Dest::value_type) >= sizeof(std::uint64_t);
360
361template <
362 class Source1,
363 class Source2,
366constexpr bool can_muldiv_sources_v =
367 can_muldiv_source_v<Source1> && can_muldiv_source_v<Source2> &&
368 std::is_same_v<typename Source1::unit_type, typename Source2::unit_type>;
369
370template <
371 class Source1,
372 class Source2,
373 class Dest,
377constexpr bool can_muldiv_v =
378 can_muldiv_sources_v<Source1, Source2> && can_muldiv_dest_v<Dest>;
379// Source and Dest can be the same by default
380
381template <
382 class Source1,
383 class Source2,
384 class Dest,
388constexpr bool can_muldiv_commute_v = can_muldiv_v<Source1, Source2, Dest> &&
389 !std::is_same_v<typename Source1::unit_type, typename Dest::unit_type>;
390
391template <class T>
394
395template <class T>
397
398template <class Source1, class Source2>
401
402template <class Source1, class Source2, class Dest>
405
406template <class Source1, class Source2, class Dest>
409
410template <class T>
412scalar(T value)
413{
414 return TaggedFee<unitlessTag, T>{value};
415}
416
417template <
418 class Source1,
419 class Source2,
420 class Dest,
421 class = enable_muldiv_t<Source1, Source2, Dest>>
423mulDivU(Source1 value, Dest mul, Source2 div)
424{
425 // Fees can never be negative in any context.
426 if (value.value() < 0 || mul.value() < 0 || div.value() < 0)
427 {
428 // split the asserts so if one hits, the user can tell which
429 // without a debugger.
430 XRPL_ASSERT(
431 value.value() >= 0,
432 "ripple::feeunit::mulDivU : minimum value input");
433 XRPL_ASSERT(
434 mul.value() >= 0, "ripple::feeunit::mulDivU : minimum mul input");
435 XRPL_ASSERT(
436 div.value() >= 0, "ripple::feeunit::mulDivU : minimum div input");
437 return std::nullopt;
438 }
439
440 using desttype = typename Dest::value_type;
441 constexpr auto max = std::numeric_limits<desttype>::max();
442
443 // Shortcuts, since these happen a lot in the real world
444 if (value == div)
445 return mul;
446 if (mul.value() == div.value())
447 {
448 if (value.value() > max)
449 return std::nullopt;
450 return Dest{static_cast<desttype>(value.value())};
451 }
452
453 using namespace boost::multiprecision;
454
455 uint128_t product;
456 product = multiply(
457 product,
458 static_cast<std::uint64_t>(value.value()),
459 static_cast<std::uint64_t>(mul.value()));
460
461 auto quotient = product / div.value();
462
463 if (quotient > max)
464 return std::nullopt;
465
466 return Dest{static_cast<desttype>(quotient)};
467}
468
469} // namespace feeunit
470
471template <class T>
475
476template <
477 class Source1,
478 class Source2,
479 class Dest,
482mulDiv(Source1 value, Dest mul, Source2 div)
483{
484 return feeunit::mulDivU(value, mul, div);
485}
486
487template <
488 class Source1,
489 class Source2,
490 class Dest,
491 class = feeunit::enable_muldiv_commute_t<Source1, Source2, Dest>>
493mulDiv(Dest value, Source1 mul, Source2 div)
494{
495 // Multiplication is commutative
496 return feeunit::mulDivU(mul, value, div);
497}
498
499template <class Dest, class = feeunit::enable_muldiv_dest_t<Dest>>
501mulDiv(std::uint64_t value, Dest mul, std::uint64_t div)
502{
503 // Give the scalars a non-tag so the
504 // unit-handling version gets called.
505 return feeunit::mulDivU(feeunit::scalar(value), mul, feeunit::scalar(div));
506}
507
508template <class Dest, class = feeunit::enable_muldiv_dest_t<Dest>>
510mulDiv(Dest value, std::uint64_t mul, std::uint64_t div)
511{
512 // Multiplication is commutative
513 return mulDiv(mul, value, div);
514}
515
516template <
517 class Source1,
518 class Source2,
519 class = feeunit::enable_muldiv_sources_t<Source1, Source2>>
521mulDiv(Source1 value, std::uint64_t mul, Source2 div)
522{
523 // Give the scalars a dimensionless unit so the
524 // unit-handling version gets called.
525 auto unitresult = feeunit::mulDivU(value, feeunit::scalar(mul), div);
526
527 if (!unitresult)
528 return std::nullopt;
529
530 return unitresult->value();
531}
532
533template <
534 class Source1,
535 class Source2,
536 class = feeunit::enable_muldiv_sources_t<Source1, Source2>>
538mulDiv(std::uint64_t value, Source1 mul, Source2 div)
539{
540 // Multiplication is commutative
541 return mulDiv(mul, value, div);
542}
543
544template <class Dest, class Src>
545constexpr std::enable_if_t<
546 std::is_same_v<typename Dest::unit_type, typename Src::unit_type> &&
547 std::is_integral_v<typename Dest::value_type> &&
548 std::is_integral_v<typename Src::value_type>,
549 Dest>
550safe_cast(Src s) noexcept
551{
552 // Dest may not have an explicit value constructor
553 return Dest{safe_cast<typename Dest::value_type>(s.value())};
554}
555
556template <class Dest, class Src>
557constexpr std::enable_if_t<
558 std::is_same_v<typename Dest::unit_type, typename Src::unit_type> &&
559 std::is_integral_v<typename Dest::value_type> &&
560 std::is_integral_v<typename Src::value_type>,
561 Dest>
562unsafe_cast(Src s) noexcept
563{
564 // Dest may not have an explicit value constructor
565 return Dest{unsafe_cast<typename Dest::value_type>(s.value())};
566}
567
568} // namespace ripple
569
570#endif // BASICS_FEES_H_INCLUDED
Represents a JSON value.
Definition: json_value.h:150
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:147
std::enable_if_t< is_usable_unit_v< TaggedFee >, Json::Value > jsonClipped() const
Definition: FeeUnits.h:294
constexpr TaggedFee & operator=(TaggedFee const &other)=default
TaggedFee & operator++()
Definition: FeeUnits.h:186
TaggedFee & operator--()
Definition: FeeUnits.h:193
TaggedFee & operator=(value_type fee)
Definition: FeeUnits.h:133
bool operator==(value_type other) const
Definition: FeeUnits.h:243
bool operator==(TaggedFee< unit_type, Other > const &other) const
Definition: FeeUnits.h:237
constexpr value_type operator/(TaggedFee const &rhs) const
Definition: FeeUnits.h:166
friend constexpr TaggedFee operator*(value_type lhs, TaggedFee const &rhs)
Definition: FeeUnits.h:159
static constexpr bool is_compatiblefee_v
Definition: FeeUnits.h:99
constexpr value_type value() const
Returns the underlying value.
Definition: FeeUnits.h:323
friend std::istream & operator>>(std::istream &s, TaggedFee &val)
Definition: FeeUnits.h:329
constexpr int signum() const noexcept
Return the sign of the amount.
Definition: FeeUnits.h:270
std::enable_if_t< std::is_integral_v< transparent >, TaggedFee & > operator%=(value_type const &rhs)
Definition: FeeUnits.h:215
typename std::enable_if_t< is_compatible_v< Other > > enable_if_compatible_t
Definition: FeeUnits.h:105
constexpr TaggedFee & operator=(beast::Zero)
Definition: FeeUnits.h:122
constexpr TaggedFee(value_type fee)
Definition: FeeUnits.h:128
typename std::enable_if_t< is_compatiblefee_v< OtherFee > > enable_if_compatiblefee_t
Definition: FeeUnits.h:109
constexpr TaggedFee(beast::Zero)
Definition: FeeUnits.h:117
TaggedFee operator-() const
Definition: FeeUnits.h:222
constexpr TaggedFee(TaggedFee const &other)=default
TaggedFee & operator-=(TaggedFee const &other)
Definition: FeeUnits.h:179
TaggedFee & operator*=(value_type const &rhs)
Definition: FeeUnits.h:200
constexpr double decimalFromReference(TaggedFee< unit_type, Other > reference) const
Definition: FeeUnits.h:284
bool operator<(TaggedFee const &other) const
Definition: FeeUnits.h:256
static constexpr bool is_compatible_v
Definition: FeeUnits.h:94
constexpr value_type fee() const
Returns the number of drops.
Definition: FeeUnits.h:277
TaggedFee & operator/=(value_type const &rhs)
Definition: FeeUnits.h:207
constexpr TaggedFee operator*(value_type const &rhs) const
Definition: FeeUnits.h:153
TaggedFee & operator+=(TaggedFee const &other)
Definition: FeeUnits.h:172
bool operator!=(TaggedFee< unit_type, Other > const &other) const
Definition: FeeUnits.h:250
bool operator==(TaggedFee const &other) const
Definition: FeeUnits.h:230
Set the fee on a JTx.
Definition: fee.h:37
T max(T... args)
T min(T... args)
int Int
Definition: json_forwards.h:26
unsigned int UInt
Definition: json_forwards.h:27
typename std::enable_if_t< can_muldiv_sources_v< Source1, Source2 > > enable_muldiv_sources_t
Definition: FeeUnits.h:400
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:71
std::string to_string(TaggedFee< UnitTag, T > const &amount)
Definition: FeeUnits.h:346
constexpr bool can_muldiv_dest_v
Definition: FeeUnits.h:356
std::optional< Dest > mulDivU(Source1 value, Dest mul, Source2 div)
Definition: FeeUnits.h:423
constexpr bool can_muldiv_sources_v
Definition: FeeUnits.h:366
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:61
std::basic_ostream< Char, Traits > & operator<<(std::basic_ostream< Char, Traits > &os, TaggedFee< UnitTag, T > const &q)
Definition: FeeUnits.h:339
constexpr bool can_muldiv_commute_v
Definition: FeeUnits.h:388
typename std::enable_if_t< can_muldiv_v< Source1, Source2, Dest > > enable_muldiv_t
Definition: FeeUnits.h:404
constexpr bool can_muldiv_v
Definition: FeeUnits.h:377
typename std::enable_if_t< can_muldiv_source_v< T > > enable_muldiv_source_t
Definition: FeeUnits.h:393
typename std::enable_if_t< can_muldiv_dest_v< T > > enable_muldiv_dest_t
Definition: FeeUnits.h:396
typename std::enable_if_t< can_muldiv_commute_v< Source1, Source2, Dest > > enable_muldiv_commute_t
Definition: FeeUnits.h:408
TaggedFee< unitlessTag, T > scalar(T value)
Definition: FeeUnits.h:412
constexpr bool can_muldiv_source_v
Definition: FeeUnits.h:352
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
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.
Definition: mulDiv.cpp:32
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)