mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-04-17 02:57:33 +02:00
Merge bitcoin/bitcoin#34436: refactor: add overflow-safe CeilDiv helper and use it in unsigned callsites
02d047fd5brefactor: add overflow-safe `CeilDiv` helper (Lőrinc) Pull request description: ### Problem The codebase has many open-coded ceiling-division expressions (for example `(x+y-1)/y`) scattered across files. These are less readable, duplicate logic, and can be overflow-prone in edge cases. ### Fix Introduce a small overflow-safe integer helper, `CeilDiv()`, and use it in existing **unsigned** callsites where the conversion is straightforward and noise-free. ### What this PR does * Adds `CeilDiv()` to `src/util/overflow.h` for unsigned integral inputs. * Keeps the precondition check `assert(divisor > 0)`. * Replaces selected unsigned ceiling-division expressions with `CeilDiv(...)`. * Adds focused unit tests in `src/test/util_tests.cpp` for the migrated patterns. --- This is a pure refactor with no intended behavioral change. Signed arithmetic callsites are intentionally left unchanged in this PR. This PR changed a few more things originally but based on feedback reverted to the simplest cases only. ACKs for top commit: rustaceanrob: ACK02d047fd5bhodlinator: ACK02d047fd5bsedited: ACK02d047fd5bTree-SHA512: b09336031f487e6ce289822e0ffeb8cfc8cfe8a2f4f3f49470748dfbd0a6cbab97498674cb8686dd2bd4ab6dd0b79cfdf2da00041fee12d109892e1bc5dde0ff
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
#include <tuple>
|
||||
#include <util/overflow.h>
|
||||
|
||||
/** Class that mimics std::deque<bool>, but with std::vector<bool>'s bit packing.
|
||||
*
|
||||
@@ -211,7 +212,7 @@ public:
|
||||
void assign(size_type count, bool val)
|
||||
{
|
||||
m_deque.clear();
|
||||
m_deque.resize((count + BITS_PER_WORD - 1) / BITS_PER_WORD);
|
||||
m_deque.resize(CeilDiv(count, size_type{BITS_PER_WORD}));
|
||||
m_pad_begin = 0;
|
||||
m_pad_end = 0;
|
||||
if (val) {
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#define BITCOIN_UTIL_BITSET_H
|
||||
|
||||
#include <util/check.h>
|
||||
#include <util/overflow.h>
|
||||
|
||||
#include <array>
|
||||
#include <bit>
|
||||
@@ -522,6 +523,6 @@ public:
|
||||
template<unsigned BITS>
|
||||
using BitSet = std::conditional_t<(BITS <= 32), bitset_detail::IntBitSet<uint32_t>,
|
||||
std::conditional_t<(BITS <= std::numeric_limits<size_t>::digits), bitset_detail::IntBitSet<size_t>,
|
||||
bitset_detail::MultiIntBitSet<size_t, (BITS + std::numeric_limits<size_t>::digits - 1) / std::numeric_limits<size_t>::digits>>>;
|
||||
bitset_detail::MultiIntBitSet<size_t, CeilDiv(BITS, size_t{std::numeric_limits<size_t>::digits})>>>;
|
||||
|
||||
#endif // BITCOIN_UTIL_BITSET_H
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include <span.h>
|
||||
#include <util/check.h>
|
||||
#include <util/overflow.h>
|
||||
|
||||
#include <compare>
|
||||
#include <cstdint>
|
||||
@@ -208,7 +209,7 @@ struct FeeFrac
|
||||
if constexpr (RoundDown) {
|
||||
return (uint64_t(fee) * at_size) / uint32_t(size);
|
||||
} else {
|
||||
return (uint64_t(fee) * at_size + size - 1U) / uint32_t(size);
|
||||
return CeilDiv(uint64_t(fee) * at_size, uint32_t(size));
|
||||
}
|
||||
} else {
|
||||
// Otherwise, use Mul and Div.
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#ifndef BITCOIN_UTIL_OVERFLOW_H
|
||||
#define BITCOIN_UTIL_OVERFLOW_H
|
||||
|
||||
#include <cassert>
|
||||
#include <climits>
|
||||
#include <concepts>
|
||||
#include <limits>
|
||||
@@ -57,6 +58,21 @@ template <class T>
|
||||
return i + j;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Integer ceiling division (for unsigned values).
|
||||
*
|
||||
* Computes the smallest integer q such that q * divisor >= dividend.
|
||||
* Both dividend and divisor must be unsigned, and divisor must be non-zero.
|
||||
*
|
||||
* The implementation avoids overflow that can occur with `(dividend + divisor - 1) / divisor`.
|
||||
*/
|
||||
template <std::unsigned_integral Dividend, std::unsigned_integral Divisor>
|
||||
[[nodiscard]] constexpr auto CeilDiv(const Dividend dividend, const Divisor divisor)
|
||||
{
|
||||
assert(divisor > 0);
|
||||
return dividend / divisor + (dividend % divisor != 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Left bit shift with overflow checking.
|
||||
* @param input The input value to be left shifted.
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include <crypto/hex_base.h>
|
||||
#include <span.h>
|
||||
#include <util/overflow.h>
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
@@ -100,7 +101,7 @@ std::string EncodeBase64(std::span<const unsigned char> input)
|
||||
static const char *pbase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
std::string str;
|
||||
str.reserve(((input.size() + 2) / 3) * 4);
|
||||
str.reserve(CeilDiv(input.size(), 3u) * 4);
|
||||
ConvertBits<8, 6, true>([&](int v) { str += pbase64[v]; }, input.begin(), input.end());
|
||||
while (str.size() % 4) str += '=';
|
||||
return str;
|
||||
@@ -146,7 +147,7 @@ std::string EncodeBase32(std::span<const unsigned char> input, bool pad)
|
||||
static const char *pbase32 = "abcdefghijklmnopqrstuvwxyz234567";
|
||||
|
||||
std::string str;
|
||||
str.reserve(((input.size() + 4) / 5) * 8);
|
||||
str.reserve(CeilDiv(input.size(), 5u) * 8);
|
||||
ConvertBits<8, 5, true>([&](int v) { str += pbase32[v]; }, input.begin(), input.end());
|
||||
if (pad) {
|
||||
while (str.size() % 8) {
|
||||
|
||||
Reference in New Issue
Block a user