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 alway 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  Quality(Out const& out, In const& in)
138  : Quality(Amounts(toSTAmount(in), toSTAmount(out)))
139  {
140  }
141 
144  Quality&
145  operator++();
146 
147  Quality
148  operator++(int);
153  Quality&
154  operator--();
155 
156  Quality
157  operator--(int);
161  STAmount
162  rate() const
163  {
164  return amountFromQuality(m_value);
165  }
166 
170  Quality
171  round(int tickSize) const;
172 
177  Amounts
178  ceil_in(Amounts const& amount, STAmount const& limit) const;
179 
180  template <class In, class Out>
181  TAmounts<In, Out>
182  ceil_in(TAmounts<In, Out> const& amount, In const& limit) const
183  {
184  if (amount.in <= limit)
185  return amount;
186 
187  // Use the existing STAmount implementation for now, but consider
188  // replacing with code specific to IOUAMount and XRPAmount
189  Amounts stAmt(toSTAmount(amount.in), toSTAmount(amount.out));
190  STAmount stLim(toSTAmount(limit));
191  auto const stRes = ceil_in(stAmt, stLim);
192  return TAmounts<In, Out>(
193  toAmount<In>(stRes.in), toAmount<Out>(stRes.out));
194  }
195 
200  Amounts
201  ceil_out(Amounts const& amount, STAmount const& limit) const;
202 
203  template <class In, class Out>
204  TAmounts<In, Out>
205  ceil_out(TAmounts<In, Out> const& amount, Out const& limit) const
206  {
207  if (amount.out <= limit)
208  return amount;
209 
210  // Use the existing STAmount implementation for now, but consider
211  // replacing with code specific to IOUAMount and XRPAmount
212  Amounts stAmt(toSTAmount(amount.in), toSTAmount(amount.out));
213  STAmount stLim(toSTAmount(limit));
214  auto const stRes = ceil_out(stAmt, stLim);
215  return TAmounts<In, Out>(
216  toAmount<In>(stRes.in), toAmount<Out>(stRes.out));
217  }
218 
223  friend bool
224  operator<(Quality const& lhs, Quality const& rhs) noexcept
225  {
226  return lhs.m_value > rhs.m_value;
227  }
228 
229  friend bool
230  operator>(Quality const& lhs, Quality const& rhs) noexcept
231  {
232  return lhs.m_value < rhs.m_value;
233  }
234 
235  friend bool
236  operator<=(Quality const& lhs, Quality const& rhs) noexcept
237  {
238  return !(lhs > rhs);
239  }
240 
241  friend bool
242  operator>=(Quality const& lhs, Quality const& rhs) noexcept
243  {
244  return !(lhs < rhs);
245  }
246 
247  friend bool
248  operator==(Quality const& lhs, Quality const& rhs) noexcept
249  {
250  return lhs.m_value == rhs.m_value;
251  }
252 
253  friend bool
254  operator!=(Quality const& lhs, Quality const& rhs) noexcept
255  {
256  return !(lhs == rhs);
257  }
258 
259  friend std::ostream&
260  operator<<(std::ostream& os, Quality const& quality)
261  {
262  os << quality.m_value;
263  return os;
264  }
265 
266  // return the relative distance (relative error) between two qualities. This
267  // is used for testing only. relative distance is abs(a-b)/min(a,b)
268  friend double
269  relativeDistance(Quality const& q1, Quality const& q2)
270  {
271  assert(q1.m_value > 0 && q2.m_value > 0);
272 
273  if (q1.m_value == q2.m_value) // make expected common case fast
274  return 0;
275 
276  auto const [minV, maxV] = std::minmax(q1.m_value, q2.m_value);
277 
278  auto mantissa = [](std::uint64_t rate) {
279  return rate & ~(255ull << (64 - 8));
280  };
281  auto exponent = [](std::uint64_t rate) {
282  return static_cast<int>(rate >> (64 - 8)) - 100;
283  };
284 
285  auto const minVMantissa = mantissa(minV);
286  auto const maxVMantissa = mantissa(maxV);
287  auto const expDiff = exponent(maxV) - exponent(minV);
288 
289  double const minVD = static_cast<double>(minVMantissa);
290  double const maxVD = expDiff ? maxVMantissa * pow(10, expDiff)
291  : static_cast<double>(maxVMantissa);
292 
293  // maxVD and minVD are scaled so they have the same exponents. Dividing
294  // cancels out the exponents, so we only need to deal with the (scaled)
295  // mantissas
296  return (maxVD - minVD) / minVD;
297  }
298 };
299 
304 Quality
305 composed_quality(Quality const& lhs, Quality const& rhs);
306 
307 } // namespace ripple
308 
309 #endif
ripple::operator>
bool operator>(base_uint< Bits, Tag > const &a, base_uint< Bits, Tag > const &b)
Definition: base_uint.h:492
ripple::composed_quality
Quality composed_quality(Quality const &lhs, Quality const &rhs)
Definition: Quality.cpp:101
ripple::operator>=
bool operator>=(base_uint< Bits, Tag > const &a, base_uint< Bits, Tag > const &b)
Definition: base_uint.h:499
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:155
ripple::operator<=
bool operator<=(base_uint< Bits, Tag > const &a, base_uint< Bits, Tag > const &b)
Definition: base_uint.h:485
ripple::QualityDirection::out
@ out
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:165
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:749
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:229
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:585