Bitcoin ABC 0.34.2
P2P Digital Currency
feefrac.h
Go to the documentation of this file.
1// Copyright (c) The Bitcoin Core developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5#ifndef BITCOIN_UTIL_FEEFRAC_H
6#define BITCOIN_UTIL_FEEFRAC_H
7
8#include <util/check.h>
9
10#include <compare>
11#include <cstdint>
12#include <span.h>
13#include <vector>
14
41struct FeeFrac {
47 static inline std::pair<int64_t, uint32_t> MulFallback(int64_t a,
48 int32_t b) noexcept {
49 int64_t low = int64_t{static_cast<uint32_t>(a)} * b;
50 int64_t high = (a >> 32) * b;
51 return {high + (low >> 32), static_cast<uint32_t>(low)};
52 }
53
65 static inline int64_t DivFallback(std::pair<int64_t, uint32_t> n, int32_t d,
66 bool round_down) noexcept {
67 Assume(d > 0);
68 // Compute quot_high = n.first / d, so the result becomes
69 // (n.second + (n.first - quot_high * d) * 2**32) / d +
70 // (quot_high * 2**32), or
71 // (n.second + (n.first % d) * 2**32) / d + (quot_high * 2**32).
72 int64_t quot_high = n.first / d;
73 // Evaluate the parenthesized expression above, so the result becomes
74 // n_low / d + (quot_high * 2**32)
75 int64_t n_low = ((n.first % d) << 32) + n.second;
76 // Evaluate the division so the result becomes
77 // quot_low + quot_high * 2**32. It is possible that the / operator
78 // here rounds in the wrong direction (if n_low is not a multiple of
79 // size, and is (if round_down) negative, or (if !round_down)
80 // positive). If so, make a correction.
81 int64_t quot_low = n_low / d;
82 int32_t mod_low = n_low % d;
83 quot_low += (mod_low > 0) - (mod_low && round_down);
84 // Combine and return the result
85 return (quot_high << 32) + quot_low;
86 }
87
88#ifdef __SIZEOF_INT128__
93 static inline __int128 Mul(int64_t a, int32_t b) noexcept {
94 return __int128{a} * b;
95 }
96
104 static inline int64_t Div(__int128 n, int32_t d, bool round_down) noexcept {
105 Assume(d > 0);
106 // Compute the division.
107 int64_t quot = n / d;
108 int32_t mod = n % d;
109 // Correct result if the / operator above rounded in the wrong
110 // direction.
111 return quot + (mod > 0) - (mod && round_down);
112 }
113#else
114 static constexpr auto Mul = MulFallback;
115 static constexpr auto Div = DivFallback;
116#endif
117
118 int64_t fee;
119 int32_t size;
120
122 inline FeeFrac() noexcept : fee{0}, size{0} {}
123
125 inline FeeFrac(int64_t f, int32_t s) noexcept : fee{f}, size{s} {}
126
127 inline FeeFrac(const FeeFrac &) noexcept = default;
128 inline FeeFrac &operator=(const FeeFrac &) noexcept = default;
129
131 bool inline IsEmpty() const noexcept { return size == 0; }
132
134 void inline operator+=(const FeeFrac &other) noexcept {
135 fee += other.fee;
136 size += other.size;
137 }
138
140 void inline operator-=(const FeeFrac &other) noexcept {
141 fee -= other.fee;
142 size -= other.size;
143 }
144
146 friend inline FeeFrac operator+(const FeeFrac &a,
147 const FeeFrac &b) noexcept {
148 return {a.fee + b.fee, a.size + b.size};
149 }
150
152 friend inline FeeFrac operator-(const FeeFrac &a,
153 const FeeFrac &b) noexcept {
154 return {a.fee - b.fee, a.size - b.size};
155 }
156
158 friend inline bool operator==(const FeeFrac &a, const FeeFrac &b) noexcept {
159 return a.fee == b.fee && a.size == b.size;
160 }
161
163 friend inline std::weak_ordering FeeRateCompare(const FeeFrac &a,
164 const FeeFrac &b) noexcept {
165 auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);
166 return cross_a <=> cross_b;
167 }
168
170 friend inline bool operator<<(const FeeFrac &a, const FeeFrac &b) noexcept {
171 auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);
172 return cross_a < cross_b;
173 }
174
176 friend inline bool operator>>(const FeeFrac &a, const FeeFrac &b) noexcept {
177 auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);
178 return cross_a > cross_b;
179 }
180
182 friend inline std::strong_ordering operator<=>(const FeeFrac &a,
183 const FeeFrac &b) noexcept {
184 auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);
185 if (cross_a == cross_b) return b.size <=> a.size;
186 return cross_a <=> cross_b;
187 }
188
190 friend inline void swap(FeeFrac &a, FeeFrac &b) noexcept {
191 std::swap(a.fee, b.fee);
192 std::swap(a.size, b.size);
193 }
194
207 template <bool RoundDown>
208 int64_t EvaluateFee(int32_t at_size) const noexcept {
209 Assume(size > 0);
210 Assume(at_size >= 0);
211 if (fee >= 0 && fee < 0x200000000) [[likely]] {
212 // Common case where (this->fee * at_size) is guaranteed to fit in a
213 // uint64_t.
214 if constexpr (RoundDown) {
215 return (uint64_t(fee) * at_size) / uint32_t(size);
216 } else {
217 return (uint64_t(fee) * at_size + size - 1U) / uint32_t(size);
218 }
219 } else {
220 // Otherwise, use Mul and Div.
221 return Div(Mul(fee, at_size), size, RoundDown);
222 }
223 }
224
225public:
228 int64_t EvaluateFeeDown(int32_t at_size) const noexcept {
229 return EvaluateFee<true>(at_size);
230 }
233 int64_t EvaluateFeeUp(int32_t at_size) const noexcept {
234 return EvaluateFee<false>(at_size);
235 }
236};
237
242template <typename Tag> struct FeePerUnit : public FeeFrac {
243 // Inherit FeeFrac constructors.
245
247 static FeePerUnit FromFeeFrac(const FeeFrac &feefrac) noexcept {
248 return {feefrac.fee, feefrac.size};
249 }
250};
251
252// FeePerUnit instance for satoshi / vbyte.
253struct VSizeTag {};
255
256#endif // BITCOIN_UTIL_FEEFRAC_H
#define Assume(val)
Assume is the identity function.
Definition: check.h:100
Data structure storing a fee and size, ordered by increasing fee/size.
Definition: feefrac.h:41
friend std::weak_ordering FeeRateCompare(const FeeFrac &a, const FeeFrac &b) noexcept
Compare two FeeFracs just by feerate.
Definition: feefrac.h:163
friend FeeFrac operator-(const FeeFrac &a, const FeeFrac &b) noexcept
Subtract both fee and size.
Definition: feefrac.h:152
friend bool operator>>(const FeeFrac &a, const FeeFrac &b) noexcept
Check if a FeeFrac object has strictly higher feerate than another.
Definition: feefrac.h:176
friend void swap(FeeFrac &a, FeeFrac &b) noexcept
Swap two FeeFracs.
Definition: feefrac.h:190
FeeFrac(const FeeFrac &) noexcept=default
int64_t fee
Definition: feefrac.h:118
int64_t EvaluateFeeDown(int32_t at_size) const noexcept
Compute the fee for a given size at_size using this object's feerate, rounding down.
Definition: feefrac.h:228
int64_t EvaluateFee(int32_t at_size) const noexcept
Compute the fee for a given size at_size using this object's feerate.
Definition: feefrac.h:208
static int64_t DivFallback(std::pair< int64_t, uint32_t > n, int32_t d, bool round_down) noexcept
Helper function for 96/32 signed division, rounding towards negative infinity (if round_down) or posi...
Definition: feefrac.h:65
int64_t EvaluateFeeUp(int32_t at_size) const noexcept
Compute the fee for a given size at_size using this object's feerate, rounding up.
Definition: feefrac.h:233
friend std::strong_ordering operator<=>(const FeeFrac &a, const FeeFrac &b) noexcept
Compare two FeeFracs.
Definition: feefrac.h:182
FeeFrac & operator=(const FeeFrac &) noexcept=default
static constexpr auto Div
Definition: feefrac.h:115
static constexpr auto Mul
Definition: feefrac.h:114
friend bool operator<<(const FeeFrac &a, const FeeFrac &b) noexcept
Check if a FeeFrac object has strictly lower feerate than another.
Definition: feefrac.h:170
FeeFrac() noexcept
Construct an IsEmpty() FeeFrac.
Definition: feefrac.h:122
void operator-=(const FeeFrac &other) noexcept
Subtract fee and size of another FeeFrac from this one.
Definition: feefrac.h:140
int32_t size
Definition: feefrac.h:119
FeeFrac(int64_t f, int32_t s) noexcept
Construct a FeeFrac with specified fee and size.
Definition: feefrac.h:125
void operator+=(const FeeFrac &other) noexcept
Add fee and size of another FeeFrac to this one.
Definition: feefrac.h:134
bool IsEmpty() const noexcept
Check if this is empty (size and fee are 0).
Definition: feefrac.h:131
static std::pair< int64_t, uint32_t > MulFallback(int64_t a, int32_t b) noexcept
Helper function for 32*64 signed multiplication, returning an unspecified but totally ordered type.
Definition: feefrac.h:47
friend FeeFrac operator+(const FeeFrac &a, const FeeFrac &b) noexcept
Sum fee and size.
Definition: feefrac.h:146
friend bool operator==(const FeeFrac &a, const FeeFrac &b) noexcept
Check if two FeeFrac objects are equal (both same fee and same size).
Definition: feefrac.h:158
Tagged wrapper around FeeFrac to avoid unit confusion.
Definition: feefrac.h:242
static FeePerUnit FromFeeFrac(const FeeFrac &feefrac) noexcept
Convert a FeeFrac to a FeePerUnit.
Definition: feefrac.h:247