rippled
Quality.cpp
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 #include <ripple/protocol/Quality.h>
21 #include <cassert>
22 #include <limits>
23 
24 namespace ripple {
25 
26 Quality::Quality(std::uint64_t value) : m_value(value)
27 {
28 }
29 
30 Quality::Quality(Amounts const& amount)
31  : m_value(getRate(amount.out, amount.in))
32 {
33 }
34 
35 Quality&
36 Quality::operator++()
37 {
38  assert(m_value > 0);
39  --m_value;
40  return *this;
41 }
42 
43 Quality
44 Quality::operator++(int)
45 {
46  Quality prev(*this);
47  ++*this;
48  return prev;
49 }
50 
51 Quality&
52 Quality::operator--()
53 {
54  assert(m_value < std::numeric_limits<value_type>::max());
55  ++m_value;
56  return *this;
57 }
58 
59 Quality
60 Quality::operator--(int)
61 {
62  Quality prev(*this);
63  --*this;
64  return prev;
65 }
66 
67 Amounts
68 Quality::ceil_in(Amounts const& amount, STAmount const& limit) const
69 {
70  if (amount.in > limit)
71  {
72  Amounts result(
73  limit, divRound(limit, rate(), amount.out.issue(), true));
74  // Clamp out
75  if (result.out > amount.out)
76  result.out = amount.out;
77  assert(result.in == limit);
78  return result;
79  }
80  assert(amount.in <= limit);
81  return amount;
82 }
83 
84 template <STAmount (
85  *MulRoundFunc)(STAmount const&, STAmount const&, Issue const&, bool)>
86 static Amounts
88  Amounts const& amount,
89  STAmount const& limit,
90  bool roundUp,
91  Quality const& quality)
92 {
93  if (amount.out > limit)
94  {
95  Amounts result(
96  MulRoundFunc(limit, quality.rate(), amount.in.issue(), roundUp),
97  limit);
98  // Clamp in
99  if (result.in > amount.in)
100  result.in = amount.in;
101  assert(result.out == limit);
102  return result;
103  }
104  assert(amount.out <= limit);
105  return amount;
106 }
107 
108 Amounts
109 Quality::ceil_out(Amounts const& amount, STAmount const& limit) const
110 {
111  return ceil_out_impl<mulRound>(amount, limit, /* roundUp */ true, *this);
112 }
113 
114 Amounts
115 Quality::ceil_out_strict(
116  Amounts const& amount,
117  STAmount const& limit,
118  bool roundUp) const
119 {
120  return ceil_out_impl<mulRoundStrict>(amount, limit, roundUp, *this);
121 }
122 
123 Quality
124 composed_quality(Quality const& lhs, Quality const& rhs)
125 {
126  STAmount const lhs_rate(lhs.rate());
127  assert(lhs_rate != beast::zero);
128 
129  STAmount const rhs_rate(rhs.rate());
130  assert(rhs_rate != beast::zero);
131 
132  STAmount const rate(mulRound(lhs_rate, rhs_rate, lhs_rate.issue(), true));
133 
134  std::uint64_t const stored_exponent(rate.exponent() + 100);
135  std::uint64_t const stored_mantissa(rate.mantissa());
136 
137  assert((stored_exponent > 0) && (stored_exponent <= 255));
138 
139  return Quality((stored_exponent << (64 - 8)) | stored_mantissa);
140 }
141 
142 Quality
143 Quality::round(int digits) const
144 {
145  // Modulus for mantissa
146  static const std::uint64_t mod[17] = {
147  /* 0 */ 10000000000000000,
148  /* 1 */ 1000000000000000,
149  /* 2 */ 100000000000000,
150  /* 3 */ 10000000000000,
151  /* 4 */ 1000000000000,
152  /* 5 */ 100000000000,
153  /* 6 */ 10000000000,
154  /* 7 */ 1000000000,
155  /* 8 */ 100000000,
156  /* 9 */ 10000000,
157  /* 10 */ 1000000,
158  /* 11 */ 100000,
159  /* 12 */ 10000,
160  /* 13 */ 1000,
161  /* 14 */ 100,
162  /* 15 */ 10,
163  /* 16 */ 1,
164  };
165 
166  auto exponent = m_value >> (64 - 8);
167  auto mantissa = m_value & 0x00ffffffffffffffULL;
168  mantissa += mod[digits] - 1;
169  mantissa -= (mantissa % mod[digits]);
170 
171  return Quality{(exponent << (64 - 8)) | mantissa};
172 }
173 
174 } // namespace ripple
ripple::composed_quality
Quality composed_quality(Quality const &lhs, Quality const &rhs)
Definition: Quality.cpp:124
ripple::STAmount::issue
Issue const & issue() const
Definition: STAmount.h:350
ripple::QualityDirection::in
@ in
ripple::ceil_out_impl
static Amounts ceil_out_impl(Amounts const &amount, STAmount const &limit, bool roundUp, Quality const &quality)
Definition: Quality.cpp:87
ripple::mulRound
STAmount mulRound(STAmount const &v1, STAmount const &v2, Issue const &issue, bool roundUp)
Definition: STAmount.cpp:1508
ripple::getRate
std::uint64_t getRate(STAmount const &offerOut, STAmount const &offerIn)
Definition: STAmount.cpp:506
ripple::QualityDirection::out
@ out
ripple::divRound
STAmount divRound(STAmount const &num, STAmount const &den, Issue const &issue, bool roundUp)
Definition: STAmount.cpp:1614
ripple::STAmount
Definition: STAmount.h:46
std::uint64_t
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
limits
cassert
std::prev
T prev(T... args)
std::numeric_limits
ripple::test::jtx::rate
Json::Value rate(Account const &account, double multiplier)
Set a transfer rate.
Definition: rate.cpp:30