mirror of
https://github.com/johndoe6345789/SDL3CPlusPlus.git
synced 2026-04-25 14:15:02 +00:00
237 lines
5.3 KiB
C++
237 lines
5.3 KiB
C++
//
|
|
// Copyright Contributors to the MaterialX Project
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
//
|
|
|
|
#include <MaterialXCore/Traversal.h>
|
|
|
|
#include <MaterialXCore/Node.h>
|
|
|
|
MATERIALX_NAMESPACE_BEGIN
|
|
|
|
const Edge& getNullEdge() {
|
|
static const auto ret = new Edge(nullptr, nullptr, nullptr);
|
|
return *ret;
|
|
}
|
|
|
|
const TreeIterator& getNullTreeIterator() {
|
|
static const auto ret = new TreeIterator(nullptr);
|
|
return *ret;
|
|
}
|
|
const GraphIterator& getNullGraphIterator() {
|
|
static const auto ret = new GraphIterator(nullptr);
|
|
return *ret;
|
|
}
|
|
const InheritanceIterator& getNullInheritanceIterator() {
|
|
static const auto ret = new InheritanceIterator(nullptr);
|
|
return *ret;
|
|
}
|
|
|
|
//
|
|
// Edge methods
|
|
//
|
|
|
|
Edge::operator bool() const
|
|
{
|
|
return *this != getNullEdge();
|
|
}
|
|
|
|
string Edge::getName() const
|
|
{
|
|
return _elemConnect ? _elemConnect->getName() : EMPTY_STRING;
|
|
}
|
|
|
|
//
|
|
// TreeIterator methods
|
|
//
|
|
|
|
const TreeIterator& TreeIterator::end()
|
|
{
|
|
return getNullTreeIterator();
|
|
}
|
|
|
|
TreeIterator& TreeIterator::operator++()
|
|
{
|
|
if (_holdCount)
|
|
{
|
|
_holdCount--;
|
|
return *this;
|
|
}
|
|
|
|
if (!_prune && _elem && !_elem->getChildren().empty())
|
|
{
|
|
// Traverse to the first child of this element.
|
|
_stack.emplace_back(_elem, 0);
|
|
_elem = _elem->getChildren()[0];
|
|
return *this;
|
|
}
|
|
_prune = false;
|
|
|
|
while (true)
|
|
{
|
|
if (_stack.empty())
|
|
{
|
|
// Traversal is complete.
|
|
_elem = ElementPtr();
|
|
return *this;
|
|
}
|
|
|
|
// Traverse to our siblings.
|
|
StackFrame& parentFrame = _stack.back();
|
|
const ElementVec& siblings = parentFrame.first->getChildren();
|
|
if (parentFrame.second + 1 < siblings.size())
|
|
{
|
|
_elem = siblings[++parentFrame.second];
|
|
return *this;
|
|
}
|
|
|
|
// Traverse to our parent's siblings.
|
|
_stack.pop_back();
|
|
}
|
|
}
|
|
|
|
//
|
|
// GraphIterator methods
|
|
//
|
|
|
|
size_t GraphIterator::getNodeDepth() const
|
|
{
|
|
size_t nodeDepth = 0;
|
|
for (ElementPtr elem : _pathElems)
|
|
{
|
|
if (elem->isA<Node>())
|
|
{
|
|
nodeDepth++;
|
|
}
|
|
}
|
|
return nodeDepth;
|
|
}
|
|
|
|
const GraphIterator& GraphIterator::end()
|
|
{
|
|
return getNullGraphIterator();
|
|
}
|
|
|
|
GraphIterator& GraphIterator::operator++()
|
|
{
|
|
if (_holdCount)
|
|
{
|
|
_holdCount--;
|
|
return *this;
|
|
}
|
|
|
|
if (!_prune && _upstreamElem && _upstreamElem->getUpstreamEdgeCount())
|
|
{
|
|
// Traverse to the first upstream edge of this element.
|
|
_stack.emplace_back(_upstreamElem, 0);
|
|
Edge nextEdge = _upstreamElem->getUpstreamEdge(0);
|
|
if (nextEdge && nextEdge.getUpstreamElement() && !skipOrMarkAsVisited(nextEdge))
|
|
{
|
|
extendPathUpstream(nextEdge.getUpstreamElement(), nextEdge.getConnectingElement());
|
|
return *this;
|
|
}
|
|
}
|
|
_prune = false;
|
|
|
|
while (true)
|
|
{
|
|
if (_upstreamElem)
|
|
{
|
|
returnPathDownstream(_upstreamElem);
|
|
}
|
|
|
|
if (_stack.empty())
|
|
{
|
|
// Traversal is complete.
|
|
*this = GraphIterator::end();
|
|
return *this;
|
|
}
|
|
|
|
// Traverse to our siblings.
|
|
StackFrame& parentFrame = _stack.back();
|
|
if (parentFrame.second + 1 < parentFrame.first->getUpstreamEdgeCount())
|
|
{
|
|
Edge nextEdge = parentFrame.first->getUpstreamEdge(++parentFrame.second);
|
|
if (nextEdge && nextEdge.getUpstreamElement() && !skipOrMarkAsVisited(nextEdge))
|
|
{
|
|
extendPathUpstream(nextEdge.getUpstreamElement(), nextEdge.getConnectingElement());
|
|
return *this;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
// Traverse to our parent's siblings.
|
|
returnPathDownstream(parentFrame.first);
|
|
_stack.pop_back();
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
void GraphIterator::extendPathUpstream(ElementPtr upstreamElem, ElementPtr connectingElem)
|
|
{
|
|
// Check for cycles.
|
|
if (_pathElems.count(upstreamElem))
|
|
{
|
|
throw ExceptionFoundCycle("Encountered cycle at element: " + upstreamElem->asString());
|
|
}
|
|
|
|
// Extend the current path to the new element.
|
|
_pathElems.insert(upstreamElem);
|
|
_upstreamElem = upstreamElem;
|
|
_connectingElem = connectingElem;
|
|
}
|
|
|
|
void GraphIterator::returnPathDownstream(ElementPtr upstreamElem)
|
|
{
|
|
_pathElems.erase(upstreamElem);
|
|
_upstreamElem = ElementPtr();
|
|
_connectingElem = ElementPtr();
|
|
}
|
|
|
|
bool GraphIterator::skipOrMarkAsVisited(const Edge& edge)
|
|
{
|
|
auto [it, inserted] = _visitedEdges.emplace(edge);
|
|
return !inserted;
|
|
}
|
|
|
|
//
|
|
// InheritanceIterator methods
|
|
//
|
|
|
|
const InheritanceIterator& InheritanceIterator::end()
|
|
{
|
|
return getNullInheritanceIterator();
|
|
}
|
|
|
|
InheritanceIterator& InheritanceIterator::operator++()
|
|
{
|
|
if (_holdCount)
|
|
{
|
|
_holdCount--;
|
|
return *this;
|
|
}
|
|
|
|
if (_elem)
|
|
{
|
|
ElementPtr super = _elem->getInheritsFrom();
|
|
if (super && super->getCategory() != _elem->getCategory())
|
|
{
|
|
super = nullptr;
|
|
}
|
|
if (super)
|
|
{
|
|
// Check for cycles.
|
|
if (_pathElems.count(super))
|
|
{
|
|
throw ExceptionFoundCycle("Encountered cycle at element: " + super->asString());
|
|
}
|
|
_pathElems.insert(super);
|
|
}
|
|
_elem = super;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
MATERIALX_NAMESPACE_END
|