/Users/eugenesiegel/btc/bitcoin/src/util/overflow.h
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) 2021-2022 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 | | [[nodiscard]] bool AdditionOverflow(const T i, const T j) noexcept |
16 | 20.3M | { |
17 | 20.3M | static_assert(std::is_integral_v<T>, "Integral required."); |
18 | 20.3M | if constexpr (std::numeric_limits<T>::is_signed) { |
19 | 0 | return (i > 0 && j > std::numeric_limits<T>::max() - i) || |
20 | 0 | (i < 0 && j < std::numeric_limits<T>::min() - i); |
21 | 0 | } |
22 | 0 | return std::numeric_limits<T>::max() - i < j; |
23 | 20.3M | } Unexecuted instantiation: _Z16AdditionOverflowIxEbT_S0_ Unexecuted instantiation: _Z16AdditionOverflowIyEbT_S0_ Unexecuted instantiation: _Z16AdditionOverflowIiEbT_S0_ Unexecuted instantiation: _Z16AdditionOverflowIjEbT_S0_ Unexecuted instantiation: _Z16AdditionOverflowIsEbT_S0_ Unexecuted instantiation: _Z16AdditionOverflowItEbT_S0_ Unexecuted instantiation: _Z16AdditionOverflowIcEbT_S0_ Unexecuted instantiation: _Z16AdditionOverflowIhEbT_S0_ Unexecuted instantiation: _Z16AdditionOverflowIaEbT_S0_ _Z16AdditionOverflowImEbT_S0_ Line | Count | Source | 16 | 20.3M | { | 17 | 20.3M | static_assert(std::is_integral_v<T>, "Integral required."); | 18 | | if constexpr (std::numeric_limits<T>::is_signed) { | 19 | | return (i > 0 && j > std::numeric_limits<T>::max() - i) || | 20 | | (i < 0 && j < std::numeric_limits<T>::min() - i); | 21 | | } | 22 | 20.3M | return std::numeric_limits<T>::max() - i < j; | 23 | 20.3M | } |
|
24 | | |
25 | | template <class T> |
26 | | [[nodiscard]] std::optional<T> CheckedAdd(const T i, const T j) noexcept |
27 | 20.3M | { |
28 | 20.3M | if (AdditionOverflow(i, j)) { |
29 | 0 | return std::nullopt; |
30 | 0 | } |
31 | 20.3M | return i + j; |
32 | 20.3M | } Unexecuted instantiation: _Z10CheckedAddIxENSt3__18optionalIT_EES2_S2_ Unexecuted instantiation: _Z10CheckedAddIyENSt3__18optionalIT_EES2_S2_ Unexecuted instantiation: _Z10CheckedAddIiENSt3__18optionalIT_EES2_S2_ Unexecuted instantiation: _Z10CheckedAddIjENSt3__18optionalIT_EES2_S2_ Unexecuted instantiation: _Z10CheckedAddIsENSt3__18optionalIT_EES2_S2_ Unexecuted instantiation: _Z10CheckedAddItENSt3__18optionalIT_EES2_S2_ Unexecuted instantiation: _Z10CheckedAddIcENSt3__18optionalIT_EES2_S2_ Unexecuted instantiation: _Z10CheckedAddIhENSt3__18optionalIT_EES2_S2_ Unexecuted instantiation: _Z10CheckedAddIaENSt3__18optionalIT_EES2_S2_ _Z10CheckedAddImENSt3__18optionalIT_EES2_S2_ Line | Count | Source | 27 | 20.3M | { | 28 | 20.3M | if (AdditionOverflow(i, j)) { | 29 | 0 | return std::nullopt; | 30 | 0 | } | 31 | 20.3M | return i + j; | 32 | 20.3M | } |
|
33 | | |
34 | | template <class T> |
35 | | [[nodiscard]] T SaturatingAdd(const T i, const T j) noexcept |
36 | 0 | { |
37 | 0 | if constexpr (std::numeric_limits<T>::is_signed) { |
38 | 0 | if (i > 0 && j > std::numeric_limits<T>::max() - i) { |
39 | 0 | return std::numeric_limits<T>::max(); |
40 | 0 | } |
41 | 0 | if (i < 0 && j < std::numeric_limits<T>::min() - i) { |
42 | 0 | return std::numeric_limits<T>::min(); |
43 | 0 | } |
44 | 0 | } else { |
45 | 0 | if (std::numeric_limits<T>::max() - i < j) { |
46 | 0 | return std::numeric_limits<T>::max(); |
47 | 0 | } |
48 | 0 | } |
49 | 0 | return i + j; |
50 | 0 | } Unexecuted instantiation: _Z13SaturatingAddIxET_S0_S0_ Unexecuted instantiation: _Z13SaturatingAddIyET_S0_S0_ Unexecuted instantiation: _Z13SaturatingAddIiET_S0_S0_ Unexecuted instantiation: _Z13SaturatingAddIjET_S0_S0_ Unexecuted instantiation: _Z13SaturatingAddIsET_S0_S0_ Unexecuted instantiation: _Z13SaturatingAddItET_S0_S0_ Unexecuted instantiation: _Z13SaturatingAddIcET_S0_S0_ Unexecuted instantiation: _Z13SaturatingAddIhET_S0_S0_ Unexecuted instantiation: _Z13SaturatingAddIaET_S0_S0_ |
51 | | |
52 | | /** |
53 | | * @brief Left bit shift with overflow checking. |
54 | | * @param input The input value to be left shifted. |
55 | | * @param shift The number of bits to left shift. |
56 | | * @return (input * 2^shift) or nullopt if it would not fit in the return type. |
57 | | */ |
58 | | template <std::integral T> |
59 | | constexpr std::optional<T> CheckedLeftShift(T input, unsigned shift) noexcept |
60 | 0 | { |
61 | 0 | if (shift == 0 || input == 0) return input; |
62 | | // Avoid undefined c++ behaviour if shift is >= number of bits in T. |
63 | 0 | if (shift >= sizeof(T) * CHAR_BIT) return std::nullopt; |
64 | | // If input << shift is too big to fit in T, return nullopt. |
65 | 0 | if (input > (std::numeric_limits<T>::max() >> shift)) return std::nullopt; |
66 | 0 | if (input < (std::numeric_limits<T>::min() >> shift)) return std::nullopt; |
67 | 0 | return input << shift; |
68 | 0 | } Unexecuted instantiation: _Z16CheckedLeftShiftITkNSt3__18integralEyENS0_8optionalIT_EES2_j Unexecuted instantiation: _Z16CheckedLeftShiftITkNSt3__18integralEaENS0_8optionalIT_EES2_j Unexecuted instantiation: _Z16CheckedLeftShiftITkNSt3__18integralEsENS0_8optionalIT_EES2_j Unexecuted instantiation: _Z16CheckedLeftShiftITkNSt3__18integralEiENS0_8optionalIT_EES2_j Unexecuted instantiation: _Z16CheckedLeftShiftITkNSt3__18integralEhENS0_8optionalIT_EES2_j Unexecuted instantiation: _Z16CheckedLeftShiftITkNSt3__18integralEtENS0_8optionalIT_EES2_j Unexecuted instantiation: _Z16CheckedLeftShiftITkNSt3__18integralEjENS0_8optionalIT_EES2_j |
69 | | |
70 | | /** |
71 | | * @brief Left bit shift with safe minimum and maximum values. |
72 | | * @param input The input value to be left shifted. |
73 | | * @param shift The number of bits to left shift. |
74 | | * @return (input * 2^shift) clamped to fit between the lowest and highest |
75 | | * representable values of the type T. |
76 | | */ |
77 | | template <std::integral T> |
78 | | constexpr T SaturatingLeftShift(T input, unsigned shift) noexcept |
79 | 0 | { |
80 | 0 | if (auto result{CheckedLeftShift(input, shift)}) return *result; |
81 | | // If input << shift is too big to fit in T, return biggest positive or negative |
82 | | // number that fits. |
83 | 0 | return input < 0 ? std::numeric_limits<T>::min() : std::numeric_limits<T>::max(); |
84 | 0 | } Unexecuted instantiation: _Z19SaturatingLeftShiftITkNSt3__18integralEaET_S1_j Unexecuted instantiation: _Z19SaturatingLeftShiftITkNSt3__18integralEsET_S1_j Unexecuted instantiation: _Z19SaturatingLeftShiftITkNSt3__18integralEiET_S1_j Unexecuted instantiation: _Z19SaturatingLeftShiftITkNSt3__18integralEhET_S1_j Unexecuted instantiation: _Z19SaturatingLeftShiftITkNSt3__18integralEtET_S1_j Unexecuted instantiation: _Z19SaturatingLeftShiftITkNSt3__18integralEjET_S1_j Unexecuted instantiation: _Z19SaturatingLeftShiftITkNSt3__18integralEyET_S1_j |
85 | | |
86 | | #endif // BITCOIN_UTIL_OVERFLOW_H |