rippled
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
12namespace xrpl {
13
23template <class In, class Out>
24struct TAmounts
25{
26 TAmounts() = default;
27
28 TAmounts(beast::Zero, beast::Zero) : in(beast::zero), out(beast::zero)
29 {
30 }
31
32 TAmounts(In const& in_, Out const& out_) : in(in_), out(out_)
33 {
34 }
35
37 bool
38 empty() const noexcept
39 {
40 return in <= beast::zero || out <= beast::zero;
41 }
42
43 TAmounts&
44 operator+=(TAmounts const& rhs)
45 {
46 in += rhs.in;
47 out += rhs.out;
48 return *this;
49 }
50
51 TAmounts&
52 operator-=(TAmounts const& rhs)
53 {
54 in -= rhs.in;
55 out -= rhs.out;
56 return *this;
57 }
58
59 In in{};
60 Out out{};
61};
62
63using Amounts = TAmounts<STAmount, STAmount>;
64
65template <class In, class Out>
66bool
67operator==(TAmounts<In, Out> const& lhs, TAmounts<In, Out> const& rhs) noexcept
68{
69 return lhs.in == rhs.in && lhs.out == rhs.out;
70}
71
72template <class In, class Out>
73bool
74operator!=(TAmounts<In, Out> const& lhs, TAmounts<In, Out> const& rhs) noexcept
75{
76 return !(lhs == rhs);
77}
78
79//------------------------------------------------------------------------------
80
81// Ripple specific constant used for parsing qualities and other things
82#define QUALITY_ONE 1'000'000'000
83
89class Quality
90{
91public:
92 // Type of the internal representation. Higher qualities
93 // have lower unsigned integer representations.
94 using value_type = std::uint64_t;
95
96 static int const minTickSize = 3;
97 static int const maxTickSize = 16;
98
99private:
100 // This has the same representation as STAmount, see the comment on the
101 // STAmount. However, this class does not always use the canonical
102 // representation. In particular, the increment and decrement operators may
103 // cause a non-canonical representation.
104 value_type m_value;
105
106public:
107 Quality() = default;
108
110 explicit Quality(std::uint64_t value);
111
113 explicit Quality(Amounts const& amount);
114
116 template <class In, class Out>
117 explicit Quality(TAmounts<In, Out> const& amount)
118 : Quality(Amounts(toSTAmount(amount.in), toSTAmount(amount.out)))
119 {
120 }
121
123 template <class In, class Out>
124 Quality(Out const& out, In const& in) : Quality(Amounts(toSTAmount(in), toSTAmount(out)))
125 {
126 }
127
130 Quality&
131 operator++();
132
133 Quality
134 operator++(int);
139 Quality&
140 operator--();
141
142 Quality
143 operator--(int);
147 STAmount
148 rate() const
149 {
150 return amountFromQuality(m_value);
151 }
152
156 Quality
157 round(int tickSize) const;
158
163 [[nodiscard]] Amounts
164 ceil_in(Amounts const& amount, STAmount const& limit) const;
165
166 template <class In, class Out>
167 [[nodiscard]] TAmounts<In, Out>
168 ceil_in(TAmounts<In, Out> const& amount, In const& limit) const;
169
170 // Some of the underlying rounding functions called by ceil_in() ignored
171 // low order bits that could influence rounding decisions. This "strict"
172 // method uses underlying functions that pay attention to all the bits.
173 [[nodiscard]] Amounts
174 ceil_in_strict(Amounts const& amount, STAmount const& limit, bool roundUp) const;
175
176 template <class In, class Out>
177 [[nodiscard]] TAmounts<In, Out>
178 ceil_in_strict(TAmounts<In, Out> const& amount, In const& limit, bool roundUp) const;
179
184 [[nodiscard]] Amounts
185 ceil_out(Amounts const& amount, STAmount const& limit) const;
186
187 template <class In, class Out>
188 [[nodiscard]] TAmounts<In, Out>
189 ceil_out(TAmounts<In, Out> const& amount, Out const& limit) const;
190
191 // Some of the underlying rounding functions called by ceil_out() ignored
192 // low order bits that could influence rounding decisions. This "strict"
193 // method uses underlying functions that pay attention to all the bits.
194 [[nodiscard]] Amounts
195 ceil_out_strict(Amounts const& amount, STAmount const& limit, bool roundUp) const;
196
197 template <class In, class Out>
198 [[nodiscard]] TAmounts<In, Out>
199 ceil_out_strict(TAmounts<In, Out> const& amount, Out const& limit, bool roundUp) const;
200
201private:
202 // The ceil_in and ceil_out methods that deal in TAmount all convert
203 // their arguments to STAmount and convert the result back to TAmount.
204 // This helper function takes care of all the conversion operations.
205 template <class In, class Out, class Lim, typename FnPtr, std::same_as<bool>... Round>
206 [[nodiscard]] TAmounts<In, Out>
207 ceil_TAmounts_helper(
208 TAmounts<In, Out> const& amount,
209 Lim const& limit,
210 Lim const& limit_cmp,
211 FnPtr ceil_function,
212 Round... round) const;
213
214public:
219 friend bool
220 operator<(Quality const& lhs, Quality const& rhs) noexcept
221 {
222 return lhs.m_value > rhs.m_value;
223 }
224
225 friend bool
226 operator>(Quality const& lhs, Quality const& rhs) noexcept
227 {
228 return lhs.m_value < rhs.m_value;
229 }
230
231 friend bool
232 operator<=(Quality const& lhs, Quality const& rhs) noexcept
233 {
234 return !(lhs > rhs);
235 }
236
237 friend bool
238 operator>=(Quality const& lhs, Quality const& rhs) noexcept
239 {
240 return !(lhs < rhs);
241 }
242
243 friend bool
244 operator==(Quality const& lhs, Quality const& rhs) noexcept
245 {
246 return lhs.m_value == rhs.m_value;
247 }
248
249 friend bool
250 operator!=(Quality const& lhs, Quality const& rhs) noexcept
251 {
252 return !(lhs == rhs);
253 }
254
255 friend std::ostream&
256 operator<<(std::ostream& os, Quality const& quality)
257 {
258 os << quality.m_value;
259 return os;
260 }
261
262 // return the relative distance (relative error) between two qualities. This
263 // is used for testing only. relative distance is abs(a-b)/min(a,b)
264 friend double
265 relativeDistance(Quality const& q1, Quality const& q2)
266 {
267 XRPL_ASSERT(
268 q1.m_value > 0 && q2.m_value > 0, "xrpl::Quality::relativeDistance : minimum inputs");
269
270 if (q1.m_value == q2.m_value) // make expected common case fast
271 return 0;
272
273 auto const [minV, maxV] = std::minmax(q1.m_value, q2.m_value);
274
275 auto mantissa = [](std::uint64_t rate) { return rate & ~(255ull << (64 - 8)); };
276 auto exponent = [](std::uint64_t rate) { return static_cast<int>(rate >> (64 - 8)) - 100; };
277
278 auto const minVMantissa = mantissa(minV);
279 auto const maxVMantissa = mantissa(maxV);
280 auto const expDiff = exponent(maxV) - exponent(minV);
281
282 double const minVD = static_cast<double>(minVMantissa);
283 double const maxVD =
284 expDiff ? maxVMantissa * pow(10, expDiff) : static_cast<double>(maxVMantissa);
285
286 // maxVD and minVD are scaled so they have the same exponents. Dividing
287 // cancels out the exponents, so we only need to deal with the (scaled)
288 // mantissas
289 return (maxVD - minVD) / minVD;
290 }
291};
292
293template <class In, class Out, class Lim, typename FnPtr, std::same_as<bool>... Round>
294TAmounts<In, Out>
295Quality::ceil_TAmounts_helper(
296 TAmounts<In, Out> const& amount,
297 Lim const& limit,
298 Lim const& limit_cmp,
299 FnPtr ceil_function,
300 Round... roundUp) const
301{
302 if (limit_cmp <= limit)
303 return amount;
304
305 // Use the existing STAmount implementation for now, but consider
306 // replacing with code specific to IOUAMount and XRPAmount
307 Amounts const stAmt(toSTAmount(amount.in), toSTAmount(amount.out));
308 STAmount const stLim(toSTAmount(limit));
309 Amounts const stRes = ((*this).*ceil_function)(stAmt, stLim, roundUp...);
310 return TAmounts<In, Out>(toAmount<In>(stRes.in), toAmount<Out>(stRes.out));
311}
312
313template <class In, class Out>
314TAmounts<In, Out>
315Quality::ceil_in(TAmounts<In, Out> const& amount, In const& limit) const
316{
317 // Construct a function pointer to the function we want to call.
318 static constexpr Amounts (Quality::*ceil_in_fn_ptr)(Amounts const&, STAmount const&) const =
319 &Quality::ceil_in;
320
321 return ceil_TAmounts_helper(amount, limit, amount.in, ceil_in_fn_ptr);
322}
323
324template <class In, class Out>
325TAmounts<In, Out>
326Quality::ceil_in_strict(TAmounts<In, Out> const& amount, In const& limit, bool roundUp) const
327{
328 // Construct a function pointer to the function we want to call.
329 static constexpr Amounts (Quality::*ceil_in_fn_ptr)(Amounts const&, STAmount const&, bool)
330 const = &Quality::ceil_in_strict;
331
332 return ceil_TAmounts_helper(amount, limit, amount.in, ceil_in_fn_ptr, roundUp);
333}
334
335template <class In, class Out>
336TAmounts<In, Out>
337Quality::ceil_out(TAmounts<In, Out> const& amount, Out const& limit) const
338{
339 // Construct a function pointer to the function we want to call.
340 static constexpr Amounts (Quality::*ceil_out_fn_ptr)(Amounts const&, STAmount const&) const =
341 &Quality::ceil_out;
342
343 return ceil_TAmounts_helper(amount, limit, amount.out, ceil_out_fn_ptr);
344}
345
346template <class In, class Out>
347TAmounts<In, Out>
348Quality::ceil_out_strict(TAmounts<In, Out> const& amount, Out const& limit, bool roundUp) const
349{
350 // Construct a function pointer to the function we want to call.
351 static constexpr Amounts (Quality::*ceil_out_fn_ptr)(Amounts const&, STAmount const&, bool)
352 const = &Quality::ceil_out_strict;
353
354 return ceil_TAmounts_helper(amount, limit, amount.out, ceil_out_fn_ptr, roundUp);
355}
356
361Quality
362composed_quality(Quality const& lhs, Quality const& rhs);
363
364} // namespace xrpl
T empty(T... args)
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:249
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:5
bool operator<(Slice const &lhs, Slice const &rhs) noexcept
Definition Slice.h:199
Quality composed_quality(Quality const &lhs, Quality const &rhs)
Definition Quality.cpp:113
STAmount toSTAmount(IOUAmount const &iou, Issue const &iss)
std::ostream & operator<<(std::ostream &out, base_uint< Bits, Tag > const &u)
Definition base_uint.h:617
constexpr bool operator==(base_uint< Bits, Tag > const &lhs, base_uint< Bits, Tag > const &rhs)
Definition base_uint.h:557
STAmount amountFromQuality(std::uint64_t rate)
Definition STAmount.cpp:975
bool operator!=(Buffer const &lhs, Buffer const &rhs) noexcept
Definition Buffer.h:209
T operator>(T... args)
T pow(T... args)
T round(T... args)
Zero allows classes to offer efficient comparisons to zero.
Definition Zero.h:25