Bitcoin Core  31.0.0
P2P Digital Currency
overflow.h
Go to the documentation of this file.
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 [[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  return (i > 0 && j > std::numeric_limits<T>::max() - i) ||
20  (i < 0 && j < std::numeric_limits<T>::min() - i);
21  }
22  return std::numeric_limits<T>::max() - i < j;
23 }
24 
25 template <class T>
26 [[nodiscard]] std::optional<T> CheckedAdd(const T i, const T j) noexcept
27 {
28  if (AdditionOverflow(i, j)) {
29  return std::nullopt;
30  }
31  return i + j;
32 }
33 
34 template <std::unsigned_integral T, std::unsigned_integral U>
35 [[nodiscard]] constexpr bool TrySub(T& i, const U j) noexcept
36 {
37  if (i < T{j}) return false;
38  i -= T{j};
39  return true;
40 }
41 
42 template <class T>
43 [[nodiscard]] T SaturatingAdd(const T i, const T j) noexcept
44 {
45  if constexpr (std::numeric_limits<T>::is_signed) {
46  if (i > 0 && j > std::numeric_limits<T>::max() - i) {
47  return std::numeric_limits<T>::max();
48  }
49  if (i < 0 && j < std::numeric_limits<T>::min() - i) {
50  return std::numeric_limits<T>::min();
51  }
52  } else {
53  if (std::numeric_limits<T>::max() - i < j) {
54  return std::numeric_limits<T>::max();
55  }
56  }
57  return i + j;
58 }
59 
66 template <std::integral T>
67 constexpr std::optional<T> CheckedLeftShift(T input, unsigned shift) noexcept
68 {
69  if (shift == 0 || input == 0) return input;
70  // Avoid undefined c++ behaviour if shift is >= number of bits in T.
71  if (shift >= sizeof(T) * CHAR_BIT) return std::nullopt;
72  // If input << shift is too big to fit in T, return nullopt.
73  if (input > (std::numeric_limits<T>::max() >> shift)) return std::nullopt;
74  if (input < (std::numeric_limits<T>::min() >> shift)) return std::nullopt;
75  return input << shift;
76 }
77 
85 template <std::integral T>
86 constexpr T SaturatingLeftShift(T input, unsigned shift) noexcept
87 {
88  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
constexpr bool TrySub(T &i, const U j) noexcept
Definition: overflow.h:35
bool AdditionOverflow(const T i, const T j) noexcept
Definition: overflow.h:15
constexpr std::optional< T > CheckedLeftShift(T input, unsigned shift) noexcept
Left bit shift with overflow checking.
Definition: overflow.h:67
std::optional< T > CheckedAdd(const T i, const T j) noexcept
Definition: overflow.h:26
T SaturatingAdd(const T i, const T j) noexcept
Definition: overflow.h:43
constexpr T SaturatingLeftShift(T input, unsigned shift) noexcept
Left bit shift with safe minimum and maximum values.
Definition: overflow.h:86
auto result
Definition: common-types.h:74
#define T(expected, seed, data)