/**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the QtXmlPatterns module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the Technology Preview License Agreement accompanying ** this package. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain ** additional rights. These rights are described in the Nokia Qt LGPL ** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this ** package. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** ** ** ** ** ** ** ** ** $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 "qacceltree_p.h" #include "qitem_p.h" QT_BEGIN_HEADER 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 QT_END_HEADER #endif