/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtXmlPatterns module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ // // W A R N I N G // ------------- // // This file is not part of the Qt API. It exists purely as an // implementation detail. This header file may change from version to // version without notice, or even be removed. // // We mean it. #ifndef Patternist_AccelIterators_H #define Patternist_AccelIterators_H #include #include QT_BEGIN_NAMESPACE namespace QPatternist { /** * @short Abstract base class for Iterators for the AccelTree, that * contains common functions and members. * * @author Frans Englich */ class AccelIterator : public QXmlNodeModelIndex::Iterator { public: virtual xsInteger position() const; virtual QXmlNodeModelIndex current() const; protected: inline AccelIterator(const AccelTree *const doc, const AccelTree::PreNumber pre, const AccelTree::PreNumber currentPre) : m_document(doc) , m_preNumber(pre) , m_currentPre(currentPre) , m_position(0) { Q_ASSERT(m_document); Q_ASSERT(m_preNumber >= 0); } inline QXmlNodeModelIndex closedExit() { m_position = -1; m_current.reset(); return QXmlNodeModelIndex(); } /** * We do not own it. */ const AccelTree *const m_document; /** * The pre number of the node that should be navigated from. */ const AccelTree::PreNumber m_preNumber; AccelTree::PreNumber m_currentPre; xsInteger m_position; QXmlNodeModelIndex m_current; }; /** * @short Iterates along the @c ancestor or @c ancestor-or-self axis in an AccelTree. * * @author Frans Englich */ template class AncestorIterator : public AccelIterator { public: /** * @p pre is the node from which iteration starts * from. In the @c ancestor axis it is excluded, * while in @c ancestor-or-self it is included. @p pre * must have at least one ancestor. */ inline AncestorIterator(const AccelTree *const doc, const AccelTree::PreNumber pre) : AccelIterator(doc, pre, IncludeSelf ? pre : doc->basicData.at(pre).parent()) { Q_ASSERT(IncludeSelf || m_document->hasParent(pre)); } virtual QXmlNodeModelIndex next() { if(m_currentPre == -1) return closedExit(); else { ++m_position; m_current = m_document->createIndex(m_currentPre); m_currentPre = m_document->basicData.at(m_currentPre).parent(); return m_current; } } virtual QXmlNodeModelIndex::Iterator::Ptr copy() const { return QXmlNodeModelIndex::Iterator::Ptr(new AncestorIterator(m_document, m_preNumber)); } }; /** * @short Iterates along the @c child axis in an AccelTree. * * @author Frans Englich */ class ChildIterator : public AccelIterator { public: /** * @p pre must have at least one child. */ inline ChildIterator(const AccelTree *const doc, const AccelTree::PreNumber pre) : AccelIterator(doc, pre, pre + 1), m_depth(m_document->depth(m_currentPre)) { Q_ASSERT(m_document->hasChildren(pre)); /* Skip the attributes, that are children in the pre/post plane, of * the node we're applying the child axis to. */ while(m_document->kind(m_currentPre) == QXmlNodeModelIndex::Attribute) { ++m_currentPre; /* We check the depth here because we would otherwise include * following siblings. */ if(m_currentPre > m_document->maximumPreNumber() || m_document->depth(m_currentPre) != m_depth) { m_currentPre = -1; break; } } } virtual QXmlNodeModelIndex next(); virtual QXmlNodeModelIndex::Iterator::Ptr copy() const; private: const AccelTree::Depth m_depth; }; /** * @short Iterates along the sibling axes in an AccelTree. * * @author Frans Englich */ template class SiblingIterator : public AccelIterator { public: inline SiblingIterator(const AccelTree *const doc, const AccelTree::PreNumber pre) : AccelIterator(doc, pre, pre + (IsFollowing ? 0 : -1)), m_depth(doc->depth(pre)) { Q_ASSERT_X(IsFollowing || pre != 0, "", "When being preceding-sibling, the context node cannot be the first node in the document."); Q_ASSERT_X(!IsFollowing || pre != m_document->maximumPreNumber(), "", "When being following-sibling, the context node cannot be the last node in the document."); } virtual QXmlNodeModelIndex next() { if(m_currentPre == -1) return QXmlNodeModelIndex(); if(IsFollowing) { /* Skip the descendants, and jump to the next node. */ m_currentPre += m_document->size(m_currentPre) + 1; if(m_currentPre > m_document->maximumPreNumber() || m_document->depth(m_currentPre) != m_depth) return closedExit(); else { ++m_position; m_current = m_document->createIndex(m_currentPre); return m_current; } } else { while(m_document->depth(m_currentPre) > m_depth) --m_currentPre; while(m_document->kind(m_currentPre) == QXmlNodeModelIndex::Attribute) --m_currentPre; if(m_document->depth(m_currentPre) == m_depth && m_document->kind(m_currentPre) != QXmlNodeModelIndex::Attribute) { m_current = m_document->createIndex(m_currentPre); ++m_position; --m_currentPre; return m_current; } else { m_currentPre = -1; return closedExit(); } } } virtual QXmlNodeModelIndex::Iterator::Ptr copy() const { return QXmlNodeModelIndex::Iterator::Ptr(new SiblingIterator(m_document, m_preNumber)); } private: const AccelTree::Depth m_depth; }; /** * @short Implements axis @c descendant and @c descendant-or-self for the * AccelTree. * * @author Frans Englich */ template class DescendantIterator : public AccelIterator { public: /** * @p pre must have at least one child. */ inline DescendantIterator(const AccelTree *const doc, const AccelTree::PreNumber pre) : AccelIterator(doc, pre, pre + (IncludeSelf ? 0 : 1)), m_postNumber(doc->postNumber(pre)) { Q_ASSERT(IncludeSelf || m_document->hasChildren(pre)); /* Make sure that m_currentPre is the first node part of this axis. * Since we're not including ourself, advance to the node after our * attributes, if any. */ if(!IncludeSelf) { while(m_document->kind(m_currentPre) == QXmlNodeModelIndex::Attribute) { ++m_currentPre; /* We check the depth here because we would otherwise include * following siblings. */ if(m_currentPre > m_document->maximumPreNumber() || m_document->postNumber(m_currentPre) > m_postNumber) { m_currentPre = -1; break; } } } } virtual QXmlNodeModelIndex next() { if(m_currentPre == -1) return closedExit(); ++m_position; m_current = m_document->createIndex(m_currentPre); ++m_currentPre; if(m_currentPre > m_document->maximumPreNumber()) { m_currentPre = -1; return m_current; } if(m_document->postNumber(m_currentPre) < m_postNumber) { while(m_document->kind(m_currentPre) == QXmlNodeModelIndex::Attribute) { ++m_currentPre; if(m_currentPre > m_document->maximumPreNumber()) { m_currentPre = -1; break; } } } else m_currentPre = -1; return m_current; } virtual QXmlNodeModelIndex::Iterator::Ptr copy() const { return QXmlNodeModelIndex::Iterator::Ptr(new DescendantIterator(m_document, m_preNumber)); } private: const AccelTree::PreNumber m_postNumber; }; /** * @short Implements axis @c following for the AccelTree. * * @author Frans Englich */ class FollowingIterator : public AccelIterator { public: /** * @ pre must have at least one child. */ inline FollowingIterator(const AccelTree *const doc, const AccelTree::PreNumber pre) : AccelIterator(doc, pre, pre) { } virtual QXmlNodeModelIndex next(); virtual QXmlNodeModelIndex::Iterator::Ptr copy() const; }; /** * @short Implements axis @c preceding for the AccelTree. * * @author Frans Englich */ class PrecedingIterator : public AccelIterator { public: /** * @ pre must have at least one child. */ inline PrecedingIterator(const AccelTree *const doc, const AccelTree::PreNumber pre) : AccelIterator(doc, pre, pre - 1 /* currentPre */) , m_postNumber(m_document->postNumber(m_preNumber)) { } virtual QXmlNodeModelIndex next(); virtual QXmlNodeModelIndex::Iterator::Ptr copy() const; private: const AccelTree::PreNumber m_postNumber; }; /** * @short Implements axis @c attribute for the AccelTree. * * @author Frans Englich */ class AttributeIterator : public AccelIterator { public: /** * @p pre must have at least one child. */ inline AttributeIterator(const AccelTree *const doc, const AccelTree::PreNumber pre) : AccelIterator(doc, pre, pre + 1) { Q_ASSERT(m_document->hasChildren(pre)); Q_ASSERT(m_document->kind(m_currentPre) == QXmlNodeModelIndex::Attribute); } virtual QXmlNodeModelIndex next(); virtual QXmlNodeModelIndex::Iterator::Ptr copy() const; }; } QT_END_NAMESPACE #endif