Cppcheck
calculate.h
Go to the documentation of this file.
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 bool isEqual(T x, T y)
29 {
30  return x == y;
31 }
32 
33 inline bool isEqual(double x, double y)
34 {
35  const double diff = (x > y) ? x - y : y - x;
36  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 bool isZero(T x)
45 {
46  return isEqual(x, T(0));
47 }
48 
49 template<class R, class T>
50 R calculate(const std::string& s, const T& x, const T& y, bool* error = nullptr)
51 {
52  auto wrap = [](T z) {
53  return R{z};
54  };
55  constexpr MathLib::bigint maxBitsShift = sizeof(MathLib::bigint) * 8;
56  // For portability we cannot shift signed integers by 63 bits
57  constexpr MathLib::bigint maxBitsSignedShift = maxBitsShift - 1;
58  switch (MathLib::encodeMultiChar(s)) {
59  case '+':
60  return wrap(x + y);
61  case '-':
62  return wrap(x - y);
63  case '*':
64  return wrap(x * y);
65  case '/':
66  if (isZero(y) || (std::is_integral<T>{} && std::is_signed<T>{} && isEqual(y, T(-1)) && isEqual(x, std::numeric_limits<T>::min()))) {
67  if (error)
68  *error = true;
69  return R{};
70  }
71  return wrap(x / y);
72  case '%':
73  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  if (error)
75  *error = true;
76  return R{};
77  }
78  return wrap(MathLib::bigint(x) % MathLib::bigint(y));
79  case '&':
80  return wrap(MathLib::bigint(x) & MathLib::bigint(y));
81  case '|':
82  return wrap(MathLib::bigint(x) | MathLib::bigint(y));
83  case '^':
84  return wrap(MathLib::bigint(x) ^ MathLib::bigint(y));
85  case '>':
86  return wrap(x > y);
87  case '<':
88  return wrap(x < y);
89  case '<<':
90  if (y >= maxBitsSignedShift || y < 0 || x < 0) {
91  if (error)
92  *error = true;
93  return R{};
94  }
95  return wrap(MathLib::bigint(x) << MathLib::bigint(y));
96  case '>>':
97  if (y >= maxBitsSignedShift || y < 0 || x < 0) {
98  if (error)
99  *error = true;
100  return R{};
101  }
102  return wrap(MathLib::bigint(x) >> MathLib::bigint(y));
103  case '&&':
104  return wrap(!isZero(x) && !isZero(y));
105  case '||':
106  return wrap(!isZero(x) || !isZero(y));
107  case '==':
108  return wrap(isEqual(x, y));
109  case '!=':
110  return wrap(!isEqual(x, y));
111  case '>=':
112  return wrap(x >= y);
113  case '<=':
114  return wrap(x <= y);
115  case '<=>':
116  return wrap(x - y);
117  }
118  throw InternalError(nullptr, "Unknown operator: " + s);
119 }
120 
121 template<class T>
122 T calculate(const std::string& s, const T& x, const T& y, bool* error = nullptr)
123 {
124  return calculate<T, T>(s, x, y, error);
125 }
126 
127 #endif
bool isEqual(T x, T y)
Definition: calculate.h:28
R calculate(const std::string &s, const T &x, const T &y, bool *error=nullptr)
Definition: calculate.h:50
bool isZero(T x)
Definition: calculate.h:44
long long bigint
Definition: mathlib.h:68
static unsigned int encodeMultiChar(const std::string &str)
Definition: mathlib.cpp:360
@ error
Programming error.
Simple container to be thrown when internal error is detected.
Definition: errortypes.h:36