rippled
Loading...
Searching...
No Matches
Quality.h
1#ifndef XRPL_PROTOCOL_QUALITY_H_INCLUDED
2#define XRPL_PROTOCOL_QUALITY_H_INCLUDED
3
4#include <xrpl/protocol/AmountConversions.h>
5#include <xrpl/protocol/IOUAmount.h>
6#include <xrpl/protocol/STAmount.h>
7#include <xrpl/protocol/XRPAmount.h>
8
9#include <algorithm>
10#include <cstdint>
11#include <ostream>
12
13namespace ripple {
14
24template <class In, class Out>
25struct TAmounts
26{
27 TAmounts() = default;
28
29 TAmounts(beast::Zero, beast::Zero) : in(beast::zero), out(beast::zero)
30 {
31 }
32
33 TAmounts(In const& in_, Out const& out_) : in(in_), out(out_)
34 {
35 }
36
38 bool
39 empty() const noexcept
40 {
41 return in <= beast::zero || out <= beast::zero;
42 }
43
44 TAmounts&
45 operator+=(TAmounts const& rhs)
46 {
47 in += rhs.in;
48 out += rhs.out;
49 return *this;
50 }
51
52 TAmounts&
53 operator-=(TAmounts const& rhs)
54 {
55 in -= rhs.in;
56 out -= rhs.out;
57 return *this;
58 }
59
60 In in;
61 Out out;
62};
63
64using Amounts = TAmounts<STAmount, STAmount>;
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// Ripple specific constant used for parsing qualities and other things
83#define QUALITY_ONE 1'000'000'000
84
90class Quality
91{
92public:
93 // Type of the internal representation. Higher qualities
94 // have lower unsigned integer representations.
95 using value_type = std::uint64_t;
96
97 static int const minTickSize = 3;
98 static int const maxTickSize = 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.
105 value_type m_value;
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)
126 : Quality(Amounts(toSTAmount(in), toSTAmount(out)))
127 {
128 }
129
132 Quality&
133 operator++();
134
135 Quality
136 operator++(int);
141 Quality&
142 operator--();
143
144 Quality
145 operator--(int);
149 STAmount
150 rate() const
151 {
152 return amountFromQuality(m_value);
153 }
154
158 Quality
159 round(int tickSize) const;
160
165 [[nodiscard]] Amounts
166 ceil_in(Amounts const& amount, STAmount const& limit) const;
167
168 template <class In, class Out>
169 [[nodiscard]] TAmounts<In, Out>
170 ceil_in(TAmounts<In, Out> const& amount, In const& limit) const;
171
172 // Some of the underlying rounding functions called by ceil_in() ignored
173 // low order bits that could influence rounding decisions. This "strict"
174 // method uses underlying functions that pay attention to all the bits.
175 [[nodiscard]] Amounts
176 ceil_in_strict(Amounts const& amount, STAmount const& limit, bool roundUp)
177 const;
178
179 template <class In, class Out>
180 [[nodiscard]] TAmounts<In, Out>
181 ceil_in_strict(
182 TAmounts<In, Out> const& amount,
183 In const& limit,
184 bool roundUp) const;
185
190 [[nodiscard]] Amounts
191 ceil_out(Amounts const& amount, STAmount const& limit) const;
192
193 template <class In, class Out>
194 [[nodiscard]] TAmounts<In, Out>
195 ceil_out(TAmounts<In, Out> const& amount, Out const& limit) const;
196
197 // Some of the underlying rounding functions called by ceil_out() ignored
198 // low order bits that could influence rounding decisions. This "strict"
199 // method uses underlying functions that pay attention to all the bits.
200 [[nodiscard]] Amounts
201 ceil_out_strict(Amounts const& amount, STAmount const& limit, bool roundUp)
202 const;
203
204 template <class In, class Out>
205 [[nodiscard]] TAmounts<In, Out>
206 ceil_out_strict(
207 TAmounts<In, Out> const& amount,
208 Out const& limit,
209 bool roundUp) const;
210
211private:
212 // The ceil_in and ceil_out methods that deal in TAmount all convert
213 // their arguments to STAoumout and convert the result back to TAmount.
214 // This helper function takes care of all the conversion operations.
215 template <
216 class In,
217 class Out,
218 class Lim,
219 typename FnPtr,
220 std::same_as<bool>... Round>
221 [[nodiscard]] TAmounts<In, Out>
222 ceil_TAmounts_helper(
223 TAmounts<In, Out> const& amount,
224 Lim const& limit,
225 Lim const& limit_cmp,
226 FnPtr ceil_function,
227 Round... round) const;
228
229public:
234 friend bool
235 operator<(Quality const& lhs, Quality const& rhs) noexcept
236 {
237 return lhs.m_value > rhs.m_value;
238 }
239
240 friend bool
241 operator>(Quality const& lhs, Quality const& rhs) noexcept
242 {
243 return lhs.m_value < rhs.m_value;
244 }
245
246 friend bool
247 operator<=(Quality const& lhs, Quality const& rhs) noexcept
248 {
249 return !(lhs > rhs);
250 }
251
252 friend bool
253 operator>=(Quality const& lhs, Quality const& rhs) noexcept
254 {
255 return !(lhs < rhs);
256 }
257
258 friend bool
259 operator==(Quality const& lhs, Quality const& rhs) noexcept
260 {
261 return lhs.m_value == rhs.m_value;
262 }
263
264 friend bool
265 operator!=(Quality const& lhs, Quality const& rhs) noexcept
266 {
267 return !(lhs == rhs);
268 }
269
270 friend std::ostream&
271 operator<<(std::ostream& os, Quality const& quality)
272 {
273 os << quality.m_value;
274 return os;
275 }
276
277 // return the relative distance (relative error) between two qualities. This
278 // is used for testing only. relative distance is abs(a-b)/min(a,b)
279 friend double
280 relativeDistance(Quality const& q1, Quality const& q2)
281 {
282 XRPL_ASSERT(
283 q1.m_value > 0 && q2.m_value > 0,
284 "ripple::Quality::relativeDistance : minimum inputs");
285
286 if (q1.m_value == q2.m_value) // make expected common case fast
287 return 0;
288
289 auto const [minV, maxV] = std::minmax(q1.m_value, q2.m_value);
290
291 auto mantissa = [](std::uint64_t rate) {
292 return rate & ~(255ull << (64 - 8));
293 };
294 auto exponent = [](std::uint64_t rate) {
295 return static_cast<int>(rate >> (64 - 8)) - 100;
296 };
297
298 auto const minVMantissa = mantissa(minV);
299 auto const maxVMantissa = mantissa(maxV);
300 auto const expDiff = exponent(maxV) - exponent(minV);
301
302 double const minVD = static_cast<double>(minVMantissa);
303 double const maxVD = expDiff ? maxVMantissa * pow(10, expDiff)
304 : static_cast<double>(maxVMantissa);
305
306 // maxVD and minVD are scaled so they have the same exponents. Dividing
307 // cancels out the exponents, so we only need to deal with the (scaled)
308 // mantissas
309 return (maxVD - minVD) / minVD;
310 }
311};
312
313template <
314 class In,
315 class Out,
316 class Lim,
317 typename FnPtr,
318 std::same_as<bool>... Round>
319TAmounts<In, Out>
320Quality::ceil_TAmounts_helper(
321 TAmounts<In, Out> const& amount,
322 Lim const& limit,
323 Lim const& limit_cmp,
324 FnPtr ceil_function,
325 Round... roundUp) const
326{
327 if (limit_cmp <= limit)
328 return amount;
329
330 // Use the existing STAmount implementation for now, but consider
331 // replacing with code specific to IOUAMount and XRPAmount
332 Amounts stAmt(toSTAmount(amount.in), toSTAmount(amount.out));
333 STAmount stLim(toSTAmount(limit));
334 Amounts const stRes = ((*this).*ceil_function)(stAmt, stLim, roundUp...);
335 return TAmounts<In, Out>(toAmount<In>(stRes.in), toAmount<Out>(stRes.out));
336}
337
338template <class In, class Out>
339TAmounts<In, Out>
340Quality::ceil_in(TAmounts<In, Out> const& amount, In const& limit) const
341{
342 // Construct a function pointer to the function we want to call.
343 static constexpr Amounts (Quality::*ceil_in_fn_ptr)(
344 Amounts const&, STAmount const&) const = &Quality::ceil_in;
345
346 return ceil_TAmounts_helper(amount, limit, amount.in, ceil_in_fn_ptr);
347}
348
349template <class In, class Out>
350TAmounts<In, Out>
351Quality::ceil_in_strict(
352 TAmounts<In, Out> const& amount,
353 In const& limit,
354 bool roundUp) const
355{
356 // Construct a function pointer to the function we want to call.
357 static constexpr Amounts (Quality::*ceil_in_fn_ptr)(
358 Amounts const&, STAmount const&, bool) const = &Quality::ceil_in_strict;
359
360 return ceil_TAmounts_helper(
361 amount, limit, amount.in, ceil_in_fn_ptr, roundUp);
362}
363
364template <class In, class Out>
365TAmounts<In, Out>
366Quality::ceil_out(TAmounts<In, Out> const& amount, Out const& limit) const
367{
368 // Construct a function pointer to the function we want to call.
369 static constexpr Amounts (Quality::*ceil_out_fn_ptr)(
370 Amounts const&, STAmount const&) const = &Quality::ceil_out;
371
372 return ceil_TAmounts_helper(amount, limit, amount.out, ceil_out_fn_ptr);
373}
374
375template <class In, class Out>
376TAmounts<In, Out>
377Quality::ceil_out_strict(
378 TAmounts<In, Out> const& amount,
379 Out const& limit,
380 bool roundUp) const
381{
382 // Construct a function pointer to the function we want to call.
383 static constexpr Amounts (Quality::*ceil_out_fn_ptr)(
384 Amounts const&, STAmount const&, bool) const =
385 &Quality::ceil_out_strict;
386
387 return ceil_TAmounts_helper(
388 amount, limit, amount.out, ceil_out_fn_ptr, roundUp);
389}
390
395Quality
396composed_quality(Quality const& lhs, Quality const& rhs);
397
398} // namespace ripple
399
400#endif
T empty(T... args)
T is_same_v
T minmax(T... args)
Keylet quality(Keylet const &k, std::uint64_t q) noexcept
The initial directory page for a specific quality.
Definition Indexes.cpp:261
Rate rate(Env &env, Account const &account, std::uint32_t const &seq)
Definition escrow.cpp:50
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:6
bool operator!=(Buffer const &lhs, Buffer const &rhs) noexcept
Definition Buffer.h:213
STAmount toSTAmount(IOUAmount const &iou, Issue const &iss)
STAmount amountFromQuality(std::uint64_t rate)
Definition STAmount.cpp:965
std::ostream & operator<<(std::ostream &out, base_uint< Bits, Tag > const &u)
Definition base_uint.h:628
Quality composed_quality(Quality const &lhs, Quality const &rhs)
Definition Quality.cpp:139
bool operator<(Slice const &lhs, Slice const &rhs) noexcept
Definition Slice.h:204
constexpr bool operator==(base_uint< Bits, Tag > const &lhs, base_uint< Bits, Tag > const &rhs)
Definition base_uint.h:566
T operator>(T... args)
T pow(T... args)
T round(T... args)
Zero allows classes to offer efficient comparisons to zero.
Definition Zero.h:26