Cppcheck
utils.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 //---------------------------------------------------------------------------
20 #ifndef utilsH
21 #define utilsH
22 //---------------------------------------------------------------------------
23 
24 #include "config.h"
25 
26 #include <algorithm>
27 #include <array>
28 #include <cstddef>
29 #include <cstdint>
30 #include <functional>
31 #include <initializer_list>
32 #include <limits>
33 #include <stdexcept>
34 #include <string>
35 #include <type_traits>
36 #include <vector>
37 
38 struct SelectMapKeys {
39  template<class Pair>
40  // NOLINTNEXTLINE(readability-const-return-type) - false positive
41  typename Pair::first_type operator()(const Pair& p) const {
42  return p.first;
43  }
44 };
45 
47  template<class Pair>
48  typename Pair::second_type operator()(const Pair& p) const {
49  return p.second;
50  }
51 };
52 
53 struct OnExit {
54  std::function<void()> f;
55 
56  ~OnExit() {
57  f();
58  }
59 };
60 
61 template<class Range, class T>
62 bool contains(const Range& r, const T& x)
63 {
64  return std::find(r.cbegin(), r.cend(), x) != r.cend();
65 }
66 
67 template<class T>
68 bool contains(const std::initializer_list<T>& r, const T& x)
69 {
70  return std::find(r.begin(), r.end(), x) != r.end();
71 }
72 
73 template<class T, class U>
74 bool contains(const std::initializer_list<T>& r, const U& x)
75 {
76  return std::find(r.begin(), r.end(), x) != r.end();
77 }
78 
79 template<class T, class ... Ts>
80 inline std::array<T, sizeof...(Ts) + 1> makeArray(T x, Ts... xs)
81 {
82  return {std::move(x), std::move(xs)...};
83 }
84 
85 // Enum hash for C++11. This is not needed in C++14
86 struct EnumClassHash {
87  template<typename T>
88  std::size_t operator()(T t) const
89  {
90  return static_cast<std::size_t>(t);
91  }
92 };
93 
94 inline bool startsWith(const std::string& str, const char start[], std::size_t startlen)
95 {
96  return str.compare(0, startlen, start) == 0;
97 }
98 
99 template<std::size_t N>
100 bool startsWith(const std::string& str, const char (&start)[N])
101 {
102  return startsWith(str, start, N - 1);
103 }
104 
105 inline bool startsWith(const std::string& str, const std::string& start)
106 {
107  return startsWith(str, start.c_str(), start.length());
108 }
109 
110 inline bool endsWith(const std::string &str, char c)
111 {
112  return !str.empty() && str.back() == c;
113 }
114 
115 inline bool endsWith(const std::string &str, const char end[], std::size_t endlen)
116 {
117  return (str.size() >= endlen) && (str.compare(str.size()-endlen, endlen, end)==0);
118 }
119 
120 template<std::size_t N>
121 bool endsWith(const std::string& str, const char (&end)[N])
122 {
123  return endsWith(str, end, N - 1);
124 }
125 
126 inline static bool isPrefixStringCharLiteral(const std::string &str, char q, const std::string& p)
127 {
128  // str must be at least the prefix plus the start and end quote
129  if (str.length() < p.length() + 2)
130  return false;
131 
132  // check for end quote
133  if (!endsWith(str, q))
134  return false;
135 
136  // check for start quote
137  if (str[p.size()] != q)
138  return false;
139 
140  // check for prefix
141  if (str.compare(0, p.size(), p) != 0)
142  return false;
143 
144  return true;
145 }
146 
147 inline static bool isStringCharLiteral(const std::string &str, char q)
148 {
149  // early out to avoid the loop
150  if (!endsWith(str, q))
151  return false;
152 
153  static const std::array<std::string, 5> suffixes{"", "u8", "u", "U", "L"};
154  return std::any_of(suffixes.cbegin(), suffixes.cend(), [&](const std::string& p) {
155  return isPrefixStringCharLiteral(str, q, p);
156  });
157 }
158 
159 inline static bool isStringLiteral(const std::string &str)
160 {
161  return isStringCharLiteral(str, '"');
162 }
163 
164 inline static bool isCharLiteral(const std::string &str)
165 {
166  return isStringCharLiteral(str, '\'');
167 }
168 
169 inline static std::string getStringCharLiteral(const std::string &str, char q)
170 {
171  const std::size_t quotePos = str.find(q);
172  return str.substr(quotePos + 1U, str.size() - quotePos - 2U);
173 }
174 
175 inline static std::string getStringLiteral(const std::string &str)
176 {
177  if (isStringLiteral(str))
178  return getStringCharLiteral(str, '"');
179  return "";
180 }
181 
182 inline static std::string getCharLiteral(const std::string &str)
183 {
184  if (isCharLiteral(str))
185  return getStringCharLiteral(str, '\'');
186  return "";
187 }
188 
189 inline static const char *getOrdinalText(int i)
190 {
191  if (i == 1)
192  return "st";
193  if (i == 2)
194  return "nd";
195  if (i == 3)
196  return "rd";
197  return "th";
198 }
199 
200 CPPCHECKLIB int caseInsensitiveStringCompare(const std::string& lhs, const std::string& rhs);
201 
202 CPPCHECKLIB bool isValidGlobPattern(const std::string& pattern);
203 
204 CPPCHECKLIB bool matchglob(const std::string& pattern, const std::string& name);
205 
206 CPPCHECKLIB bool matchglobs(const std::vector<std::string> &patterns, const std::string &name);
207 
208 CPPCHECKLIB void strTolower(std::string& str);
209 
210 template<typename T, typename std::enable_if<std::is_signed<T>::value, bool>::type=true>
211 bool strToInt(const std::string& str, T &num, std::string* err = nullptr)
212 {
213  long long tmp;
214  try {
215  std::size_t idx = 0;
216  tmp = std::stoll(str, &idx);
217  if (idx != str.size()) {
218  if (err)
219  *err = "not an integer";
220  return false;
221  }
222  } catch (const std::out_of_range&) {
223  if (err)
224  *err = "out of range (stoll)";
225  return false;
226  } catch (const std::invalid_argument &) {
227  if (err)
228  *err = "not an integer";
229  return false;
230  }
231  if (str.front() == '-' && std::numeric_limits<T>::min() == 0) {
232  if (err)
233  *err = "needs to be positive";
234  return false;
235  }
236  if (tmp < std::numeric_limits<T>::min() || tmp > std::numeric_limits<T>::max()) {
237  if (err)
238  *err = "out of range (limits)";
239  return false;
240  }
241  num = static_cast<T>(tmp);
242  return true;
243 }
244 
245 template<typename T, typename std::enable_if<std::is_unsigned<T>::value, bool>::type=true>
246 bool strToInt(const std::string& str, T &num, std::string* err = nullptr)
247 {
248  unsigned long long tmp;
249  try {
250  std::size_t idx = 0;
251  tmp = std::stoull(str, &idx);
252  if (idx != str.size()) {
253  if (err)
254  *err = "not an integer";
255  return false;
256  }
257  } catch (const std::out_of_range&) {
258  if (err)
259  *err = "out of range (stoull)";
260  return false;
261  } catch (const std::invalid_argument &) {
262  if (err)
263  *err = "not an integer";
264  return false;
265  }
266  if (str.front() == '-') {
267  if (err)
268  *err = "needs to be positive";
269  return false;
270  }
271  if (tmp > std::numeric_limits<T>::max()) {
272  if (err)
273  *err = "out of range (limits)";
274  return false;
275  }
276  num = tmp;
277  return true;
278 }
279 
280 template<typename T>
281 T strToInt(const std::string& str)
282 {
283  T tmp = 0;
284  std::string err;
285  if (!strToInt(str, tmp, &err))
286  throw std::runtime_error("converting '" + str + "' to integer failed - " + err);
287  return tmp;
288 }
289 
290 /**
291  * Simple helper function:
292  * \return size of array
293  * */
294 template<typename T, int size>
295 // cppcheck-suppress unusedFunction - only used in conditional code
296 std::size_t getArrayLength(const T (& /*unused*/)[size])
297 {
298  return size;
299 }
300 
301 /**
302  * @brief get id string. i.e. for dump files
303  * it will be a hexadecimal output.
304  */
305 static inline std::string id_string_i(std::uintptr_t l)
306 {
307  if (!l)
308  return "0";
309 
310  static constexpr int ptr_size = sizeof(void*);
311 
312  // two characters of each byte / contains terminating \0
313  static constexpr int buf_size = (ptr_size * 2) + 1;
314 
315  char buf[buf_size];
316 
317  // needs to be signed so we don't underflow in padding loop
318  int idx = buf_size - 1;
319  buf[idx] = '\0';
320 
321  while (l != 0)
322  {
323  char c;
324  const uintptr_t temp = l % 16; // get the remainder
325  if (temp < 10) {
326  // 0-9
327  c = '0' + temp;
328  }
329  else {
330  // a-f
331  c = 'a' + (temp - 10);
332  }
333  buf[--idx] = c; // store in reverse order
334  l = l / 16;
335  }
336 
337  return &buf[idx];
338 }
339 
340 static inline std::string id_string(const void* p)
341 {
342  return id_string_i(reinterpret_cast<uintptr_t>(p));
343 }
344 
345 static inline const char* bool_to_string(bool b)
346 {
347  return b ? "true" : "false";
348 }
349 
350 namespace cppcheck
351 {
352  NORETURN inline void unreachable()
353  {
354 #if defined(__GNUC__)
355  __builtin_unreachable();
356 #elif defined(_MSC_VER)
357  __assume(false);
358 #else
359 #error "no unreachable implementation"
360 #endif
361  }
362 }
363 
364 template<typename T>
365 static inline T* empty_if_null(T* p)
366 {
367  return p ? p : "";
368 }
369 
370 #endif
#define CPPCHECKLIB
Definition: config.h:35
#define NORETURN
Definition: config.h:80
NORETURN void unreachable()
Definition: utils.h:352
std::size_t operator()(T t) const
Definition: utils.h:88
Definition: utils.h:53
std::function< void()> f
Definition: utils.h:54
~OnExit()
Definition: utils.h:56
Pair::first_type operator()(const Pair &p) const
Definition: utils.h:41
Pair::second_type operator()(const Pair &p) const
Definition: utils.h:48
static std::string id_string_i(std::uintptr_t l)
get id string.
Definition: utils.h:305
static bool isStringLiteral(const std::string &str)
Definition: utils.h:159
static std::string getStringCharLiteral(const std::string &str, char q)
Definition: utils.h:169
static const char * getOrdinalText(int i)
Definition: utils.h:189
CPPCHECKLIB void strTolower(std::string &str)
Definition: utils.cpp:124
std::array< T, sizeof...(Ts)+1 > makeArray(T x, Ts... xs)
Definition: utils.h:80
static std::string id_string(const void *p)
Definition: utils.h:340
CPPCHECKLIB int caseInsensitiveStringCompare(const std::string &lhs, const std::string &rhs)
Definition: utils.cpp:28
CPPCHECKLIB bool matchglob(const std::string &pattern, const std::string &name)
Definition: utils.cpp:54
static bool isPrefixStringCharLiteral(const std::string &str, char q, const std::string &p)
Definition: utils.h:126
bool startsWith(const std::string &str, const char start[], std::size_t startlen)
Definition: utils.h:94
static std::string getStringLiteral(const std::string &str)
Definition: utils.h:175
bool strToInt(const std::string &str, T &num, std::string *err=nullptr)
Definition: utils.h:211
CPPCHECKLIB bool isValidGlobPattern(const std::string &pattern)
Definition: utils.cpp:41
bool endsWith(const std::string &str, char c)
Definition: utils.h:110
static bool isCharLiteral(const std::string &str)
Definition: utils.h:164
static T * empty_if_null(T *p)
Definition: utils.h:365
static const char * bool_to_string(bool b)
Definition: utils.h:345
std::size_t getArrayLength(const T(&)[size])
Simple helper function:
Definition: utils.h:296
static std::string getCharLiteral(const std::string &str)
Definition: utils.h:182
static bool isStringCharLiteral(const std::string &str, char q)
Definition: utils.h:147
CPPCHECKLIB bool matchglobs(const std::vector< std::string > &patterns, const std::string &name)
Definition: utils.cpp:118
bool contains(const Range &r, const T &x)
Definition: utils.h:62