Skip to content

Commit 9fdaba2

Browse files
committed
Expr-depth-iterator: use indices not iterators
The iterators are appealing, but are invalidated when an expression is replaced via mutate(), preventing iteration from continuing over the newly altered node.
1 parent 375d583 commit 9fdaba2

File tree

1 file changed

+20
-24
lines changed

1 file changed

+20
-24
lines changed

src/util/expr_iterator.h

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -42,22 +42,20 @@ class const_unique_depth_iteratort;
4242
struct depth_iterator_expr_statet final
4343
{
4444
typedef exprt::operandst::const_iterator operands_iteratort;
45-
inline depth_iterator_expr_statet(
46-
const exprt &expr,
47-
operands_iteratort it,
48-
operands_iteratort end):
49-
expr(expr), it(it), end(end) { }
45+
inline depth_iterator_expr_statet(const exprt &expr) :
46+
expr(expr),
47+
op_idx(0)
48+
{
49+
}
5050
std::reference_wrapper<const exprt> expr;
51-
operands_iteratort it;
52-
operands_iteratort end;
51+
std::size_t op_idx;
5352
};
5453

5554
inline bool operator==(
5655
const depth_iterator_expr_statet &left,
5756
const depth_iterator_expr_statet &right)
5857
{
59-
return distance(left.it, left.end) == distance(right.it, right.end) &&
60-
left.expr.get() == right.expr.get();
58+
return left.op_idx == right.op_idx && left.expr.get() == right.expr.get();
6159
}
6260

6361
/// Depth first search iterator base - iterates over supplied expression
@@ -100,16 +98,21 @@ class depth_iterator_baset
10098
PRECONDITION(!m_stack.empty());
10199
while(true)
102100
{
103-
if(m_stack.back().it==m_stack.back().end)
101+
102+
if(m_stack.back().op_idx == m_stack.back().expr.get().operands().size())
104103
{
105104
m_stack.pop_back();
106105
if(m_stack.empty())
107106
break;
108107
}
109108
// Check eg. if we haven't seen this node before
110-
else if(this->downcast().push_expr(*m_stack.back().it))
109+
else if(
110+
this->downcast().push_expr(
111+
m_stack.back().expr.get().operands()[m_stack.back().op_idx]))
112+
{
111113
break;
112-
m_stack.back().it++;
114+
}
115+
++m_stack.back().op_idx;
113116
}
114117
return this->downcast();
115118
}
@@ -120,7 +123,7 @@ class depth_iterator_baset
120123
m_stack.pop_back();
121124
if(!m_stack.empty())
122125
{
123-
++m_stack.back().it;
126+
++m_stack.back().op_idx;
124127
return ++(*this);
125128
}
126129
return this->downcast();
@@ -185,18 +188,11 @@ class depth_iterator_baset
185188
for(auto &state : m_stack)
186189
{
187190
// This deliberately breaks sharing as expr is now non-const
188-
auto &operands = expr->operands();
189-
// Get iterators into the operands of the new expr corresponding to the
190-
// ones into the operands of the old expr
191-
const auto it = operands.end() - (state.end - state.it);
191+
(void)expr->operands();
192192
state.expr = *expr;
193-
state.it=it;
194-
state.end=operands.end();
195193
// Get the expr for the next level down to use in the next iteration
196-
if(!(state==m_stack.back()))
197-
{
198-
expr = &*it;
199-
}
194+
if(!(state == m_stack.back()))
195+
expr = &const_cast<exprt &>(state.expr.get().operands()[state.op_idx]);
200196
}
201197
return *expr;
202198
}
@@ -208,7 +204,7 @@ class depth_iterator_baset
208204
/// false otherwise. If returning false, child will not be iterated over.
209205
bool push_expr(const exprt &expr)
210206
{
211-
m_stack.emplace_back(expr, expr.operands().begin(), expr.operands().end());
207+
m_stack.emplace_back(expr);
212208
return true;
213209
}
214210

0 commit comments

Comments
 (0)