rippled
Loading...
Searching...
No Matches
Quality.h
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012, 2013 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
20#ifndef RIPPLE_PROTOCOL_QUALITY_H_INCLUDED
21#define RIPPLE_PROTOCOL_QUALITY_H_INCLUDED
22
23#include <xrpl/protocol/AmountConversions.h>
24#include <xrpl/protocol/IOUAmount.h>
25#include <xrpl/protocol/STAmount.h>
26#include <xrpl/protocol/XRPAmount.h>
27
28#include <algorithm>
29#include <cstdint>
30#include <ostream>
31
32namespace ripple {
33
43template <class In, class Out>
44struct TAmounts
45{
46 TAmounts() = default;
47
48 TAmounts(beast::Zero, beast::Zero) : in(beast::zero), out(beast::zero)
49 {
50 }
51
52 TAmounts(In const& in_, Out const& out_) : in(in_), out(out_)
53 {
54 }
55
57 bool
58 empty() const noexcept
59 {
60 return in <= beast::zero || out <= beast::zero;
61 }
62
63 TAmounts&
64 operator+=(TAmounts const& rhs)
65 {
66 in += rhs.in;
67 out += rhs.out;
68 return *this;
69 }
70
71 TAmounts&
72 operator-=(TAmounts const& rhs)
73 {
74 in -= rhs.in;
75 out -= rhs.out;
76 return *this;
77 }
78
79 In in;
80 Out out;
81};
82
83using Amounts = TAmounts<STAmount, STAmount>;
84
85template <class In, class Out>
86bool
87operator==(TAmounts<In, Out> const& lhs, TAmounts<In, Out> const& rhs) noexcept
88{
89 return lhs.in == rhs.in && lhs.out == rhs.out;
90}
91
92template <class In, class Out>
93bool
94operator!=(TAmounts<In, Out> const& lhs, TAmounts<In, Out> const& rhs) noexcept
95{
96 return !(lhs == rhs);
97}
98
99//------------------------------------------------------------------------------
100
101// Ripple specific constant used for parsing qualities and other things
102#define QUALITY_ONE 1'000'000'000
103
109class Quality
110{
111public:
112 // Type of the internal representation. Higher qualities
113 // have lower unsigned integer representations.
114 using value_type = std::uint64_t;
115
116 static int const minTickSize = 3;
117 static int const maxTickSize = 16;
118
119private:
120 // This has the same representation as STAmount, see the comment on the
121 // STAmount. However, this class does not always use the canonical
122 // representation. In particular, the increment and decrement operators may
123 // cause a non-canonical representation.
124 value_type m_value;
125
126public:
127 Quality() = default;
128
130 explicit Quality(std::uint64_t value);
131
133 explicit Quality(Amounts const& amount);
134
136 template <class In, class Out>
137 explicit Quality(TAmounts<In, Out> const& amount)
138 : Quality(Amounts(toSTAmount(amount.in), toSTAmount(amount.out)))
139 {
140 }
141
143 template <class In, class Out>
144 Quality(Out const& out, In const& in)
145 : Quality(Amounts(toSTAmount(in), toSTAmount(out)))
146 {
147 }
148
151 Quality&
152 operator++();
153
154 Quality
155 operator++(int);
160 Quality&
161 operator--();
162
163 Quality
164 operator--(int);
168 STAmount
169 rate() const
170 {
171 return amountFromQuality(m_value);
172 }
173
177 Quality
178 round(int tickSize) const;
179
184 [[nodiscard]] Amounts
185 ceil_in(Amounts const& amount, STAmount const& limit) const;
186
187 template <class In, class Out>
188 [[nodiscard]] TAmounts<In, Out>
189 ceil_in(TAmounts<In, Out> const& amount, In const& limit) const;
190
191 // Some of the underlying rounding functions called by ceil_in() 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_in_strict(Amounts const& amount, STAmount const& limit, bool roundUp)
196 const;
197
198 template <class In, class Out>
199 [[nodiscard]] TAmounts<In, Out>
200 ceil_in_strict(
201 TAmounts<In, Out> const& amount,
202 In const& limit,
203 bool roundUp) const;
204
209 [[nodiscard]] Amounts
210 ceil_out(Amounts const& amount, STAmount const& limit) const;
211
212 template <class In, class Out>
213 [[nodiscard]] TAmounts<In, Out>
214 ceil_out(TAmounts<In, Out> const& amount, Out const& limit) const;
215
216 // Some of the underlying rounding functions called by ceil_out() ignored
217 // low order bits that could influence rounding decisions. This "strict"
218 // method uses underlying functions that pay attention to all the bits.
219 [[nodiscard]] Amounts
220 ceil_out_strict(Amounts const& amount, STAmount const& limit, bool roundUp)
221 const;
222
223 template <class In, class Out>
224 [[nodiscard]] TAmounts<In, Out>
225 ceil_out_strict(
226 TAmounts<In, Out> const& amount,
227 Out const& limit,
228 bool roundUp) const;
229
230private:
231 // The ceil_in and ceil_out methods that deal in TAmount all convert
232 // their arguments to STAoumout and convert the result back to TAmount.
233 // This helper function takes care of all the conversion operations.
234 template <
235 class In,
236 class Out,
237 class Lim,
238 typename FnPtr,
239 std::same_as<bool>... Round>
240 [[nodiscard]] TAmounts<In, Out>
241 ceil_TAmounts_helper(
242 TAmounts<In, Out> const& amount,
243 Lim const& limit,
244 Lim const& limit_cmp,
245 FnPtr ceil_function,
246 Round... round) const;
247
248public:
253 friend bool
254 operator<(Quality const& lhs, Quality const& rhs) noexcept
255 {
256 return lhs.m_value > rhs.m_value;
257 }
258
259 friend bool
260 operator>(Quality const& lhs, Quality const& rhs) noexcept
261 {
262 return lhs.m_value < rhs.m_value;
263 }
264
265 friend bool
266 operator<=(Quality const& lhs, Quality const& rhs) noexcept
267 {
268 return !(lhs > rhs);
269 }
270
271 friend bool
272 operator>=(Quality const& lhs, Quality const& rhs) noexcept
273 {
274 return !(lhs < rhs);
275 }
276
277 friend bool
278 operator==(Quality const& lhs, Quality const& rhs) noexcept
279 {
280 return lhs.m_value == rhs.m_value;
281 }
282
283 friend bool
284 operator!=(Quality const& lhs, Quality const& rhs) noexcept
285 {
286 return !(lhs == rhs);
287 }
288
289 friend std::ostream&
290 operator<<(std::ostream& os, Quality const& quality)
291 {
292 os << quality.m_value;
293 return os;
294 }
295
296 // return the relative distance (relative error) between two qualities. This
297 // is used for testing only. relative distance is abs(a-b)/min(a,b)
298 friend double
299 relativeDistance(Quality const& q1, Quality const& q2)
300 {
301 XRPL_ASSERT(
302 q1.m_value > 0 && q2.m_value > 0,
303 "ripple::Quality::relativeDistance : minimum inputs");
304
305 if (q1.m_value == q2.m_value) // make expected common case fast
306 return 0;
307
308 auto const [minV, maxV] = std::minmax(q1.m_value, q2.m_value);
309
310 auto mantissa = [](std::uint64_t rate) {
311 return rate & ~(255ull << (64 - 8));
312 };
313 auto exponent = [](std::uint64_t rate) {
314 return static_cast<int>(rate >> (64 - 8)) - 100;
315 };
316
317 auto const minVMantissa = mantissa(minV);
318 auto const maxVMantissa = mantissa(maxV);
319 auto const expDiff = exponent(maxV) - exponent(minV);
320
321 double const minVD = static_cast<double>(minVMantissa);
322 double const maxVD = expDiff ? maxVMantissa * pow(10, expDiff)
323 : static_cast<double>(maxVMantissa);
324
325 // maxVD and minVD are scaled so they have the same exponents. Dividing
326 // cancels out the exponents, so we only need to deal with the (scaled)
327 // mantissas
328 return (maxVD - minVD) / minVD;
329 }
330};
331
332template <
333 class In,
334 class Out,
335 class Lim,
336 typename FnPtr,
337 std::same_as<bool>... Round>
338TAmounts<In, Out>
339Quality::ceil_TAmounts_helper(
340 TAmounts<In, Out> const& amount,
341 Lim const& limit,
342 Lim const& limit_cmp,
343 FnPtr ceil_function,
344 Round... roundUp) const
345{
346 if (limit_cmp <= limit)
347 return amount;
348
349 // Use the existing STAmount implementation for now, but consider
350 // replacing with code specific to IOUAMount and XRPAmount
351 Amounts stAmt(toSTAmount(amount.in), toSTAmount(amount.out));
352 STAmount stLim(toSTAmount(limit));
353 Amounts const stRes = ((*this).*ceil_function)(stAmt, stLim, roundUp...);
354 return TAmounts<In, Out>(toAmount<In>(stRes.in), toAmount<Out>(stRes.out));
355}
356
357template <class In, class Out>
358TAmounts<In, Out>
359Quality::ceil_in(TAmounts<In, Out> const& amount, In const& limit) const
360{
361 // Construct a function pointer to the function we want to call.
362 static constexpr Amounts (Quality::*ceil_in_fn_ptr)(
363 Amounts const&, STAmount const&) const = &Quality::ceil_in;
364
365 return ceil_TAmounts_helper(amount, limit, amount.in, ceil_in_fn_ptr);
366}
367
368template <class In, class Out>
369TAmounts<In, Out>
370Quality::ceil_in_strict(
371 TAmounts<In, Out> const& amount,
372 In const& limit,
373 bool roundUp) const
374{
375 // Construct a function pointer to the function we want to call.
376 static constexpr Amounts (Quality::*ceil_in_fn_ptr)(
377 Amounts const&, STAmount const&, bool) const = &Quality::ceil_in_strict;
378
379 return ceil_TAmounts_helper(
380 amount, limit, amount.in, ceil_in_fn_ptr, roundUp);
381}
382
383template <class In, class Out>
384TAmounts<In, Out>
385Quality::ceil_out(TAmounts<In, Out> const& amount, Out const& limit) const
386{
387 // Construct a function pointer to the function we want to call.
388 static constexpr Amounts (Quality::*ceil_out_fn_ptr)(
389 Amounts const&, STAmount const&) const = &Quality::ceil_out;
390
391 return ceil_TAmounts_helper(amount, limit, amount.out, ceil_out_fn_ptr);
392}
393
394template <class In, class Out>
395TAmounts<In, Out>
396Quality::ceil_out_strict(
397 TAmounts<In, Out> const& amount,
398 Out const& limit,
399 bool roundUp) const
400{
401 // Construct a function pointer to the function we want to call.
402 static constexpr Amounts (Quality::*ceil_out_fn_ptr)(
403 Amounts const&, STAmount const&, bool) const =
404 &Quality::ceil_out_strict;
405
406 return ceil_TAmounts_helper(
407 amount, limit, amount.out, ceil_out_fn_ptr, roundUp);
408}
409
414Quality
415composed_quality(Quality const& lhs, Quality const& rhs);
416
417} // namespace ripple
418
419#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:280
Rate rate(Env &env, Account const &account, std::uint32_t const &seq)
Definition escrow.cpp:69
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:25
bool operator!=(Buffer const &lhs, Buffer const &rhs) noexcept
Definition Buffer.h:232
STAmount toSTAmount(IOUAmount const &iou, Issue const &iss)
STAmount amountFromQuality(std::uint64_t rate)
std::ostream & operator<<(std::ostream &out, base_uint< Bits, Tag > const &u)
Definition base_uint.h:647
Quality composed_quality(Quality const &lhs, Quality const &rhs)
Definition Quality.cpp:158
bool operator<(Slice const &lhs, Slice const &rhs) noexcept
Definition Slice.h:223
constexpr bool operator==(base_uint< Bits, Tag > const &lhs, base_uint< Bits, Tag > const &rhs)
Definition base_uint.h:585
T operator>(T... args)
T pow(T... args)
T round(T... args)
Zero allows classes to offer efficient comparisons to zero.
Definition Zero.h:43