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