// // Copyright Contributors to the MaterialX Project // SPDX-License-Identifier: Apache-2.0 // #include #include 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()) { 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