CBMC
Loading...
Searching...
No Matches
expr_iterator.h
Go to the documentation of this file.
1/*******************************************************************\
2
3Module: exprt iterator module
4
5Author: Diffblue Ltd.
6
7\*******************************************************************/
8
9#ifndef CPROVER_UTIL_EXPR_ITERATOR_H
10#define CPROVER_UTIL_EXPR_ITERATOR_H
11
12#include <deque>
13#include <iterator>
14#include <functional>
15#include <set>
16#include <algorithm>
17#include "expr.h"
18#include "invariant.h"
19
20// Forward declarations - table of contents
21
30
33class depth_iteratort;
42
45{
46 typedef exprt::operandst::const_iterator operands_iteratort;
48 {
49 }
50 std::reference_wrapper<const exprt> expr;
51 std::size_t op_idx;
52};
53
54inline bool operator==(
56 const depth_iterator_expr_statet &right)
57{
58 return left.op_idx == right.op_idx && left.expr.get() == right.expr.get();
59}
60
67template<typename depth_iterator_t>
69{
70public:
71 typedef void difference_type; // NOLINT Required by STL
72 typedef exprt value_type; // NOLINT
73 typedef const exprt *pointer; // NOLINT
74 typedef const exprt &reference; // NOLINT
75 typedef std::forward_iterator_tag iterator_category; // NOLINT
76
77 template <typename other_depth_iterator_t>
79
80 template <typename other_depth_iterator_t>
83 {
84 return m_stack==other.m_stack;
85 }
86
87 template <typename other_depth_iterator_t>
90 {
91 return !(*this == other);
92 }
93
97 {
98 PRECONDITION(!m_stack.empty());
99 while(true)
100 {
101 if(m_stack.back().op_idx == m_stack.back().expr.get().operands().size())
102 {
103 m_stack.pop_back();
104 if(m_stack.empty())
105 break;
106 }
107 // Check eg. if we haven't seen this node before
108 else if(this->downcast().push_expr(
109 m_stack.back().expr.get().operands()[m_stack.back().op_idx]))
110 {
111 break;
112 }
113 ++m_stack.back().op_idx;
114 }
115 return this->downcast();
116 }
117
119 {
120 PRECONDITION(!m_stack.empty());
121 m_stack.pop_back();
122 if(!m_stack.empty())
123 {
124 ++m_stack.back().op_idx;
125 return ++(*this);
126 }
127 return this->downcast();
128 }
129
133 {
135 this->operator++();
136 return tmp;
137 }
138
141 const exprt &operator*() const
142 {
143 PRECONDITION(!m_stack.empty());
144 return m_stack.back().expr.get();
145 }
146
149 const exprt *operator->() const
150 { return &**this; }
151
152protected:
155
157 explicit depth_iterator_baset(const exprt &root)
158 { this->push_expr(root); }
159
163
166 { m_stack=std::move(other.m_stack); }
169 {
170 m_stack = std::move(other.m_stack);
171 return *this;
172 }
173
175 {
176 return m_stack.front().expr.get();
177 }
178
185 {
186 PRECONDITION(!m_stack.empty());
187 // Cast the root expr to non-const
188 exprt *expr = &const_cast<exprt &>(get_root());
189 for(auto &state : m_stack)
190 {
191 // This deliberately breaks sharing as expr is now non-const
192 (void)expr->write();
193 state.expr = *expr;
194 // Get the expr for the next level down to use in the next iteration
195 if(!(state == m_stack.back()))
196 expr = &expr->operands()[state.op_idx];
197 }
198 return *expr;
199 }
200
206 bool push_expr(const exprt &expr)
207 {
208 m_stack.emplace_back(expr);
209 return true;
210 }
211
212private:
213 std::deque<depth_iterator_expr_statet> m_stack;
214
216 { return static_cast<depth_iterator_t &>(*this); }
217};
218
220 public depth_iterator_baset<const_depth_iteratort>
221{
222public:
224 explicit const_depth_iteratort(const exprt &expr):
225 depth_iterator_baset(expr) { }
228};
229
230class depth_iteratort final:
231 public depth_iterator_baset<depth_iteratort>
232{
233private:
236 std::function<exprt &()> mutate_root;
237
238public:
241
246 {
247 }
248
257 const exprt &expr,
258 std::function<exprt &()> mutate_root)
260 {
261 // If you don't provide a mutate_root function then you must pass a
262 // non-const exprt (use the other constructor).
264 }
265
273 {
274 if(mutate_root)
275 {
277 INVARIANT(
278 &new_root.read() == &get_root().read(),
279 "mutate_root must return the same root node that depth_iteratort was "
280 "constructed with");
281 mutate_root = nullptr;
282 }
284 }
285};
286
288 public depth_iterator_baset<const_unique_depth_iteratort>
289{
291public:
293 explicit const_unique_depth_iteratort(const exprt &expr):
295 m_traversed({ expr }) { }
298private:
300 bool push_expr(const exprt &expr) // "override" - hide base class method
301 {
302 const bool inserted=this->m_traversed.insert(expr).second;
303 if(inserted)
305 return inserted;
306 }
307 std::set<exprt> m_traversed;
308};
309
313{
314public:
318
320 {
321 return root.depth_cbegin();
322 }
323
325 {
326 return root.depth_cend();
327 }
328
329protected:
330 const exprt &root;
331};
332
335{
337}
338
343{
344public:
345 typedef void difference_type; // NOLINT Required by STL
346 typedef exprt value_type; // NOLINT
347 typedef const exprt *pointer; // NOLINT
348 typedef const exprt &reference; // NOLINT
349 typedef std::forward_iterator_tag iterator_category; // NOLINT
350
353 explicit const_post_depth_iteratort(const exprt &expr)
354 {
356 }
357
360
361 bool operator==(const const_post_depth_iteratort &other) const
362 {
363 return m_stack == other.m_stack;
364 }
365
366 bool operator!=(const const_post_depth_iteratort &other) const
367 {
368 return !(*this == other);
369 }
370
374 {
375 PRECONDITION(!m_stack.empty());
376
377 // Pop the current node (we've just visited it)
378 m_stack.pop_back();
379
380 if(m_stack.empty())
381 return *this;
382
383 // Move to next sibling
384 ++m_stack.back().op_idx;
385
386 // If there's a next sibling, descend to its leftmost leaf
387 if(m_stack.back().op_idx < m_stack.back().expr.get().operands().size())
388 {
390 m_stack.back().expr.get().operands()[m_stack.back().op_idx]);
391 }
392 // Otherwise, the parent is the next node to visit (already on stack)
393
394 return *this;
395 }
396
400 {
402 ++(*this);
403 return tmp;
404 }
405
408 const exprt &operator*() const
409 {
410 PRECONDITION(!m_stack.empty());
411 return m_stack.back().expr.get();
412 }
413
416 const exprt *operator->() const
417 {
418 return &**this;
419 }
420
421private:
425 {
426 const exprt *current = &expr;
427 while(true)
428 {
429 m_stack.emplace_back(*current);
430 if(current->operands().empty())
431 break;
432 current = &current->operands().front();
433 }
434 }
435
436 std::deque<depth_iterator_expr_statet> m_stack;
437};
438
441{
442public:
444 : root{_root}
445 {
446 }
447
452
457
458protected:
459 const exprt &root;
460};
461
464{
466}
467
468#endif
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Definition ai.h:562
An adapter to yield a range (expected to satisfy C++20 std::ranges::range) of const_depth_iteratort.
const_depth_iteratort begin() const
const_depth_iteratort end() const
const_depth_iterator_range_adaptert(const exprt &_root)
const_depth_iteratort(const exprt &expr)
Create iterator starting at the supplied node (root)
const_depth_iteratort()=default
Create an end iterator.
An adapter to yield a range of const_post_depth_iteratort.
const_post_depth_iteratort end() const
const exprt & root
const_post_depth_iterator_range_adaptert(const exprt &_root)
const_post_depth_iteratort begin() const
Post-order depth-first-search iterator.
bool operator!=(const const_post_depth_iteratort &other) const
void difference_type
void descend_to_leftmost_leaf(const exprt &expr)
Descend from the given expression to its leftmost leaf, pushing all nodes along the path onto the sta...
const exprt & operator*() const
Dereference operator Dereferencing end() iterator is undefined behaviour.
const exprt & reference
const_post_depth_iteratort & operator++()
Preincrement operator Do not call on the end() iterator.
const_post_depth_iteratort operator++(int)
Post-increment operator Expensive copy.
std::deque< depth_iterator_expr_statet > m_stack
const_post_depth_iteratort(const exprt &expr)
Create iterator starting at the supplied node (root).
const_post_depth_iteratort()=default
Create an end iterator.
const exprt * operator->() const
Dereference operator (member access) Dereferencing end() iterator is undefined behaviour.
bool operator==(const const_post_depth_iteratort &other) const
const exprt * pointer
exprt value_type
std::forward_iterator_tag iterator_category
const_unique_depth_iteratort()=default
Create an end iterator.
bool push_expr(const exprt &expr)
Push expression onto the stack and add to the set of traversed exprts.
std::set< exprt > m_traversed
const_unique_depth_iteratort(const exprt &expr)
Create iterator starting at the supplied node (root)
Depth first search iterator base - iterates over supplied expression and all its operands recursively...
depth_iterator_t & next_sibling_or_parent()
depth_iterator_t & operator++()
Preincrement operator Do not call on the end() iterator.
depth_iterator_baset(const depth_iterator_baset &)=default
exprt & mutate()
Obtain non-const exprt reference.
std::deque< depth_iterator_expr_statet > m_stack
depth_iterator_baset & operator=(const depth_iterator_baset &)=default
const exprt * operator->() const
Dereference operator (member access) Dereferencing end() iterator is undefined behaviour.
depth_iterator_baset(const exprt &root)
Create begin iterator, starting at the supplied node.
const exprt & operator*() const
Dereference operator Dereferencing end() iterator is undefined behaviour.
depth_iterator_baset(depth_iterator_baset &&other)
const exprt * pointer
bool operator!=(const depth_iterator_baset< other_depth_iterator_t > &other) const
bool push_expr(const exprt &expr)
Pushes expression onto the stack If overridden, this function should be called from the inheriting cl...
bool operator==(const depth_iterator_baset< other_depth_iterator_t > &other) const
const exprt & get_root()
depth_iterator_t operator++(int)
Post-increment operator Expensive copy.
std::forward_iterator_tag iterator_category
depth_iterator_t & downcast()
const exprt & reference
depth_iterator_baset & operator=(depth_iterator_baset &&other)
~depth_iterator_baset()=default
Destructor Protected to discourage upcasting.
depth_iterator_baset()=default
Create end iterator.
depth_iteratort(const exprt &expr, std::function< exprt &()> mutate_root)
Create iterator starting at the supplied node (root) If mutations of the child nodes are required the...
depth_iteratort(exprt &expr)
Create iterator starting at the supplied node (root) All mutations of the child nodes will be reflect...
exprt & mutate()
Obtain non-const reference to the exprt instance currently pointed to by the iterator.
depth_iteratort()=default
Create an end iterator.
std::function< exprt &()> mutate_root
If this is non-empty then the root is currently const and this function must be called before any mut...
Base class for all expressions.
Definition expr.h:57
operandst & operands()
Definition expr.h:95
dt & write()
Definition irep.h:245
static const_depth_iterator_range_adaptert pre_traversal(const exprt &root)
bool operator==(const depth_iterator_expr_statet &left, const depth_iterator_expr_statet &right)
static const_post_depth_iterator_range_adaptert post_traversal(const exprt &root)
int __CPROVER_ID java::java io InputStream read
Definition java.io.c:5
STL namespace.
#define PRECONDITION(CONDITION)
Definition invariant.h:463
#define INVARIANT(CONDITION, REASON)
This macro uses the wrapper function 'invariant_violated_string'.
Definition invariant.h:423
Helper class for depth_iterator_baset.
std::reference_wrapper< const exprt > expr
depth_iterator_expr_statet(const exprt &expr)
exprt::operandst::const_iterator operands_iteratort