rippled
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 <ripple/basics/IOUAmount.h>
24 #include <ripple/basics/XRPAmount.h>
25 #include <ripple/protocol/AmountConversions.h>
26 #include <ripple/protocol/STAmount.h>
27 
28 #include <algorithm>
29 #include <cstdint>
30 #include <ostream>
31 
32 namespace ripple {
33 
43 template <class In, class Out>
44 struct 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 
83 using Amounts = TAmounts<STAmount, STAmount>;
84 
85 template <class In, class Out>
86 bool
87 operator==(TAmounts<In, Out> const& lhs, TAmounts<In, Out> const& rhs) noexcept
88 {
89  return lhs.in == rhs.in && lhs.out == rhs.out;
90 }
91 
92 template <class In, class Out>
93 bool
94 operator!=(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 
109 class Quality
110 {
111 public:
112  // Type of the internal representation. Higher qualities
113  // have lower unsigned integer representations.
114  using value_type = std::uint64_t;
115 
116  static const int minTickSize = 3;
117  static const int maxTickSize = 16;
118 
119 private:
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 
126 public:
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  Amounts
185  ceil_in(Amounts const& amount, STAmount const& limit) const;
186 
187  template <class In, class Out>
188  TAmounts<In, Out>
189  ceil_in(TAmounts<In, Out> const& amount, In const& limit) const
190  {
191  if (amount.in <= limit)
192  return amount;
193 
194  // Use the existing STAmount implementation for now, but consider
195  // replacing with code specific to IOUAMount and XRPAmount
196  Amounts stAmt(toSTAmount(amount.in), toSTAmount(amount.out));
197  STAmount stLim(toSTAmount(limit));
198  auto const stRes = ceil_in(stAmt, stLim);
199  return TAmounts<In, Out>(
200  toAmount<In>(stRes.in), toAmount<Out>(stRes.out));
201  }
202 
207  Amounts
208  ceil_out(Amounts const& amount, STAmount const& limit) const;
209 
210  template <class In, class Out>
211  TAmounts<In, Out>
212  ceil_out(TAmounts<In, Out> const& amount, Out const& limit) const
213  {
214  if (amount.out <= limit)
215  return amount;
216 
217  // Use the existing STAmount implementation for now, but consider
218  // replacing with code specific to IOUAMount and XRPAmount
219  Amounts stAmt(toSTAmount(amount.in), toSTAmount(amount.out));
220  STAmount stLim(toSTAmount(limit));
221  auto const stRes = ceil_out(stAmt, stLim);
222  return TAmounts<In, Out>(
223  toAmount<In>(stRes.in), toAmount<Out>(stRes.out));
224  }
225 
230  friend bool
231  operator<(Quality const& lhs, Quality const& rhs) noexcept
232  {
233  return lhs.m_value > rhs.m_value;
234  }
235 
236  friend bool
237  operator>(Quality const& lhs, Quality const& rhs) noexcept
238  {
239  return lhs.m_value < rhs.m_value;
240  }
241 
242  friend bool
243  operator<=(Quality const& lhs, Quality const& rhs) noexcept
244  {
245  return !(lhs > rhs);
246  }
247 
248  friend bool
249  operator>=(Quality const& lhs, Quality const& rhs) noexcept
250  {
251  return !(lhs < rhs);
252  }
253 
254  friend bool
255  operator==(Quality const& lhs, Quality const& rhs) noexcept
256  {
257  return lhs.m_value == rhs.m_value;
258  }
259 
260  friend bool
261  operator!=(Quality const& lhs, Quality const& rhs) noexcept
262  {
263  return !(lhs == rhs);
264  }
265 
266  friend std::ostream&
267  operator<<(std::ostream& os, Quality const& quality)
268  {
269  os << quality.m_value;
270  return os;
271  }
272 
273  // return the relative distance (relative error) between two qualities. This
274  // is used for testing only. relative distance is abs(a-b)/min(a,b)
275  friend double
276  relativeDistance(Quality const& q1, Quality const& q2)
277  {
278  assert(q1.m_value > 0 && q2.m_value > 0);
279 
280  if (q1.m_value == q2.m_value) // make expected common case fast
281  return 0;
282 
283  auto const [minV, maxV] = std::minmax(q1.m_value, q2.m_value);
284 
285  auto mantissa = [](std::uint64_t rate) {
286  return rate & ~(255ull << (64 - 8));
287  };
288  auto exponent = [](std::uint64_t rate) {
289  return static_cast<int>(rate >> (64 - 8)) - 100;
290  };
291 
292  auto const minVMantissa = mantissa(minV);
293  auto const maxVMantissa = mantissa(maxV);
294  auto const expDiff = exponent(maxV) - exponent(minV);
295 
296  double const minVD = static_cast<double>(minVMantissa);
297  double const maxVD = expDiff ? maxVMantissa * pow(10, expDiff)
298  : static_cast<double>(maxVMantissa);
299 
300  // maxVD and minVD are scaled so they have the same exponents. Dividing
301  // cancels out the exponents, so we only need to deal with the (scaled)
302  // mantissas
303  return (maxVD - minVD) / minVD;
304  }
305 };
306 
311 Quality
312 composed_quality(Quality const& lhs, Quality const& rhs);
313 
314 } // namespace ripple
315 
316 #endif
ripple::composed_quality
Quality composed_quality(Quality const &lhs, Quality const &rhs)
Definition: Quality.cpp:101
ripple::QualityDirection::in
@ in
ripple::operator<<
std::ostream & operator<<(std::ostream &os, TOffer< TIn, TOut > const &offer)
Definition: Offer.h:242
algorithm
ripple::operator==
bool operator==(Manifest const &lhs, Manifest const &rhs)
Definition: Manifest.h:165
ripple::operator<=
bool operator<=(STAmount const &lhs, STAmount const &rhs)
Definition: STAmount.h:475
ripple::QualityDirection::out
@ out
ripple::operator>
bool operator>(STAmount const &lhs, STAmount const &rhs)
Definition: STAmount.h:469
ripple::operator<
bool operator<(CanonicalTXSet::Key const &lhs, CanonicalTXSet::Key const &rhs)
Definition: CanonicalTXSet.cpp:25
std::ostream
STL class.
std::minmax
T minmax(T... args)
ripple::toSTAmount
STAmount toSTAmount(IOUAmount const &iou, Issue const &iss)
Definition: AmountConversions.h:30
ripple::operator!=
bool operator!=(Manifest const &lhs, Manifest const &rhs)
Definition: Manifest.h:175
ripple::operator>=
bool operator>=(STAmount const &lhs, STAmount const &rhs)
Definition: STAmount.h:481
beast::Zero
Zero allows classes to offer efficient comparisons to zero.
Definition: Zero.h:42
cstdint
std::uint64_t
ripple::amountFromQuality
STAmount amountFromQuality(std::uint64_t rate)
Definition: STAmount.cpp:852
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
std::round
T round(T... args)
std::empty
T empty(T... args)
ripple::keylet::quality
Keylet quality(Keylet const &k, std::uint64_t q) noexcept
The initial directory page for a specific quality.
Definition: Indexes.cpp:228
ostream
ripple::test::jtx::rate
Json::Value rate(Account const &account, double multiplier)
Set a transfer rate.
Definition: rate.cpp:30
std::pow
T pow(T... args)
beast
Definition: base_uint.h:641