/tmp/bitcoin/src/util/overflow.h
Line | Count | Source |
1 | | // Copyright (c) 2021-present 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_OVERFLOW_H |
6 | | #define BITCOIN_UTIL_OVERFLOW_H |
7 | | |
8 | | #include <util/check.h> |
9 | | |
10 | | #include <climits> |
11 | | #include <concepts> |
12 | | #include <limits> |
13 | | #include <optional> |
14 | | #include <type_traits> |
15 | | |
16 | | template <class T> |
17 | | [[nodiscard]] bool AdditionOverflow(const T i, const T j) noexcept |
18 | 12.3M | { |
19 | 12.3M | static_assert(std::is_integral_v<T>, "Integral required."); |
20 | 12.3M | if constexpr (std::numeric_limits<T>::is_signed) { |
21 | 17.9k | return (i > 0 && j > std::numeric_limits<T>::max() - i) || |
22 | 17.9k | (i < 0 && j < std::numeric_limits<T>::min() - i); |
23 | 17.9k | } |
24 | 0 | return std::numeric_limits<T>::max() - i < j; |
25 | 12.3M | } bool AdditionOverflow<unsigned long>(unsigned long, unsigned long) Line | Count | Source | 18 | 12.3M | { | 19 | 12.3M | static_assert(std::is_integral_v<T>, "Integral required."); | 20 | | if constexpr (std::numeric_limits<T>::is_signed) { | 21 | | return (i > 0 && j > std::numeric_limits<T>::max() - i) || | 22 | | (i < 0 && j < std::numeric_limits<T>::min() - i); | 23 | | } | 24 | 12.3M | return std::numeric_limits<T>::max() - i < j; | 25 | 12.3M | } |
bool AdditionOverflow<unsigned int>(unsigned int, unsigned int) Line | Count | Source | 18 | 12 | { | 19 | 12 | static_assert(std::is_integral_v<T>, "Integral required."); | 20 | | if constexpr (std::numeric_limits<T>::is_signed) { | 21 | | return (i > 0 && j > std::numeric_limits<T>::max() - i) || | 22 | | (i < 0 && j < std::numeric_limits<T>::min() - i); | 23 | | } | 24 | 12 | return std::numeric_limits<T>::max() - i < j; | 25 | 12 | } |
bool AdditionOverflow<int>(int, int) Line | Count | Source | 18 | 24 | { | 19 | 24 | static_assert(std::is_integral_v<T>, "Integral required."); | 20 | 24 | if constexpr (std::numeric_limits<T>::is_signed) { | 21 | 24 | return (i > 0 && j > std::numeric_limits<T>::max() - i) || | 22 | 24 | (i < 0 && j < std::numeric_limits<T>::min() - i); | 23 | 24 | } | 24 | 0 | return std::numeric_limits<T>::max() - i < j; | 25 | 24 | } |
bool AdditionOverflow<long>(long, long) Line | Count | Source | 18 | 17.9k | { | 19 | 17.9k | static_assert(std::is_integral_v<T>, "Integral required."); | 20 | 17.9k | if constexpr (std::numeric_limits<T>::is_signed) { | 21 | 17.9k | return (i > 0 && j > std::numeric_limits<T>::max() - i) || | 22 | 17.9k | (i < 0 && j < std::numeric_limits<T>::min() - i); | 23 | 17.9k | } | 24 | 0 | return std::numeric_limits<T>::max() - i < j; | 25 | 17.9k | } |
|
26 | | |
27 | | template <class T> |
28 | | [[nodiscard]] std::optional<T> CheckedAdd(const T i, const T j) noexcept |
29 | 12.3M | { |
30 | 12.3M | if (AdditionOverflow(i, j)) { |
31 | 12 | return std::nullopt; |
32 | 12 | } |
33 | 12.3M | return i + j; |
34 | 12.3M | } std::optional<unsigned long> CheckedAdd<unsigned long>(unsigned long, unsigned long) Line | Count | Source | 29 | 12.3M | { | 30 | 12.3M | if (AdditionOverflow(i, j)) { | 31 | 0 | return std::nullopt; | 32 | 0 | } | 33 | 12.3M | return i + j; | 34 | 12.3M | } |
std::optional<unsigned int> CheckedAdd<unsigned int>(unsigned int, unsigned int) Line | Count | Source | 29 | 12 | { | 30 | 12 | if (AdditionOverflow(i, j)) { | 31 | 4 | return std::nullopt; | 32 | 4 | } | 33 | 8 | return i + j; | 34 | 12 | } |
std::optional<int> CheckedAdd<int>(int, int) Line | Count | Source | 29 | 24 | { | 30 | 24 | if (AdditionOverflow(i, j)) { | 31 | 8 | return std::nullopt; | 32 | 8 | } | 33 | 16 | return i + j; | 34 | 24 | } |
std::optional<long> CheckedAdd<long>(long, long) Line | Count | Source | 29 | 17.9k | { | 30 | 17.9k | if (AdditionOverflow(i, j)) { | 31 | 0 | return std::nullopt; | 32 | 0 | } | 33 | 17.9k | return i + j; | 34 | 17.9k | } |
|
35 | | |
36 | | template <std::unsigned_integral T, std::unsigned_integral U> |
37 | | [[nodiscard]] constexpr bool TrySub(T& i, const U j) noexcept |
38 | 28.9M | { |
39 | 28.9M | if (i < T{j}) return false; |
40 | 28.9M | i -= T{j}; |
41 | 28.9M | return true; |
42 | 28.9M | } bool TrySub<unsigned long, bool>(unsigned long&, bool) Line | Count | Source | 38 | 14.8M | { | 39 | 14.8M | if (i < T{j}) return false; | 40 | 14.8M | i -= T{j}; | 41 | 14.8M | return true; | 42 | 14.8M | } |
bool TrySub<unsigned long, unsigned long>(unsigned long&, unsigned long) Line | Count | Source | 38 | 14.0M | { | 39 | 14.0M | if (i < T{j}) return false; | 40 | 14.0M | i -= T{j}; | 41 | 14.0M | return true; | 42 | 14.0M | } |
|
43 | | |
44 | | template <class T> |
45 | | [[nodiscard]] T SaturatingAdd(const T i, const T j) noexcept |
46 | 1.14k | { |
47 | 1.14k | if constexpr (std::numeric_limits<T>::is_signed) { |
48 | 1.09k | if (i > 0 && j > std::numeric_limits<T>::max() - i) { |
49 | 4 | return std::numeric_limits<T>::max(); |
50 | 4 | } |
51 | 1.09k | if (i < 0 && j < std::numeric_limits<T>::min() - i) { |
52 | 4 | return std::numeric_limits<T>::min(); |
53 | 4 | } |
54 | 1.09k | } else { |
55 | 44 | if (std::numeric_limits<T>::max() - i < j) { |
56 | 6 | return std::numeric_limits<T>::max(); |
57 | 6 | } |
58 | 44 | } |
59 | 1.12k | return i + j; |
60 | 1.14k | } long SaturatingAdd<long>(long, long) Line | Count | Source | 46 | 1.07k | { | 47 | 1.07k | if constexpr (std::numeric_limits<T>::is_signed) { | 48 | 1.07k | if (i > 0 && j > std::numeric_limits<T>::max() - i) { | 49 | 0 | return std::numeric_limits<T>::max(); | 50 | 0 | } | 51 | 1.07k | if (i < 0 && j < std::numeric_limits<T>::min() - i) { | 52 | 0 | return std::numeric_limits<T>::min(); | 53 | 0 | } | 54 | | } else { | 55 | | if (std::numeric_limits<T>::max() - i < j) { | 56 | | return std::numeric_limits<T>::max(); | 57 | | } | 58 | | } | 59 | 1.07k | return i + j; | 60 | 1.07k | } |
unsigned int SaturatingAdd<unsigned int>(unsigned int, unsigned int) Line | Count | Source | 46 | 12 | { | 47 | | if constexpr (std::numeric_limits<T>::is_signed) { | 48 | | if (i > 0 && j > std::numeric_limits<T>::max() - i) { | 49 | | return std::numeric_limits<T>::max(); | 50 | | } | 51 | | if (i < 0 && j < std::numeric_limits<T>::min() - i) { | 52 | | return std::numeric_limits<T>::min(); | 53 | | } | 54 | 12 | } else { | 55 | 12 | if (std::numeric_limits<T>::max() - i < j) { | 56 | 4 | return std::numeric_limits<T>::max(); | 57 | 4 | } | 58 | 12 | } | 59 | 8 | return i + j; | 60 | 12 | } |
int SaturatingAdd<int>(int, int) Line | Count | Source | 46 | 24 | { | 47 | 24 | if constexpr (std::numeric_limits<T>::is_signed) { | 48 | 24 | if (i > 0 && j > std::numeric_limits<T>::max() - i) { | 49 | 4 | return std::numeric_limits<T>::max(); | 50 | 4 | } | 51 | 20 | if (i < 0 && j < std::numeric_limits<T>::min() - i) { | 52 | 4 | return std::numeric_limits<T>::min(); | 53 | 4 | } | 54 | | } else { | 55 | | if (std::numeric_limits<T>::max() - i < j) { | 56 | | return std::numeric_limits<T>::max(); | 57 | | } | 58 | | } | 59 | 16 | return i + j; | 60 | 24 | } |
unsigned long SaturatingAdd<unsigned long>(unsigned long, unsigned long) Line | Count | Source | 46 | 32 | { | 47 | | if constexpr (std::numeric_limits<T>::is_signed) { | 48 | | if (i > 0 && j > std::numeric_limits<T>::max() - i) { | 49 | | return std::numeric_limits<T>::max(); | 50 | | } | 51 | | if (i < 0 && j < std::numeric_limits<T>::min() - i) { | 52 | | return std::numeric_limits<T>::min(); | 53 | | } | 54 | 32 | } else { | 55 | 32 | if (std::numeric_limits<T>::max() - i < j) { | 56 | 2 | return std::numeric_limits<T>::max(); | 57 | 2 | } | 58 | 32 | } | 59 | 30 | return i + j; | 60 | 32 | } |
|
61 | | |
62 | | /** |
63 | | * @brief Integer ceiling division (for unsigned values). |
64 | | * |
65 | | * Computes the smallest integer q such that q * divisor >= dividend. |
66 | | * Both dividend and divisor must be unsigned, and divisor must be non-zero. |
67 | | * |
68 | | * The implementation avoids overflow that can occur with `(dividend + divisor - 1) / divisor`. |
69 | | */ |
70 | | template <std::unsigned_integral Dividend, std::unsigned_integral Divisor> |
71 | | [[nodiscard]] constexpr auto CeilDiv(const Dividend dividend, const Divisor divisor) |
72 | 136M | { |
73 | 136M | assert(divisor > 0); |
74 | 136M | return dividend / divisor + (dividend % divisor != 0); |
75 | 136M | } auto CeilDiv<unsigned long, unsigned int>(unsigned long, unsigned int) Line | Count | Source | 72 | 1.86M | { | 73 | 1.86M | assert(divisor > 0); | 74 | 1.86M | return dividend / divisor + (dividend % divisor != 0); | 75 | 1.86M | } |
auto CeilDiv<unsigned long, unsigned long>(unsigned long, unsigned long) Line | Count | Source | 72 | 134M | { | 73 | 134M | assert(divisor > 0); | 74 | 134M | return dividend / divisor + (dividend % divisor != 0); | 75 | 134M | } |
auto CeilDiv<unsigned int, unsigned int>(unsigned int, unsigned int) Line | Count | Source | 72 | 271k | { | 73 | 271k | assert(divisor > 0); | 74 | 271k | return dividend / divisor + (dividend % divisor != 0); | 75 | 271k | } |
auto CeilDiv<unsigned int, unsigned long>(unsigned int, unsigned long) Line | Count | Source | 72 | 214k | { | 73 | 214k | assert(divisor > 0); | 74 | 214k | return dividend / divisor + (dividend % divisor != 0); | 75 | 214k | } |
|
76 | | |
77 | | /** |
78 | | * @brief Left bit shift with overflow checking. |
79 | | * @param input The input value to be left shifted. |
80 | | * @param shift The number of bits to left shift. |
81 | | * @return (input * 2^shift) or nullopt if it would not fit in the return type. |
82 | | */ |
83 | | template <std::integral T> |
84 | | constexpr std::optional<T> CheckedLeftShift(T input, unsigned shift) noexcept |
85 | 128 | { |
86 | 128 | if (shift == 0 || input == 0) return input; |
87 | | // Avoid undefined c++ behaviour if shift is >= number of bits in T. |
88 | 108 | if (shift >= sizeof(T) * CHAR_BIT) return std::nullopt; |
89 | | // If input << shift is too big to fit in T, return nullopt. |
90 | 88 | if (input > (std::numeric_limits<T>::max() >> shift)) return std::nullopt; |
91 | 64 | if (input < (std::numeric_limits<T>::min() >> shift)) return std::nullopt; |
92 | 56 | return input << shift; |
93 | 64 | } Unexecuted instantiation: std::optional<unsigned long long> CheckedLeftShift<unsigned long long>(unsigned long long, unsigned int) std::optional<unsigned char> CheckedLeftShift<unsigned char>(unsigned char, unsigned int) Line | Count | Source | 85 | 20 | { | 86 | 20 | if (shift == 0 || input == 0) return input; | 87 | | // Avoid undefined c++ behaviour if shift is >= number of bits in T. | 88 | 16 | if (shift >= sizeof(T) * CHAR_BIT) return std::nullopt; | 89 | | // If input << shift is too big to fit in T, return nullopt. | 90 | 12 | if (input > (std::numeric_limits<T>::max() >> shift)) return std::nullopt; | 91 | 8 | if (input < (std::numeric_limits<T>::min() >> shift)) return std::nullopt; | 92 | 8 | return input << shift; | 93 | 8 | } |
std::optional<signed char> CheckedLeftShift<signed char>(signed char, unsigned int) Line | Count | Source | 85 | 34 | { | 86 | 34 | if (shift == 0 || input == 0) return input; | 87 | | // Avoid undefined c++ behaviour if shift is >= number of bits in T. | 88 | 30 | if (shift >= sizeof(T) * CHAR_BIT) return std::nullopt; | 89 | | // If input << shift is too big to fit in T, return nullopt. | 90 | 26 | if (input > (std::numeric_limits<T>::max() >> shift)) return std::nullopt; | 91 | 20 | if (input < (std::numeric_limits<T>::min() >> shift)) return std::nullopt; | 92 | 16 | return input << shift; | 93 | 20 | } |
std::optional<unsigned long> CheckedLeftShift<unsigned long>(unsigned long, unsigned int) Line | Count | Source | 85 | 40 | { | 86 | 40 | if (shift == 0 || input == 0) return input; | 87 | | // Avoid undefined c++ behaviour if shift is >= number of bits in T. | 88 | 32 | if (shift >= sizeof(T) * CHAR_BIT) return std::nullopt; | 89 | | // If input << shift is too big to fit in T, return nullopt. | 90 | 24 | if (input > (std::numeric_limits<T>::max() >> shift)) return std::nullopt; | 91 | 16 | if (input < (std::numeric_limits<T>::min() >> shift)) return std::nullopt; | 92 | 16 | return input << shift; | 93 | 16 | } |
std::optional<long> CheckedLeftShift<long>(long, unsigned int) Line | Count | Source | 85 | 34 | { | 86 | 34 | if (shift == 0 || input == 0) return input; | 87 | | // Avoid undefined c++ behaviour if shift is >= number of bits in T. | 88 | 30 | if (shift >= sizeof(T) * CHAR_BIT) return std::nullopt; | 89 | | // If input << shift is too big to fit in T, return nullopt. | 90 | 26 | if (input > (std::numeric_limits<T>::max() >> shift)) return std::nullopt; | 91 | 20 | if (input < (std::numeric_limits<T>::min() >> shift)) return std::nullopt; | 92 | 16 | return input << shift; | 93 | 20 | } |
|
94 | | |
95 | | /** |
96 | | * @brief Left bit shift with safe minimum and maximum values. |
97 | | * @param input The input value to be left shifted. |
98 | | * @param shift The number of bits to left shift. |
99 | | * @return (input * 2^shift) clamped to fit between the lowest and highest |
100 | | * representable values of the type T. |
101 | | */ |
102 | | template <std::integral T> |
103 | | constexpr T SaturatingLeftShift(T input, unsigned shift) noexcept |
104 | 64 | { |
105 | 64 | if (auto result{CheckedLeftShift(input, shift)}) return *result; |
106 | | // If input << shift is too big to fit in T, return biggest positive or negative |
107 | | // number that fits. |
108 | 26 | return input < 0 ? std::numeric_limits<T>::min() : std::numeric_limits<T>::max(); |
109 | 64 | } unsigned char SaturatingLeftShift<unsigned char>(unsigned char, unsigned int) Line | Count | Source | 104 | 10 | { | 105 | 10 | if (auto result{CheckedLeftShift(input, shift)}) return *result; | 106 | | // If input << shift is too big to fit in T, return biggest positive or negative | 107 | | // number that fits. | 108 | 4 | return input < 0 ? std::numeric_limits<T>::min() : std::numeric_limits<T>::max(); | 109 | 10 | } |
signed char SaturatingLeftShift<signed char>(signed char, unsigned int) Line | Count | Source | 104 | 17 | { | 105 | 17 | if (auto result{CheckedLeftShift(input, shift)}) return *result; | 106 | | // If input << shift is too big to fit in T, return biggest positive or negative | 107 | | // number that fits. | 108 | 7 | return input < 0 ? std::numeric_limits<T>::min() : std::numeric_limits<T>::max(); | 109 | 17 | } |
unsigned long SaturatingLeftShift<unsigned long>(unsigned long, unsigned int) Line | Count | Source | 104 | 20 | { | 105 | 20 | if (auto result{CheckedLeftShift(input, shift)}) return *result; | 106 | | // If input << shift is too big to fit in T, return biggest positive or negative | 107 | | // number that fits. | 108 | 8 | return input < 0 ? std::numeric_limits<T>::min() : std::numeric_limits<T>::max(); | 109 | 20 | } |
long SaturatingLeftShift<long>(long, unsigned int) Line | Count | Source | 104 | 17 | { | 105 | 17 | if (auto result{CheckedLeftShift(input, shift)}) return *result; | 106 | | // If input << shift is too big to fit in T, return biggest positive or negative | 107 | | // number that fits. | 108 | 7 | return input < 0 ? std::numeric_limits<T>::min() : std::numeric_limits<T>::max(); | 109 | 17 | } |
|
110 | | |
111 | | #endif // BITCOIN_UTIL_OVERFLOW_H |