CodeSonar C++ API
[For improved navigation, enable JavaScript.]
cs_iterator_adapter.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_ITERATOR_ADAPTER_HPP
17 #define CS_ITERATOR_ADAPTER_HPP
18 
19 /* Adapter for creating STL-style iterators from cs C API style
20  * iterators.
21  */
22 
23 #include "cs_result.h"
24 #include "cs_basic_types.h"
25 #include "cs_result.hpp"
26 
29 namespace cs{
30 
35  template<typename policy> class iterator_adapter_mixin
36  {
37  protected:
38  iterator_adapter_mixin(){}
39  };
40 
41 #ifndef CS_TEST_ITERATOR_ADAPTER_COUPLING
42  template<typename elt> class mutable_set;
43  template<typename elt> class immutable_set;
45  template<typename T> class metric_manager;
47  template<typename T> class metricclass_manager;
48  class point;
49  class symbol;
50  class basic_block;
51  class edge_label;
52  class pdg_edge_label;
53  class pdg_edge_kind;
54  class project;
55  class compunit;
56  class procedure;
57  class sfileinst;
58  class sfile;
59 #endif
60 
64  template <typename policy>
65  class iterator_adapter: public cs::iterator_adapter_mixin<policy>
66  {
67  friend class iterator_adapter_mixin<policy>;
69  /* bridging the STL-style iterator with the first/next
70  * interface turned out ugly.
71  */
72  typedef typename cglue<typename policy::key>::ctype ckey;
76  typedef typename policy::key value_type;
77  size_t position;
78  /* This has to be a pointer for swap to work */
79  mutable typename policy::iterator_impl *inner;
80  /* This type should be a POD type, so we shouldn't run into
81  * default ctor issues when we leave it uninitialized.
82  */
83  mutable cs_result last_r;
84  /* EMPTY: The empty iterator, always "at_end()"
85  * SINGLETON: Iterates over one value then finishes
86  * INIT: Normal iterator, but hasn't actually started iterating yet
87  * LAGGING: Has started iterating, but will need to invoke the
88  * "next" function in order to get the current element.
89  * LIVE: The current element is stashed in pending
90  */
91 #ifndef SWIG
92  mutable enum state_enum{EMPTY, SINGLETON, LAGGING, LIVE, INIT, INIT_LAGGING} state;
93 #endif
94  mutable ckey pending;
95 
97  typename policy::ctype *container;
99  private:
100  void fetch(bool first) const
101  {
102  if( first )
103  {
104  assert( !inner );
105  inner = new typename policy::iterator_impl;
106  last_r = policy::iter_first(*container, &pending, inner);
107  }
108  else
109  {
110  last_r = policy::iter_next(*container, &pending, inner);
111  }
112  }
113 
114  void wake_up() const
115  {
116  state = LAGGING;
117  for( size_t i = 0; i < position; i++ )
118  {
119  fetch( i == 0 );
120  if( last_r != CS_SUCCESS )
121  return;
122  }
123  }
124 
125  void catch_up() const
126  {
127  if( state == INIT || state == INIT_LAGGING )
128  wake_up();
129  if( state == LAGGING )
130  {
131  state = LIVE;
132  fetch( position == 0 );
133  }
134  }
135 
136  /* I have intentionally not defined the postfix ++ operator
137  * since copying these iterators is so expensive.
138  */
139  iterator_adapter operator++(int unused);
140 #ifdef SWIG
141  iterator_adapter();
142 #endif
143  public:
145  typedef value_type *pointer;
146 
148  typedef const value_type *const_pointer;
149 
151  typedef value_type &reference;
152 
154  typedef const value_type &const_reference;
155 
157  typedef std::forward_iterator_tag iterator_category;
158 
159  private:
160  typedef typename policy::ctype container_type;
161 
162  public:
163 
165  typedef cs_ssize_t difference_type;
166 
167  /* Start in an "INIT" state so that any initial copy
168  * constructor calls are cheap.
169  */
170 #ifndef SWIG
171 #ifndef CS_TEST_ITERATOR_ADAPTER_COUPLING
172  /* These classes need to be able to invoke the next three
173  * constructors, but user code shouldn't be able to do that.
174  * So be friends with the classes that should be able to
175  * construct us. We could use a client-attourney pattern here
176  * to avoid giving full access to all these classes, but I
177  * worry about stupid compilers not doing RVO. You can define
178  * CS_TEST_ITERATOR_ADAPTER_COUPLING to check if any private
179  * fields are being inappropriately accessed by API code.
180  */
181  private:
182  friend class sfileinst_color_map_iterator_policy;
183  friend class ast_iterator_policy;
184  friend class sfileinst_children_iterator_policy;
185  friend class sfileinst;
186  friend class ast;
187  friend class procedure;
188  friend class sfile;
189  friend class project;
190  friend class compunit;
191  friend class directory;
192  friend class amc;
193  friend class amc_analysis;
194  friend class point;
195  friend class symbol;
196  template <typename T>
197  friend class mutable_set;
198  template <typename T>
199  friend class immutable_set;
200  template <typename T>
201  friend class metric_manager;
202  template <typename T>
203  friend class metricclass_manager;
204 #endif
205  iterator_adapter(const container_type &s)
206  : position(0)
207  , inner(NULL)
208  , last_r(CS_SUCCESS)
209  , state(INIT)
210  , container(new container_type(s))
211  {
212  }
213  iterator_adapter()
214  : position(0)
215  , inner(NULL)
216  , last_r(CS_OUT_OF_ELEMENTS)
217  , state(EMPTY)
218  , container(NULL)
219  {
220  }
221  iterator_adapter(const ckey &value)
222  : position(0)
223  , inner(NULL)
224  , last_r(CS_SUCCESS)
225  , state(SINGLETON)
226  , pending(value)
227  , container(NULL)
228  {
229  }
230  public:
231  /* The C iterators don't really offer up an interface that
232  * supports this well, so we end up doing something fairly
233  * ugly. We create a second iterator and then advance it the
234  * appropriate number of times, assuming determinism.
235  */
237  iterator_adapter(const iterator_adapter &other)
238  : position(other.position)
239  , inner(NULL)
240  , last_r(other.last_r)
241  , state(other.state)
242  , pending(other.pending)
243  , container(NULL)
244  {
245  if( state == LIVE )
246  state = INIT;
247  else if( state == LAGGING )
248  state = INIT_LAGGING;
249  if( other.container )
250  container = new container_type(*other.container);
251  }
252 #endif
253  ~iterator_adapter()
254  {
255  if( inner )
256  {
257  policy::iter_close(inner);
258  delete inner;
259  }
260  if( container )
261  delete container;
262  }
263 
270  bool at_end() const
271  {
272  /* If state is INIT and position != 0, then last_r is
273  * dependable.
274  */
275  if( state != INIT || position == 0 )
276  catch_up();
277  return ( last_r == CS_OUT_OF_ELEMENTS );
278  }
279 
281  void swap(iterator_adapter &other)
282  {
283  std::swap(inner, other.inner);
284  std::swap(pending, other.pending);
285  std::swap(last_r, other.last_r);
286  std::swap(state, other.state);
287  std::swap(position, other.position);
288  std::swap(container, other.container);
289  }
290 
297  iterator_adapter&
298  operator=(iterator_adapter other)
299  {
300  swap(other);
301  return *this;
302  }
303 
304 #if !defined(SWIGPYTHON) || !defined(SWIG)
305 
327  typename policy::key operator *() const
328  {
329  catch_up();
330  check(last_r);
331  return value_type::;
332  }
333 #endif
334 
341  bool operator ==(const iterator_adapter& other) const
342  {
343  /* The most important thing to get right is that they are
344  * equal if they are both at the end.
345  */
346  if( at_end() )
347  return other.at_end();
348  if( other.at_end() )
349  return false;
350  state_enum s1 = state;
351  state_enum s2 = other.state;
352  if( s1 != EMPTY && s1 != SINGLETON )
353  s1 = LIVE;
354  if( s2 != EMPTY && s2 != SINGLETON )
355  s2 = LIVE;
356  return s1 == s2
357  && position == other.position;
358  }
359 
368  bool operator !=(const iterator_adapter& other) const
369  { return !(*this == other); }
370 
371 #if !defined(SWIGPYTHON) || !defined(SWIG)
372 
376  void advance()
377  {
378  catch_up();
379  if( last_r == CS_OUT_OF_ELEMENTS )
380  return;
381  if( state == SINGLETON )
382  last_r = CS_OUT_OF_ELEMENTS;
383  else
384  {
385  assert( state == LIVE );
386  check(last_r);
387  state = LAGGING;
388  }
389  position++;
390  }
391 #endif
392 
393 #ifndef SWIG
394  /* I think SWIG will happily assume this returns a brand new
395  * instance, and then cause use after free issues later.
396  */
397 
403  iterator_adapter& operator++()
404  {
405  advance();
406  return *this;
407  }
408 #endif
409 
410 #if defined(SWIGPYTHON) && defined(SWIG)
411  /* SWIG has some trouble understanding the return type of next
412  * if we implement these using %extend... so do this. */
413  %extend{
414  /* Do this in python so swig doesn't get confused about
415  * ownership...
416  */
417  %pythoncode{
418  def __iter__(self): return self }
419  }
420 
421  %extend{
422  policy::key __next__()
423  {
424  try{
425  policy::key rv(**$self); /* this line may throw */
426  $self->advance();
427  return rv;
428  } catch(cs::result r) {
429  if( r == cs::result::OUT_OF_ELEMENTS )
430  /* python needs this instead */
431  throw swig::stop_iteration();
432  throw;
433  }
434  }
435  }
436 #endif
437  private:
438  std::string state_string() const
439  {
440  switch( state )
441  {
442  case SINGLETON:
443  return " singleton";
444  case EMPTY:
445  return " end";
446  default:
447  if( position == 0 )
448  return " begin";
449  return "";
450  }
451  }
452  public:
457  std::string as_string() const
458  {
459  return CS_AS_REPR_PREFIX
460  + std::string(policy::name())
461  + state_string()
462  + CS_AS_REPR_SUFFIX;
463  }
464 
470  std::string as_repr() const
471  { return as_string(); }
472  };
473 
485  template<typename policy>
486  inline std::ostream &operator<<(
487  std::ostream &out,
488  const iterator_adapter<policy> &a )
489  { return out << a.as_string(); }
490 
491 }
492 
493 namespace std{
494  template<typename _Policy>
495  inline void
496  swap(cs::iterator_adapter<_Policy>& __x, cs::iterator_adapter<_Policy>& __y)
497  { __x.swap(__y); }
498 }
499 
500 #endif /* CS_ITERATOR_ADAPTER_HPP */
Denotes the conditions under which control can flow along an edge: a component of a cfg_edge...
Definition: cs_edge_label.hpp:57
cs::iterator_adapter::operator++
iterator_adapter & operator++()
Advance the iterator.
Definition: cs_iterator_adapter.hpp:403
cs::ast_iterator_policy
Definition: cs_ast_decl.hpp:795
cs::iterator_adapter::operator=
iterator_adapter & operator=(iterator_adapter other)
Iterator assignment operator.
Definition: cs_iterator_adapter.hpp:298
Namespace for CodeSonar/CodeSurfer API.
Definition: cs_ast.hpp:33
cs::iterator_adapter::operator<<
std::ostream & operator<<(std::ostream &out, const iterator_adapter< policy > &a)
Print a representation of an iterator_adapter object to the specified stream.
Definition: cs_iterator_adapter.hpp:486
cs::iterator_adapter::advance
void advance()
Advance the iterator by one position.
Definition: cs_iterator_adapter.hpp:376
A CodeSonar or CodeSurfer project.
Definition: cs_project.hpp:392
A function or variable.
Definition: cs_symbol_decl.hpp:243
cs::iterator_adapter::operator*
policy::key operator*() const
Iterator dereference operator.
Definition: cs_iterator_adapter.hpp:327
std
Definition: cs_ast_decl.hpp:67
A single program point.
Definition: cs_point_decl.hpp:66
A directory.
Definition: cs_directory_decl.hpp:91
An Abstract Syntax Tree (AST).
Definition: cs_ast_decl.hpp:448
cs::iterator_adapter::swap
void swap(iterator_adapter &other)
Exchange the contents of this and other.
Definition: cs_iterator_adapter.hpp:281
A single procedure/function/method.
Definition: cs_procedure_decl.hpp:173
cs::iterator_adapter::at_end
bool at_end() const
Check: is the iterator at the end of the structure?
Definition: cs_iterator_adapter.hpp:270
cs::iterator_adapter_mixin
Iterator class template.
Definition: cs_iterator_adapter.hpp:35
cs::metricclass_manager
Manages the metric classes of granularity T (metricclass<T>) for an analysis.
Definition: cs_iterator_adapter.hpp:47
static const result OUT_OF_ELEMENTS
An iterator ran out of elements.
Definition: cs_result.hpp:26
cs::iterator_adapter::operator!=
bool operator!=(const iterator_adapter &other) const
Iterator inequality.
Definition: cs_iterator_adapter.hpp:368
cs::iterator_adapter::operator==
bool operator==(const iterator_adapter &other) const
Iterator equality.
Definition: cs_iterator_adapter.hpp:341
static const point_syntax_element INIT
A for loop initialization clause (kind point_syntax_kind::FOR) or catch clause formal parameter (...
Definition: cs_point_syntax_element_decls.hpp:25
cs::iterator_adapter::const_reference
const value_type & const_reference
const reference to the type of the iterator elements.
Definition: cs_iterator_adapter.hpp:154
A source file.
Definition: cs_sfile_decl.hpp:98
The result of an API operation.
Definition: cs_result.hpp:50
cs::iterator_adapter::reference
value_type & reference
Reference to the type of the iterator elements.
Definition: cs_iterator_adapter.hpp:151
cs::iterator_adapter::const_pointer
const value_type * const_pointer
const pointer to the type of the iterator elements.
Definition: cs_iterator_adapter.hpp:148
cs::iterator_adapter::iterator_adapter
iterator_adapter(const iterator_adapter &other)
Copy constructor.
Definition: cs_iterator_adapter.hpp:237
cs::mutable_set
A set that can be modified.
Definition: cs_iterator_adapter.hpp:42
cs::iterator_adapter::as_string
std::string as_string() const
Get a simple string representation of the iterator.
Definition: cs_iterator_adapter.hpp:457
cs::iterator_adapter::as_repr
std::string as_repr() const
Get a representation of the iterator that includes information useful for debugging.
Definition: cs_iterator_adapter.hpp:470
A source file instance.
Definition: cs_sfileinst_decl.hpp:302
cs::iterator_adapter::iterator_category
std::forward_iterator_tag iterator_category
Iterator is a ForwardIterator.
Definition: cs_iterator_adapter.hpp:157
cs::iterator_adapter
Iterator class template.
Definition: cs_iterator_adapter.hpp:65
cs::iterator_adapter::difference_type
cs_ssize_t difference_type
Type of distance between iterators.
Definition: cs_iterator_adapter.hpp:165
A compilation unit.
Definition: cs_compunit_decl.hpp:70
cs::sfileinst_children_iterator_policy
Definition: cs_sfileinst_decl.hpp:62
cs::sfileinst_color_map_iterator_policy
Definition: cs_sfileinst_decl.hpp:109
cs::immutable_set
A set that cannot be modified.
Definition: cs_iterator_adapter.hpp:43
cs::iterator_adapter::pointer
value_type * pointer
Pointer to the type of the iterator elements.
Definition: cs_iterator_adapter.hpp:145