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) : Quality(Amounts(toSTAmount(amount.in), toSTAmount(amount.out)))
118 {
119 }
120
122 template <class In, class Out>
123 Quality(Out const& out, In const& in) : Quality(Amounts(toSTAmount(in), toSTAmount(out)))
124 {
125 }
126
129 Quality&
130 operator++();
131
132 Quality
133 operator++(int);
138 Quality&
139 operator--();
140
141 Quality
142 operator--(int);
146 STAmount
147 rate() const
148 {
149 return amountFromQuality(m_value);
150 }
151
155 Quality
156 round(int tickSize) const;
157
162 [[nodiscard]] Amounts
163 ceil_in(Amounts const& amount, STAmount const& limit) const;
164
165 template <class In, class Out>
166 [[nodiscard]] TAmounts<In, Out>
167 ceil_in(TAmounts<In, Out> const& amount, In const& limit) const;
168
169 // Some of the underlying rounding functions called by ceil_in() ignored
170 // low order bits that could influence rounding decisions. This "strict"
171 // method uses underlying functions that pay attention to all the bits.
172 [[nodiscard]] Amounts
173 ceil_in_strict(Amounts const& amount, STAmount const& limit, bool roundUp) const;
174
175 template <class In, class Out>
176 [[nodiscard]] TAmounts<In, Out>
177 ceil_in_strict(TAmounts<In, Out> const& amount, In const& limit, bool roundUp) const;
178
183 [[nodiscard]] Amounts
184 ceil_out(Amounts const& amount, STAmount const& limit) const;
185
186 template <class In, class Out>
187 [[nodiscard]] TAmounts<In, Out>
188 ceil_out(TAmounts<In, Out> const& amount, Out const& limit) const;
189
190 // Some of the underlying rounding functions called by ceil_out() ignored
191 // low order bits that could influence rounding decisions. This "strict"
192 // method uses underlying functions that pay attention to all the bits.
193 [[nodiscard]] Amounts
194 ceil_out_strict(Amounts const& amount, STAmount const& limit, bool roundUp) const;
195
196 template <class In, class Out>
197 [[nodiscard]] TAmounts<In, Out>
198 ceil_out_strict(TAmounts<In, Out> const& amount, Out const& limit, bool roundUp) const;
199
200private:
201 // The ceil_in and ceil_out methods that deal in TAmount all convert
202 // their arguments to STAmount and convert the result back to TAmount.
203 // This helper function takes care of all the conversion operations.
204 template <class In, class Out, class Lim, typename FnPtr, std::same_as<bool>... Round>
205 [[nodiscard]] TAmounts<In, Out>
206 ceil_TAmounts_helper(
207 TAmounts<In, Out> const& amount,
208 Lim const& limit,
209 Lim const& limit_cmp,
210 FnPtr ceil_function,
211 Round... round) const;
212
213public:
218 friend bool
219 operator<(Quality const& lhs, Quality const& rhs) noexcept
220 {
221 return lhs.m_value > rhs.m_value;
222 }
223
224 friend bool
225 operator>(Quality const& lhs, Quality const& rhs) noexcept
226 {
227 return lhs.m_value < rhs.m_value;
228 }
229
230 friend bool
231 operator<=(Quality const& lhs, Quality const& rhs) noexcept
232 {
233 return !(lhs > rhs);
234 }
235
236 friend bool
237 operator>=(Quality const& lhs, Quality const& rhs) noexcept
238 {
239 return !(lhs < rhs);
240 }
241
242 friend bool
243 operator==(Quality const& lhs, Quality const& rhs) noexcept
244 {
245 return lhs.m_value == rhs.m_value;
246 }
247
248 friend bool
249 operator!=(Quality const& lhs, Quality const& rhs) noexcept
250 {
251 return !(lhs == rhs);
252 }
253
254 friend std::ostream&
255 operator<<(std::ostream& os, Quality const& quality)
256 {
257 os << quality.m_value;
258 return os;
259 }
260
261 // return the relative distance (relative error) between two qualities. This
262 // is used for testing only. relative distance is abs(a-b)/min(a,b)
263 friend double
264 relativeDistance(Quality const& q1, Quality const& q2)
265 {
266 XRPL_ASSERT(q1.m_value > 0 && q2.m_value > 0, "xrpl::Quality::relativeDistance : minimum inputs");
267
268 if (q1.m_value == q2.m_value) // make expected common case fast
269 return 0;
270
271 auto const [minV, maxV] = std::minmax(q1.m_value, q2.m_value);
272
273 auto mantissa = [](std::uint64_t rate) { return rate & ~(255ull << (64 - 8)); };
274 auto exponent = [](std::uint64_t rate) { return static_cast<int>(rate >> (64 - 8)) - 100; };
275
276 auto const minVMantissa = mantissa(minV);
277 auto const maxVMantissa = mantissa(maxV);
278 auto const expDiff = exponent(maxV) - exponent(minV);
279
280 double const minVD = static_cast<double>(minVMantissa);
281 double const maxVD = expDiff ? maxVMantissa * pow(10, expDiff) : static_cast<double>(maxVMantissa);
282
283 // maxVD and minVD are scaled so they have the same exponents. Dividing
284 // cancels out the exponents, so we only need to deal with the (scaled)
285 // mantissas
286 return (maxVD - minVD) / minVD;
287 }
288};
289
290template <class In, class Out, class Lim, typename FnPtr, std::same_as<bool>... Round>
291TAmounts<In, Out>
292Quality::ceil_TAmounts_helper(
293 TAmounts<In, Out> const& amount,
294 Lim const& limit,
295 Lim const& limit_cmp,
296 FnPtr ceil_function,
297 Round... roundUp) const
298{
299 if (limit_cmp <= limit)
300 return amount;
301
302 // Use the existing STAmount implementation for now, but consider
303 // replacing with code specific to IOUAMount and XRPAmount
304 Amounts stAmt(toSTAmount(amount.in), toSTAmount(amount.out));
305 STAmount stLim(toSTAmount(limit));
306 Amounts const stRes = ((*this).*ceil_function)(stAmt, stLim, roundUp...);
307 return TAmounts<In, Out>(toAmount<In>(stRes.in), toAmount<Out>(stRes.out));
308}
309
310template <class In, class Out>
311TAmounts<In, Out>
312Quality::ceil_in(TAmounts<In, Out> const& amount, In const& limit) const
313{
314 // Construct a function pointer to the function we want to call.
315 static constexpr Amounts (Quality::*ceil_in_fn_ptr)(Amounts const&, STAmount const&) const = &Quality::ceil_in;
316
317 return ceil_TAmounts_helper(amount, limit, amount.in, ceil_in_fn_ptr);
318}
319
320template <class In, class Out>
321TAmounts<In, Out>
322Quality::ceil_in_strict(TAmounts<In, Out> const& amount, In const& limit, bool roundUp) const
323{
324 // Construct a function pointer to the function we want to call.
325 static constexpr Amounts (Quality::*ceil_in_fn_ptr)(Amounts const&, STAmount const&, bool) const =
326 &Quality::ceil_in_strict;
327
328 return ceil_TAmounts_helper(amount, limit, amount.in, ceil_in_fn_ptr, roundUp);
329}
330
331template <class In, class Out>
332TAmounts<In, Out>
333Quality::ceil_out(TAmounts<In, Out> const& amount, Out const& limit) const
334{
335 // Construct a function pointer to the function we want to call.
336 static constexpr Amounts (Quality::*ceil_out_fn_ptr)(Amounts const&, STAmount const&) const = &Quality::ceil_out;
337
338 return ceil_TAmounts_helper(amount, limit, amount.out, ceil_out_fn_ptr);
339}
340
341template <class In, class Out>
342TAmounts<In, Out>
343Quality::ceil_out_strict(TAmounts<In, Out> const& amount, Out const& limit, bool roundUp) const
344{
345 // Construct a function pointer to the function we want to call.
346 static constexpr Amounts (Quality::*ceil_out_fn_ptr)(Amounts const&, STAmount const&, bool) const =
347 &Quality::ceil_out_strict;
348
349 return ceil_TAmounts_helper(amount, limit, amount.out, ceil_out_fn_ptr, roundUp);
350}
351
356Quality
357composed_quality(Quality const& lhs, Quality const& rhs);
358
359} // 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:241
Rate rate(Env &env, Account const &account, std::uint32_t const &seq)
Definition escrow.cpp:50
auto const amount
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:198
Quality composed_quality(Quality const &lhs, Quality const &rhs)
Definition Quality.cpp:111
STAmount toSTAmount(IOUAmount const &iou, Issue const &iss)
std::ostream & operator<<(std::ostream &out, base_uint< Bits, Tag > const &u)
Definition base_uint.h:612
constexpr bool operator==(base_uint< Bits, Tag > const &lhs, base_uint< Bits, Tag > const &rhs)
Definition base_uint.h:552
STAmount amountFromQuality(std::uint64_t rate)
Definition STAmount.cpp:927
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