Branch data Line data Source code
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 <climits>
9 : : #include <concepts>
10 : : #include <limits>
11 : : #include <optional>
12 : : #include <type_traits>
13 : :
14 : : template <class T>
15 : 15192512 : [[nodiscard]] bool AdditionOverflow(const T i, const T j) noexcept
16 : : {
17 : : static_assert(std::is_integral_v<T>, "Integral required.");
18 : : if constexpr (std::numeric_limits<T>::is_signed) {
19 [ + + + + : 20123 : return (i > 0 && j > std::numeric_limits<T>::max() - i) ||
+ + ]
20 [ + + ]: 10 : (i < 0 && j < std::numeric_limits<T>::min() - i);
21 : : }
22 : 15172389 : return std::numeric_limits<T>::max() - i < j;
23 : : }
24 : :
25 : : template <class T>
26 : 15192512 : [[nodiscard]] std::optional<T> CheckedAdd(const T i, const T j) noexcept
27 : : {
28 [ + + ]: 15192512 : if (AdditionOverflow(i, j)) {
29 : 12 : return std::nullopt;
30 : : }
31 : 15192500 : return i + j;
32 : : }
33 : :
34 : : template <std::unsigned_integral T, std::unsigned_integral U>
35 : 17341376 : [[nodiscard]] constexpr bool TrySub(T& i, const U j) noexcept
36 : : {
37 [ + - + - : 17341376 : if (i < T{j}) return false;
+ - + - +
- + - + -
+ - + - ]
[ + - # #
# # # # #
# # # # #
# # # # ]
38 : 17341376 : i -= T{j};
39 : 17341376 : return true;
40 : : }
41 : :
42 : : template <class T>
43 : 1140 : [[nodiscard]] T SaturatingAdd(const T i, const T j) noexcept
44 : : {
45 : : if constexpr (std::numeric_limits<T>::is_signed) {
46 [ + + + + ]: 1096 : if (i > 0 && j > std::numeric_limits<T>::max() - i) {
47 : : return std::numeric_limits<T>::max();
48 : : }
49 [ + + + + ]: 786 : if (i < 0 && j < std::numeric_limits<T>::min() - i) {
50 : : return std::numeric_limits<T>::min();
51 : : }
52 : : } else {
53 [ + + ]: 44 : if (std::numeric_limits<T>::max() - i < j) {
54 : : return std::numeric_limits<T>::max();
55 : : }
56 : : }
57 : 1126 : return i + j;
58 : : }
59 : :
60 : : /**
61 : : * @brief Left bit shift with overflow checking.
62 : : * @param input The input value to be left shifted.
63 : : * @param shift The number of bits to left shift.
64 : : * @return (input * 2^shift) or nullopt if it would not fit in the return type.
65 : : */
66 : : template <std::integral T>
67 : 1 : constexpr std::optional<T> CheckedLeftShift(T input, unsigned shift) noexcept
68 : : {
69 [ + - - + ]: 1 : if (shift == 0 || input == 0) return input;
70 : : // Avoid undefined c++ behaviour if shift is >= number of bits in T.
71 [ - + ]: 1 : if (shift >= sizeof(T) * CHAR_BIT) return std::nullopt;
72 : : // If input << shift is too big to fit in T, return nullopt.
73 [ + - ]: 1 : if (input > (std::numeric_limits<T>::max() >> shift)) return std::nullopt;
74 : : if (input < (std::numeric_limits<T>::min() >> shift)) return std::nullopt;
75 : 0 : return input << shift;
76 : : }
77 : :
78 : : /**
79 : : * @brief Left bit shift with safe minimum and maximum values.
80 : : * @param input The input value to be left shifted.
81 : : * @param shift The number of bits to left shift.
82 : : * @return (input * 2^shift) clamped to fit between the lowest and highest
83 : : * representable values of the type T.
84 : : */
85 : : template <std::integral T>
86 : 0 : constexpr T SaturatingLeftShift(T input, unsigned shift) noexcept
87 : : {
88 [ # # ]: 0 : if (auto result{CheckedLeftShift(input, shift)}) return *result;
89 : : // If input << shift is too big to fit in T, return biggest positive or negative
90 : : // number that fits.
91 : : return input < 0 ? std::numeric_limits<T>::min() : std::numeric_limits<T>::max();
92 : : }
93 : :
94 : : #endif // BITCOIN_UTIL_OVERFLOW_H
|