cvc5-cvc5-1.2.0.src.expr.node_traversal.cpp Maven / Gradle / Ivy
The newest version!
/******************************************************************************
* Top contributors (to current version):
* Alex Ozdemir, Andres Noetzli
*
* This file is part of the cvc5 project.
*
* Copyright (c) 2009-2024 by the authors listed in the file AUTHORS
* in the top-level source directory and their institutional affiliations.
* All rights reserved. See the file COPYING in the top-level source
* directory for licensing information.
* ****************************************************************************
*
* Iterators for traversing nodes.
*/
#include "node_traversal.h"
#include
namespace cvc5::internal {
NodeDfsIterator::NodeDfsIterator(TNode n,
VisitOrder order,
std::function skipIf)
: d_stack{n},
d_visited(),
d_order(order),
d_current(TNode()),
d_skipIf(skipIf)
{
}
NodeDfsIterator::NodeDfsIterator(VisitOrder order)
: d_stack(),
d_visited(),
d_order(order),
d_current(TNode()),
d_skipIf([](TNode) { return false; })
{
}
NodeDfsIterator& NodeDfsIterator::operator++()
{
// If we were just constructed, advance to first visit, **before**
// advancing past it to the next visit (below).
initializeIfUninitialized();
// Advance to the next visit
advanceToNextVisit();
return *this;
}
NodeDfsIterator NodeDfsIterator::operator++(int)
{
NodeDfsIterator copyOfOld(*this);
++*this;
return copyOfOld;
}
TNode& NodeDfsIterator::operator*()
{
// If we were just constructed, advance to first visit
initializeIfUninitialized();
Assert(!d_current.isNull());
return d_current;
}
bool NodeDfsIterator::operator==(NodeDfsIterator& other)
{
// Unitialize this node, and the other, before comparing.
initializeIfUninitialized();
other.initializeIfUninitialized();
// The stack and current node uniquely represent traversal state. We need not
// use the scheduled node set.
//
// Users should not compare iterators for traversals of different nodes, or
// traversals with different skipIfs.
Assert(d_order == other.d_order);
return d_stack == other.d_stack && d_current == other.d_current;
}
bool NodeDfsIterator::operator!=(NodeDfsIterator& other)
{
return !(*this == other);
}
void NodeDfsIterator::advanceToNextVisit()
{
// While a node is enqueued and we're not at the right visit type
while (!d_stack.empty())
{
TNode back = d_stack.back();
auto visitEntry = d_visited.find(back);
if (visitEntry == d_visited.end())
{
// if we haven't pre-visited this node, pre-visit it
if (d_skipIf(back))
{
// actually, skip it if the skip predicate says so...
d_stack.pop_back();
continue;
}
d_visited[back] = false;
d_current = back;
// Use integer underflow to reverse-iterate
for (size_t n = back.getNumChildren(), i = n - 1; i < n; --i)
{
d_stack.push_back(back[i]);
}
if (d_order == VisitOrder::PREORDER)
{
return;
}
}
else if (d_order == VisitOrder::PREORDER || visitEntry->second)
{
// if we're previsiting or we've already post-visited this node: skip it
d_stack.pop_back();
}
else
{
// otherwise, this is a post-visit
visitEntry->second = true;
d_current = back;
d_stack.pop_back();
return;
}
}
// We're at the end of the traversal: nullify the current node to agree
// with the "end" iterator.
d_current = TNode();
}
void NodeDfsIterator::initializeIfUninitialized()
{
if (d_current.isNull())
{
advanceToNextVisit();
}
}
NodeDfsIterable::NodeDfsIterable(TNode n,
VisitOrder order,
std::function skipIf)
: d_node(n), d_order(order), d_skipIf(skipIf)
{
}
NodeDfsIterator NodeDfsIterable::begin() const
{
return NodeDfsIterator(d_node, d_order, d_skipIf);
}
NodeDfsIterator NodeDfsIterable::end() const
{
return NodeDfsIterator(d_order);
}
} // namespace cvc5::internal