CodeSonar C++ API
[For improved navigation, enable JavaScript.]
cs_enum_boilerplate.hpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2023, an unpublished work by CodeSecure, Inc.
3  * ALL RIGHTS RESERVED
4  *
5  * Copyright (c) 2013-2023, an unpublished work by GrammaTech, Inc.
6  * ALL RIGHTS RESERVED
7  *
8  * This software is furnished under a license and may be used and
9  * copied only in accordance with the terms of such license and the
10  * inclusion of the above copyright notice. This software or any
11  * other copies thereof may not be provided or otherwise made
12  * available to any other person. Title to and ownership of the
13  * software is retained by CodeSecure, Inc.
14  */
15 
16 #ifndef CS_ENUM_BOILERPLATE_HPP
17 #define CS_ENUM_BOILERPLATE_HPP
18 
19 #include "cs_cglue.hpp"
20 
23 #ifndef SWIG
24 namespace cs{
26  inline void check(cs_result r);
28 }
29 #endif /* !SWIG */
30 
31 #define CS_ENUM_BOILERPLATE_NONMEMBERS(cls, cs) \
32  \
33  \
34  \
35  \
36  \
37  inline std::ostream &operator<<( std::ostream &out, const cls &a ) \
38  { \
39  return out << "cs" CS_AS_REPR_SCOPE #cls " " \
40  << a.name(); \
41  } \
42  CS_STD_HASH(cls, cs)
43 
44 
45 #define CS_ENUM_BOILERPLATE_NONAME_NOCTOR(cls, CTYPE) \
46 private: \
47  friend class cglue<cls>; \
48  CTYPE inner; \
49  typedef CTYPE ctype; \
50 public: \
51  \
52  \
53  \
54  \
55  \
56  \
57  \
58  \
59  int cmp(const cls& other) const \
60  { return (int)inner < (int)other.inner ? -1 \
61  : (int)inner > (int)other.inner ? 1 \
62  : 0; } \
63  SWIG_BUILD_ONLY( \
64  \
65  \
66  \
67  \
68  \
69  bool operator==(const cls& other) const \
70  { return cmp(other) == 0; } \
71  \
72  \
73  \
74  \
75  \
76  \
77  bool operator!=(const cls& b) const \
78  { return cmp(b) != 0; } \
79  \
80  \
81  \
82  \
83  \
84  \
85  bool operator<(const cls& b) const \
86  { return cmp(b) < 0; } \
87  \
88  \
89  \
90  \
91  \
92  \
93  bool operator<=(const cls& b) const \
94  { return cmp(b) <= 0; } \
95  \
96  \
97  \
98  \
99  \
100  \
101  bool operator>(const cls& b) const \
102  { return cmp(b) > 0; } \
103  \
104  \
105  \
106  \
107  \
108  \
109  bool operator>=(const cls& b) const \
110  { return cmp(b) >= 0; } ) \
111  \
112  \
113  CS_BOILERPLATE_HASH_TYPE hash() const \
114  { return inner; } \
115  \
116  \
117  \
118  \
119  csint64 as_integer() const \
120  { return (csint64)inner; } \
121  \
122 private: \
123  CTYPE unwrap() const \
124  { return inner; } \
125  \
126 public: \
127  \
128  std::string as_string() const \
129  { \
130  CS_CPP_TRY({ return name(); }) \
131  CS_CPP_CATCH(result,{ \
132  std::stringstream buf; \
133  buf << CS_AS_REPR_PREFIX #cls " " \
134  << inner << CS_AS_REPR_SUFFIX; \
135  return buf.str(); \
136  }) \
137  } \
138  \
139  \
140  std::string as_repr() const \
141  { return CS_AS_REPR_FROM_STRING(cls); } \
142 
143 
144 #define CS_ENUM_BOILERPLATE_NONAME(cls, CTYPE, is_valid) \
145  CS_ENUM_BOILERPLATE_NONAME_NOCTOR(cls, CTYPE) \
146  \
147  \
148  \
149  \
150  static cls from_integer(csint64 _inner) \
151  { \
152  if( !(is_valid) ) \
153  cs::check(CS_ERROR_INVALID_ARGUMENT); \
154  return cls((ctype)_inner); \
155  } \
156 private: \
157  cls(ctype _inner_ct): inner(_inner_ct) \
158  { \
159  csuint64 _inner = _inner_ct; \
160  (void)_inner; \
161  assert( is_valid ); \
162  } \
163 public: \
164 
165 #define CS_ENUM_BOILERPLATE(cls, CTYPE, getname, is_valid) \
166 private: \
167  \
168  cls(); \
169  CS_ENUM_BOILERPLATE_NONAME(cls, CTYPE, is_valid) \
170  \
171  \
172  std::string name() const \
173  { \
174  const char *rv; \
175  getname; \
176  return rv; \
177  } \
178  \
179 
180 
181 // Provide only the names of unique, singleton flags as arguments, not
182 // any composites (e.g., "A" and "B" but not "A_OR_B").
183 #define CS_FLAGS_BOILERPLATE(cls, CTYPE, mask, ...) \
184  CS_ENUM_BOILERPLATE_NONAME(cls, CTYPE, !(_inner & ~(csint64)(mask))) \
185  \
186  std::string name() const \
187  { \
188  static const char *const names[] = {__VA_ARGS__, NULL}; \
189  csuint32 i; \
190  /* I'm sure there are bit twiddling \
191  * tricks that would make this \
192  * faster (or ffs, where available) \
193  */ \
194  std::string rv; \
195  for( i = 0; names[i]; i++ ) \
196  { \
197  if( ((csuint32)inner) & (1<<i) ) \
198  { \
199  if( rv.size() ) \
200  rv += "|"; \
201  rv += names[i]; \
202  } \
203  } \
204  if( !rv.size() ) \
205  rv = "none"; \
206  return rv; \
207  } \
208  \
209 private: \
210  NOTSWIG( \
211  friend cls operator|(const cls& a, const cls& b); \
212  friend cls operator&(const cls& a, const cls& b); \
213  ) \
214 public: \
215  \
216  SWIG_BUILD_ONLY( \
217  cls bitwise_or(const cls& b) const \
218  { return *this | b; } \
219  cls bitwise_and(const cls& b) const \
220  { return *this & b; }) \
221  \
222  \
223  \
224  cls operator~() const \
225  { return cls((~inner) & static_cast<ctype>(mask)); } \
226  \
227  \
228  cls &operator&=(const cls &other) \
229  { \
230  inner &= other.inner; \
231  return *this; \
232  } \
233  \
234  \
235  cls &operator|=(const cls &other) \
236  { \
237  inner |= other.inner; \
238  return *this; \
239  } \
240 
241 
242 
243 #define CS_ENUM_BOILERPLATE_FRIENDS_NO_CGLUE(cls) \
244  NOT_SWIG_BUILD_ONLY( \
245  \
246  \
247  \
248  \
249  \
250  inline bool operator==(const cls& a, const cls& b) \
251  { return a.cmp(b) == 0; } \
252  \
253  \
254  \
255  \
256  \
257  \
258  inline bool operator!=(const cls& a, const cls& b) \
259  { return a.cmp(b) != 0; } \
260  \
261  \
262  \
263  \
264  \
265  \
266  inline bool operator<(const cls& a, const cls& b) \
267  { return a.cmp(b) < 0; } \
268  \
269  \
270  \
271  \
272  \
273  \
274  inline bool operator<=(const cls& a, const cls& b) \
275  { return a.cmp(b) <= 0; } \
276  \
277  \
278  \
279  \
280  \
281  \
282  inline bool operator>(const cls& a, const cls& b) \
283  { return a.cmp(b) > 0; } \
284  \
285  \
286  \
287  \
288  \
289  \
290  inline bool operator>=(const cls& a, const cls& b) \
291  { return a.cmp(b) >= 0; } ) \
292 
293 
294 
295 #define CS_ENUM_BOILERPLATE_FRIENDS(cls, friends, cs) \
296  CS_ENUM_BOILERPLATE_FRIENDS_NO_CGLUE(cls) \
297  template <> \
298  class cglue<cls> \
299  { \
300  friends \
301  cglue(); \
302  public: \
303  typedef cls::ctype ctype; \
304  typedef cls type; \
305  CS_CXX_API_CGLUE_ACCESS_MODIFIER: \
306  static type wrap(const ctype &c) \
307  { return type(c); } \
308  static ctype unwrap(const type &c) \
309  { return c.unwrap(); } \
310  }; \
311  CS_ENUM_BOILERPLATE_NONMEMBERS(cls, cs)
312 
313 
314 
315 #define CS_FLAGS_BOILERPLATE_FRIENDS(cls, friends, cs) \
316  NOT_SWIG_BUILD_ONLY( \
317  \
318  \
319  \
320  \
321  \
322  inline bool operator==(const cls& a, const cls& b) \
323  { return a.cmp(b) == 0; } \
324  \
325  \
326  \
327  \
328  \
329  \
330  inline bool operator!=(const cls& a, const cls& b) \
331  { return a.cmp(b) != 0; } \
332  \
333  \
334  \
335  \
336  \
337  \
338  inline bool operator<(const cls& a, const cls& b) \
339  { return a.cmp(b) < 0; } \
340  \
341  \
342  \
343  \
344  \
345  \
346  inline bool operator<=(const cls& a, const cls& b) \
347  { return a.cmp(b) <= 0; } \
348  \
349  \
350  \
351  \
352  \
353 \
354  inline bool operator>(const cls& a, const cls& b) \
355  { return a.cmp(b) > 0; } \
356  \
357  \
358  \
359  \
360  \
361  \
362  inline bool operator>=(const cls& a, const cls& b) \
363  { return a.cmp(b) >= 0; } \
364  ) \
365  NOTSWIG( \
366  \
367  \
368  \
369  \
370  \
371  inline cls operator|(const cls& a, const cls& b) \
372  { return cls(a.inner|b.inner); } \
373  \
374  \
375  \
376  \
377  \
378  \
379  inline cls operator&(const cls& a, const cls& b) \
380  { return cls(a.inner&b.inner); } \
381  ) \
382  template <> \
383  class cglue<cls> \
384  { \
385  friends \
386  cglue(); \
387  public: \
388  typedef cls::ctype ctype; \
389  typedef cls type; \
390  CS_CXX_API_CGLUE_ACCESS_MODIFIER: \
391  static type wrap(const ctype &c) \
392  { return type(c); } \
393  static ctype unwrap(const type &c) \
394  { return c.unwrap(); } \
395  }; \
396  CS_ENUM_BOILERPLATE_NONMEMBERS(cls, cs)
397 
398 /* gcc version 4.4.1 (Ubuntu 4.4.1-4ubuntu8) and gcc 4.2.1 (Apple
399  * Inc. build 5666) (dot 3) generate unexpected code for the bounds
400  * check below in some cases when using -O3. In particular, inside
401  * the swig-generated _wrap_new_procedure_kind function, there is a
402  * call to the procedure_kind constructor:
403  * cs::procedure_kind::ctype arg1 ;
404  * ...
405  * arg1 = static_cast< cs::procedure_kind::ctype >(val1);
406  * try {
407  * result = (cs::procedure_kind *)new cs::procedure_kind(arg1);
408  * }
409  * catch(cs::result &_e) {
410  * ...
411  *
412  * The upper bound (ub) is cs_pdg_kind_count, which is 7.
413  * So the bounds check in the constructor is:
414  * if( !(((size_t)inner) < ((size_t)7)) )
415  * check(CS_ERROR_INVALID_ARGUMENT);
416  *
417  * However, the only valid enumerants are in the range 0 to 7. The
418  * behavior of casting values outside this range to cs::procedure_kind
419  * is unspecified, and the compiler is free to assume that an equality
420  * check is sufficient and correct. The constructor now takes a
421  * size_t parameter and casts it to the enum parallel to the
422  * validity check to avoid unspecified behavior.
423  */
424 
425 #define CS_ENUM_BOILERPLATE_UB(cls, CTYPE, getname, ub) \
426  CS_ENUM_BOILERPLATE(cls, CTYPE, getname, ((csuint64)_inner) < ((csuint64)ub))
427 
428 #define CS_ENUM_BOILERPLATE_UB_NZ(cls, CTYPE, getname, ub) \
429  CS_ENUM_BOILERPLATE(cls, CTYPE, getname, _inner && ((csuint64)_inner) < ((csuint64)ub))
430 
431 #include "cs_result.hpp"
432 
433 #endif /* CS_ENUM_BOILERPLATE_HPP */
Namespace for CodeSonar/CodeSurfer API.
Definition: cs_ast.hpp:33