xrpld
Loading...
Searching...
No Matches
Quality.h
1#pragma once
2
3#include <xrpl/protocol/AmountConversions.h>
4#include <xrpl/protocol/IOUAmount.h>
5#include <xrpl/protocol/STAmount.h>
6#include <xrpl/protocol/XRPAmount.h>
7
8#include <algorithm>
9#include <cstdint>
10#include <ostream>
11#include <utility>
12
13namespace xrpl {
14
24template <class In, class Out>
26{
27 TAmounts() = default;
28
30 {
31 }
32
33 TAmounts(In in, Out out) : in(std::move(in)), out(std::move(out))
34 {
35 }
36
38 [[nodiscard]] bool
39 empty() const noexcept
40 {
41 return in <= beast::kZero || out <= beast::kZero;
42 }
43
45 operator+=(TAmounts const& rhs)
46 {
47 in += rhs.in;
48 out += rhs.out;
49 return *this;
50 }
51
53 operator-=(TAmounts const& rhs)
54 {
55 in -= rhs.in;
56 out -= rhs.out;
57 return *this;
58 }
59
60 In in{};
62};
63
65
66template <class In, class Out>
67bool
68operator==(TAmounts<In, Out> const& lhs, TAmounts<In, Out> const& rhs) noexcept
69{
70 return lhs.in == rhs.in && lhs.out == rhs.out;
71}
72
73template <class In, class Out>
74bool
75operator!=(TAmounts<In, Out> const& lhs, TAmounts<In, Out> const& rhs) noexcept
76{
77 return !(lhs == rhs);
78}
79
80//------------------------------------------------------------------------------
81
82// XRPL specific constant used for parsing qualities and other things
83#define QUALITY_ONE 1'000'000'000
84
91{
92public:
93 // Type of the internal representation. Higher qualities
94 // have lower unsigned integer representations.
96
97 static int const kMinTickSize = 3;
98 static int const kMaxTickSize = 16;
99
100private:
101 // This has the same representation as STAmount, see the comment on the
102 // STAmount. However, this class does not always use the canonical
103 // representation. In particular, the increment and decrement operators may
104 // cause a non-canonical representation.
106
107public:
108 Quality() = default;
109
111 explicit Quality(std::uint64_t value);
112
114 explicit Quality(Amounts const& amount);
115
117 template <class In, class Out>
118 explicit Quality(TAmounts<In, Out> const& amount)
119 : Quality(Amounts(toSTAmount(amount.in), toSTAmount(amount.out)))
120 {
121 }
122
124 template <class In, class Out>
125 Quality(Out const& out, In const& in) : Quality(Amounts(toSTAmount(in), toSTAmount(out)))
126 {
127 }
128
131 Quality&
132 operator++();
133
134 Quality
135 operator++(int);
137
140 Quality&
141 operator--();
142
143 Quality
144 operator--(int);
146
148 [[nodiscard]] STAmount
149 rate() const
150 {
152 }
153
157 [[nodiscard]] Quality
158 round(int tickSize) const;
159
164 [[nodiscard]] Amounts
165 ceilIn(Amounts const& amount, STAmount const& limit) const;
166
167 template <class In, class Out>
168 [[nodiscard]] TAmounts<In, Out>
169 ceilIn(TAmounts<In, Out> const& amount, In const& limit) const;
170
171 // Some of the underlying rounding functions called by ceil_in() ignored
172 // low order bits that could influence rounding decisions. This "strict"
173 // method uses underlying functions that pay attention to all the bits.
174 [[nodiscard]] Amounts
175 ceilInStrict(Amounts const& amount, STAmount const& limit, bool roundUp) const;
176
177 template <class In, class Out>
178 [[nodiscard]] TAmounts<In, Out>
179 ceilInStrict(TAmounts<In, Out> const& amount, In const& limit, bool roundUp) const;
180
185 [[nodiscard]] Amounts
186 ceilOut(Amounts const& amount, STAmount const& limit) const;
187
188 template <class In, class Out>
189 [[nodiscard]] TAmounts<In, Out>
190 ceilOut(TAmounts<In, Out> const& amount, Out const& limit) const;
191
192 // Some of the underlying rounding functions called by ceil_out() ignored
193 // low order bits that could influence rounding decisions. This "strict"
194 // method uses underlying functions that pay attention to all the bits.
195 [[nodiscard]] Amounts
196 ceilOutStrict(Amounts const& amount, STAmount const& limit, bool roundUp) const;
197
198 template <class In, class Out>
199 [[nodiscard]] TAmounts<In, Out>
200 ceilOutStrict(TAmounts<In, Out> const& amount, Out const& limit, bool roundUp) const;
201
202private:
203 // The ceil_in and ceil_out methods that deal in TAmount all convert
204 // their arguments to STAmount and convert the result back to TAmount.
205 // This helper function takes care of all the conversion operations.
206 template <class In, class Out, class Lim, typename FnPtr, std::same_as<bool>... Round>
207 [[nodiscard]] TAmounts<In, Out>
209 TAmounts<In, Out> const& amount,
210 Lim const& limit,
211 Lim const& limitCmp,
212 FnPtr ceilFunction,
213 Round... round) const;
214
215public:
220 friend bool
221 operator<(Quality const& lhs, Quality const& rhs) noexcept
222 {
223 return lhs.value_ > rhs.value_;
224 }
225
226 friend bool
227 operator>(Quality const& lhs, Quality const& rhs) noexcept
228 {
229 return lhs.value_ < rhs.value_;
230 }
231
232 friend bool
233 operator<=(Quality const& lhs, Quality const& rhs) noexcept
234 {
235 return !(lhs > rhs);
236 }
237
238 friend bool
239 operator>=(Quality const& lhs, Quality const& rhs) noexcept
240 {
241 return !(lhs < rhs);
242 }
243
244 friend bool
245 operator==(Quality const& lhs, Quality const& rhs) noexcept
246 {
247 return lhs.value_ == rhs.value_;
248 }
249
250 friend bool
251 operator!=(Quality const& lhs, Quality const& rhs) noexcept
252 {
253 return !(lhs == rhs);
254 }
255
257 operator<<(std::ostream& os, Quality const& quality)
258 {
259 os << quality.value_;
260 return os;
261 }
262
263 // return the relative distance (relative error) between two qualities. This
264 // is used for testing only. relative distance is abs(a-b)/min(a,b)
265 friend double
266 relativeDistance(Quality const& q1, Quality const& q2)
267 {
268 XRPL_ASSERT(
269 q1.value_ > 0 && q2.value_ > 0, "xrpl::Quality::relativeDistance : minimum inputs");
270
271 if (q1.value_ == q2.value_) // make expected common case fast
272 return 0;
273
274 auto const [minV, maxV] = std::minmax(q1.value_, q2.value_);
275
276 auto mantissa = [](std::uint64_t rate) { return rate & ~(255ull << (64 - 8)); };
277 auto exponent = [](std::uint64_t rate) { return static_cast<int>(rate >> (64 - 8)) - 100; };
278
279 auto const minVMantissa = mantissa(minV);
280 auto const maxVMantissa = mantissa(maxV);
281 auto const expDiff = exponent(maxV) - exponent(minV);
282
283 double const minVD = static_cast<double>(minVMantissa);
284 double const maxVD =
285 (expDiff != 0) ? maxVMantissa * pow(10, expDiff) : static_cast<double>(maxVMantissa);
286
287 // maxVD and minVD are scaled so they have the same exponents. Dividing
288 // cancels out the exponents, so we only need to deal with the (scaled)
289 // mantissas
290 return (maxVD - minVD) / minVD;
291 }
292};
293
294template <class In, class Out, class Lim, typename FnPtr, std::same_as<bool>... Round>
295TAmounts<In, Out>
297 TAmounts<In, Out> const& amount,
298 Lim const& limit,
299 Lim const& limitCmp,
300 FnPtr ceilFunction,
301 Round... roundUp) const
302{
303 if (limitCmp <= limit)
304 return amount;
305
306 // Use the existing STAmount implementation for now, but consider
307 // replacing with code specific to IOUAMount and XRPAmount
308 Amounts const stAmt(toSTAmount(amount.in), toSTAmount(amount.out));
309 STAmount const stLim(toSTAmount(limit));
310 Amounts const stRes = ((*this).*ceilFunction)(stAmt, stLim, roundUp...);
311 return TAmounts<In, Out>(toAmount<In>(stRes.in), toAmount<Out>(stRes.out));
312}
313
314template <class In, class Out>
316Quality::ceilIn(TAmounts<In, Out> const& amount, In const& limit) const
317{
318 // Construct a function pointer to the function we want to call.
319 static constexpr Amounts (Quality::*kCeilInFnPtr)(Amounts const&, STAmount const&) const =
321
322 return ceilTAmountsHelper(amount, limit, amount.in, kCeilInFnPtr);
323}
324
325template <class In, class Out>
327Quality::ceilInStrict(TAmounts<In, Out> const& amount, In const& limit, bool roundUp) const
328{
329 // Construct a function pointer to the function we want to call.
330 static constexpr Amounts (Quality::*kCeilInFnPtr)(Amounts const&, STAmount const&, bool) const =
332
333 return ceilTAmountsHelper(amount, limit, amount.in, kCeilInFnPtr, roundUp);
334}
335
336template <class In, class Out>
338Quality::ceilOut(TAmounts<In, Out> const& amount, Out const& limit) const
339{
340 // Construct a function pointer to the function we want to call.
341 static constexpr Amounts (Quality::*kCeilOutFnPtr)(Amounts const&, STAmount const&) const =
343
344 return ceil_TAmounts_helper(amount, limit, amount.out, kCeilOutFnPtr);
345}
346
347template <class In, class Out>
349Quality::ceilOutStrict(TAmounts<In, Out> const& amount, Out const& limit, bool roundUp) const
350{
351 // Construct a function pointer to the function we want to call.
352 static constexpr Amounts (Quality::*kCeilOutFnPtr)(Amounts const&, STAmount const&, bool)
353 const = &Quality::ceilOutStrict;
354
355 return ceilTAmountsHelper(amount, limit, amount.out, kCeilOutFnPtr, roundUp);
356}
357
363composedQuality(Quality const& lhs, Quality const& rhs);
364
365} // namespace xrpl
Represents the logical ratio of output currency to input currency.
Definition Quality.h:91
Quality & operator++()
Advances to the next higher quality level.
Definition Quality.cpp:22
static int const kMaxTickSize
Definition Quality.h:98
TAmounts< In, Out > ceilTAmountsHelper(TAmounts< In, Out > const &amount, Lim const &limit, Lim const &limitCmp, FnPtr ceilFunction, Round... round) const
Definition Quality.h:296
STAmount rate() const
Returns the quality as STAmount.
Definition Quality.h:149
Quality round(int tickSize) const
Returns the quality rounded up to the specified number of decimal digits.
Definition Quality.cpp:134
friend std::ostream & operator<<(std::ostream &os, Quality const &quality)
Definition Quality.h:257
Amounts ceilOut(Amounts const &amount, STAmount const &limit) const
Returns the scaled amount with out capped.
Definition Quality.cpp:102
Amounts ceilIn(Amounts const &amount, STAmount const &limit) const
Returns the scaled amount with in capped.
Definition Quality.cpp:73
friend bool operator<=(Quality const &lhs, Quality const &rhs) noexcept
Definition Quality.h:233
friend bool operator<(Quality const &lhs, Quality const &rhs) noexcept
Returns true if lhs is lower quality than rhs.
Definition Quality.h:221
Amounts ceilOutStrict(Amounts const &amount, STAmount const &limit, bool roundUp) const
Definition Quality.cpp:108
Amounts ceilInStrict(Amounts const &amount, STAmount const &limit, bool roundUp) const
Definition Quality.cpp:79
Quality(TAmounts< In, Out > const &amount)
Create a quality from the ratio of two amounts.
Definition Quality.h:118
static int const kMinTickSize
Definition Quality.h:97
friend bool operator>=(Quality const &lhs, Quality const &rhs) noexcept
Definition Quality.h:239
friend double relativeDistance(Quality const &q1, Quality const &q2)
Definition Quality.h:266
friend bool operator!=(Quality const &lhs, Quality const &rhs) noexcept
Definition Quality.h:251
Quality & operator--()
Advances to the next lower quality level.
Definition Quality.cpp:38
std::uint64_t value_type
Definition Quality.h:95
Quality()=default
value_type value_
Definition Quality.h:105
Quality(Out const &out, In const &in)
Create a quality from the ratio of two amounts.
Definition Quality.h:125
friend bool operator>(Quality const &lhs, Quality const &rhs) noexcept
Definition Quality.h:227
friend bool operator==(Quality const &lhs, Quality const &rhs) noexcept
Definition Quality.h:245
T minmax(T... args)
STL namespace.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
constexpr bool operator==(BaseUInt< Bits, Tag > const &lhs, BaseUInt< Bits, Tag > const &rhs)
Definition base_uint.h:588
TAmounts< STAmount, STAmount > Amounts
Definition Quality.h:64
T toAmount(STAmount const &amt)=delete
STAmount amountFromQuality(std::uint64_t rate)
Definition STAmount.cpp:895
bool operator!=(Buffer const &lhs, Buffer const &rhs) noexcept
Definition Buffer.h:210
Quality composedQuality(Quality const &lhs, Quality const &rhs)
Calculate the quality of a two-hop path given the two hops.
Definition Quality.cpp:114
STAmount toSTAmount(IOUAmount const &iou, Asset const &asset)
Zero allows classes to offer efficient comparisons to zero.
Definition Zero.h:25
Represents a pair of input and output currencies.
Definition Quality.h:26
TAmounts(In in, Out out)
Definition Quality.h:33
bool empty() const noexcept
Returns true if either quantity is not positive.
Definition Quality.h:39
TAmounts(beast::Zero, beast::Zero)
Definition Quality.h:29
TAmounts & operator+=(TAmounts const &rhs)
Definition Quality.h:45
TAmounts()=default
TAmounts & operator-=(TAmounts const &rhs)
Definition Quality.h:53