LCOV - code coverage report
Current view: top level - lib - calculate.h (source / functions) Hit Total Coverage
Test: lcov.info Lines: 69 70 98.6 %
Date: 2024-04-28 12:00:40 Functions: 16 17 94.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Cppcheck - A tool for static C/C++ code analysis
       3             :  * Copyright (C) 2007-2023 Cppcheck team.
       4             :  *
       5             :  * This program is free software: you can redistribute it and/or modify
       6             :  * it under the terms of the GNU General Public License as published by
       7             :  * the Free Software Foundation, either version 3 of the License, or
       8             :  * (at your option) any later version.
       9             :  *
      10             :  * This program is distributed in the hope that it will be useful,
      11             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      12             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13             :  * GNU General Public License for more details.
      14             :  *
      15             :  * You should have received a copy of the GNU General Public License
      16             :  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
      17             :  */
      18             : 
      19             : #ifndef calculateH
      20             : #define calculateH
      21             : 
      22             : #include "mathlib.h"
      23             : #include "errortypes.h"
      24             : #include <limits>
      25             : #include <string>
      26             : 
      27             : template<class T>
      28       90352 : bool isEqual(T x, T y)
      29             : {
      30       90352 :     return x == y;
      31             : }
      32             : 
      33          45 : inline bool isEqual(double x, double y)
      34             : {
      35          45 :     const double diff = (x > y) ? x - y : y - x;
      36          45 :     return !((diff / 2) < diff);
      37             : }
      38             : inline bool isEqual(float x, float y)
      39             : {
      40             :     return isEqual(double(x), double(y));
      41             : }
      42             : 
      43             : template<class T>
      44         973 : bool isZero(T x)
      45             : {
      46         973 :     return isEqual(x, T(0));
      47             : }
      48             : 
      49             : template<class R, class T>
      50      197114 : R calculate(const std::string& s, const T& x, const T& y, bool* error = nullptr)
      51             : {
      52      196491 :     auto wrap = [](T z) {
      53      196887 :         return R{z};
      54             :     };
      55      197114 :     constexpr MathLib::bigint maxBitsShift = sizeof(MathLib::bigint) * 8;
      56             :     // For portability we cannot shift signed integers by 63 bits
      57      197114 :     constexpr MathLib::bigint maxBitsSignedShift = maxBitsShift - 1;
      58      197114 :     switch (MathLib::encodeMultiChar(s)) {
      59        5835 :     case '+':
      60        5835 :         return wrap(x + y);
      61         875 :     case '-':
      62         875 :         return wrap(x - y);
      63         875 :     case '*':
      64         875 :         return wrap(x * y);
      65         487 :     case '/':
      66         487 :         if (isZero(y) || (std::is_integral<T>{} && std::is_signed<T>{} && isEqual(y, T(-1)) && isEqual(x, std::numeric_limits<T>::min()))) {
      67         318 :             if (error)
      68         302 :                 *error = true;
      69         318 :             return R{};
      70             :         }
      71         169 :         return wrap(x / y);
      72         302 :     case '%':
      73         302 :         if (isZero(MathLib::bigint(y)) || (std::is_integral<T>{} && std::is_signed<T>{} && isEqual(y, T(-1)) && isEqual(x, std::numeric_limits<T>::min()))) {
      74         143 :             if (error)
      75         143 :                 *error = true;
      76         143 :             return R{};
      77             :         }
      78         159 :         return wrap(MathLib::bigint(x) % MathLib::bigint(y));
      79         484 :     case '&':
      80         484 :         return wrap(MathLib::bigint(x) & MathLib::bigint(y));
      81         262 :     case '|':
      82         262 :         return wrap(MathLib::bigint(x) | MathLib::bigint(y));
      83          30 :     case '^':
      84          30 :         return wrap(MathLib::bigint(x) ^ MathLib::bigint(y));
      85       14075 :     case '>':
      86       14075 :         return wrap(x > y);
      87       68122 :     case '<':
      88       68122 :         return wrap(x < y);
      89         384 :     case '<<':
      90         384 :         if (y >= maxBitsSignedShift || y < 0 || x < 0) {
      91          24 :             if (error)
      92          14 :                 *error = true;
      93          24 :             return R{};
      94             :         }
      95         360 :         return wrap(MathLib::bigint(x) << MathLib::bigint(y));
      96         418 :     case '>>':
      97         418 :         if (y >= maxBitsSignedShift || y < 0 || x < 0) {
      98         138 :             if (error)
      99         138 :                 *error = true;
     100         138 :             return R{};
     101             :         }
     102         280 :         return wrap(MathLib::bigint(x) >> MathLib::bigint(y));
     103          83 :     case '&&':
     104          83 :         return wrap(!isZero(x) && !isZero(y));
     105          31 :     case '||':
     106          31 :         return wrap(!isZero(x) || !isZero(y));
     107       52650 :     case '==':
     108       52650 :         return wrap(isEqual(x, y));
     109       36443 :     case '!=':
     110       36443 :         return wrap(!isEqual(x, y));
     111        8678 :     case '>=':
     112        8678 :         return wrap(x >= y);
     113        7079 :     case '<=':
     114        7079 :         return wrap(x <= y);
     115           1 :     case '<=>':
     116           1 :         return wrap(x - y);
     117             :     }
     118           0 :     throw InternalError(nullptr, "Unknown operator: " + s);
     119             : }
     120             : 
     121             : template<class T>
     122      195999 : T calculate(const std::string& s, const T& x, const T& y, bool* error = nullptr)
     123             : {
     124      195999 :     return calculate<T, T>(s, x, y, error);
     125             : }
     126             : 
     127             : #endif

Generated by: LCOV version 1.14