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