LCOV - code coverage report
Current view: top level - src/util - overflow.h (source / functions) Coverage Total Hit
Test: total_coverage.info Lines: 85.0 % 20 17
Test Date: 2025-01-19 05:08:01 Functions: 85.7 % 14 12
Branches: 80.0 % 30 24

             Branch data     Line data    Source code
       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                 :    15203626 : [[nodiscard]] bool AdditionOverflow(const T i, const T j) noexcept
      16                 :             : {
      17                 :             :     static_assert(std::is_integral<T>::value, "Integral required.");
      18                 :             :     if constexpr (std::numeric_limits<T>::is_signed) {
      19   [ +  +  +  +  :       16788 :         return (i > 0 && j > std::numeric_limits<T>::max() - i) ||
                   +  + ]
      20         [ +  + ]:          10 :                (i < 0 && j < std::numeric_limits<T>::min() - i);
      21                 :             :     }
      22                 :    15186838 :     return std::numeric_limits<T>::max() - i < j;
      23                 :             : }
      24                 :             : 
      25                 :             : template <class T>
      26                 :    15203626 : [[nodiscard]] std::optional<T> CheckedAdd(const T i, const T j) noexcept
      27                 :             : {
      28         [ +  + ]:    15203626 :     if (AdditionOverflow(i, j)) {
      29                 :          12 :         return std::nullopt;
      30                 :             :     }
      31                 :    15203614 :     return i + j;
      32                 :             : }
      33                 :             : 
      34                 :             : template <class T>
      35                 :     1214764 : [[nodiscard]] T SaturatingAdd(const T i, const T j) noexcept
      36                 :             : {
      37                 :             :     if constexpr (std::numeric_limits<T>::is_signed) {
      38   [ +  +  +  + ]:     1214752 :         if (i > 0 && j > std::numeric_limits<T>::max() - i) {
      39                 :             :             return std::numeric_limits<T>::max();
      40                 :             :         }
      41   [ +  +  +  + ]:        2186 :         if (i < 0 && j < std::numeric_limits<T>::min() - i) {
      42                 :             :             return std::numeric_limits<T>::min();
      43                 :             :         }
      44                 :             :     } else {
      45         [ +  + ]:          12 :         if (std::numeric_limits<T>::max() - i < j) {
      46                 :             :             return std::numeric_limits<T>::max();
      47                 :             :         }
      48                 :             :     }
      49                 :     1214752 :     return i + j;
      50                 :             : }
      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                 :           1 : constexpr std::optional<T> CheckedLeftShift(T input, unsigned shift) noexcept
      60                 :             : {
      61   [ +  -  -  + ]:           1 :     if (shift == 0 || input == 0) return input;
      62                 :             :     // Avoid undefined c++ behaviour if shift is >= number of bits in T.
      63         [ -  + ]:           1 :     if (shift >= sizeof(T) * CHAR_BIT) return std::nullopt;
      64                 :             :     // If input << shift is too big to fit in T, return nullopt.
      65         [ +  - ]:           1 :     if (input > (std::numeric_limits<T>::max() >> shift)) return std::nullopt;
      66                 :             :     if (input < (std::numeric_limits<T>::min() >> shift)) return std::nullopt;
      67                 :           0 :     return input << shift;
      68                 :             : }
      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                 :           0 : constexpr T SaturatingLeftShift(T input, unsigned shift) noexcept
      79                 :             : {
      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                 :             :     return input < 0 ? std::numeric_limits<T>::min() : std::numeric_limits<T>::max();
      84                 :             : }
      85                 :             : 
      86                 :             : #endif // BITCOIN_UTIL_OVERFLOW_H
        

Generated by: LCOV version 2.0-1