1 /****************************************************************************
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the QtXmlPatterns module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
40 ****************************************************************************/
46 // This file is not part of the Qt API. It exists purely as an
47 // implementation detail. This header file may change from version to
48 // version without notice, or even be removed.
52 #ifndef Patternist_AccelIterators_H
53 #define Patternist_AccelIterators_H
55 #include <private/qacceltree_p.h>
56 #include <private/qitem_p.h>
65 * @short Abstract base class for Iterators for the AccelTree, that
66 * contains common functions and members.
68 * @author Frans Englich<frans.englich@nokia.com>
70 class AccelIterator : public QXmlNodeModelIndex::Iterator
73 virtual xsInteger position() const;
74 virtual QXmlNodeModelIndex current() const;
77 inline AccelIterator(const AccelTree *const doc,
78 const AccelTree::PreNumber pre,
79 const AccelTree::PreNumber currentPre) : m_document(doc)
81 , m_currentPre(currentPre)
86 Q_ASSERT(m_preNumber >= 0);
89 inline QXmlNodeModelIndex closedExit()
93 return QXmlNodeModelIndex();
99 const AccelTree *const m_document;
102 * The pre number of the node that should be navigated from.
104 const AccelTree::PreNumber m_preNumber;
105 AccelTree::PreNumber m_currentPre;
106 xsInteger m_position;
107 QXmlNodeModelIndex m_current;
111 * @short Iterates along the @c ancestor or @c ancestor-or-self axis in an AccelTree.
113 * @author Frans Englich<frans.englich@nokia.com>
115 template<const bool IncludeSelf>
116 class AncestorIterator : public AccelIterator
120 * @p pre is the node from which iteration starts
121 * from. In the @c ancestor axis it is excluded,
122 * while in @c ancestor-or-self it is included. @p pre
123 * must have at least one ancestor.
125 inline AncestorIterator(const AccelTree *const doc,
126 const AccelTree::PreNumber pre) : AccelIterator(doc, pre, IncludeSelf ? pre : doc->basicData.at(pre).parent())
128 Q_ASSERT(IncludeSelf || m_document->hasParent(pre));
131 virtual QXmlNodeModelIndex next()
133 if(m_currentPre == -1)
138 m_current = m_document->createIndex(m_currentPre);
139 m_currentPre = m_document->basicData.at(m_currentPre).parent();
145 virtual QXmlNodeModelIndex::Iterator::Ptr copy() const
147 return QXmlNodeModelIndex::Iterator::Ptr(new AncestorIterator<IncludeSelf>(m_document, m_preNumber));
152 * @short Iterates along the @c child axis in an AccelTree.
154 * @author Frans Englich<frans.englich@nokia.com>
156 class ChildIterator : public AccelIterator
160 * @p pre must have at least one child.
162 inline ChildIterator(const AccelTree *const doc,
163 const AccelTree::PreNumber pre) : AccelIterator(doc, pre, pre + 1),
164 m_depth(m_document->depth(m_currentPre))
166 Q_ASSERT(m_document->hasChildren(pre));
168 /* Skip the attributes, that are children in the pre/post plane, of
169 * the node we're applying the child axis to. */
170 while(m_document->kind(m_currentPre) == QXmlNodeModelIndex::Attribute)
173 /* We check the depth here because we would otherwise include
174 * following siblings. */
175 if(m_currentPre > m_document->maximumPreNumber() || m_document->depth(m_currentPre) != m_depth)
183 virtual QXmlNodeModelIndex next();
184 virtual QXmlNodeModelIndex::Iterator::Ptr copy() const;
187 const AccelTree::Depth m_depth;
191 * @short Iterates along the sibling axes in an AccelTree.
193 * @author Frans Englich<frans.englich@nokia.com>
195 template<const bool IsFollowing>
196 class SiblingIterator : public AccelIterator
199 inline SiblingIterator(const AccelTree *const doc,
200 const AccelTree::PreNumber pre) : AccelIterator(doc, pre, pre + (IsFollowing ? 0 : -1)),
201 m_depth(doc->depth(pre))
203 Q_ASSERT_X(IsFollowing || pre != 0, "",
204 "When being preceding-sibling, the context node cannot be the first node in the document.");
205 Q_ASSERT_X(!IsFollowing || pre != m_document->maximumPreNumber(), "",
206 "When being following-sibling, the context node cannot be the last node in the document.");
209 virtual QXmlNodeModelIndex next()
211 if(m_currentPre == -1)
212 return QXmlNodeModelIndex();
216 /* Skip the descendants, and jump to the next node. */
217 m_currentPre += m_document->size(m_currentPre) + 1;
219 if(m_currentPre > m_document->maximumPreNumber() || m_document->depth(m_currentPre) != m_depth)
224 m_current = m_document->createIndex(m_currentPre);
230 while(m_document->depth(m_currentPre) > m_depth)
233 while(m_document->kind(m_currentPre) == QXmlNodeModelIndex::Attribute)
236 if(m_document->depth(m_currentPre) == m_depth &&
237 m_document->kind(m_currentPre) != QXmlNodeModelIndex::Attribute)
239 m_current = m_document->createIndex(m_currentPre);
252 virtual QXmlNodeModelIndex::Iterator::Ptr copy() const
254 return QXmlNodeModelIndex::Iterator::Ptr(new SiblingIterator<IsFollowing>(m_document, m_preNumber));
258 const AccelTree::Depth m_depth;
262 * @short Implements axis @c descendant and @c descendant-or-self for the
265 * @author Frans Englich <frans.englich@nokia.com>
267 template<const bool IncludeSelf>
268 class DescendantIterator : public AccelIterator
272 * @p pre must have at least one child.
274 inline DescendantIterator(const AccelTree *const doc,
275 const AccelTree::PreNumber pre) : AccelIterator(doc, pre, pre + (IncludeSelf ? 0 : 1)),
276 m_postNumber(doc->postNumber(pre))
278 Q_ASSERT(IncludeSelf || m_document->hasChildren(pre));
280 /* Make sure that m_currentPre is the first node part of this axis.
281 * Since we're not including ourself, advance to the node after our
282 * attributes, if any. */
285 while(m_document->kind(m_currentPre) == QXmlNodeModelIndex::Attribute)
288 /* We check the depth here because we would otherwise include
289 * following siblings. */
290 if(m_currentPre > m_document->maximumPreNumber() || m_document->postNumber(m_currentPre) > m_postNumber)
299 virtual QXmlNodeModelIndex next()
301 if(m_currentPre == -1)
305 m_current = m_document->createIndex(m_currentPre);
309 if(m_currentPre > m_document->maximumPreNumber())
315 if(m_document->postNumber(m_currentPre) < m_postNumber)
317 while(m_document->kind(m_currentPre) == QXmlNodeModelIndex::Attribute)
320 if(m_currentPre > m_document->maximumPreNumber())
333 virtual QXmlNodeModelIndex::Iterator::Ptr copy() const
335 return QXmlNodeModelIndex::Iterator::Ptr(new DescendantIterator<IncludeSelf>(m_document, m_preNumber));
339 const AccelTree::PreNumber m_postNumber;
343 * @short Implements axis @c following for the AccelTree.
345 * @author Frans Englich <frans.englich@nokia.com>
347 class FollowingIterator : public AccelIterator
351 * @ pre must have at least one child.
353 inline FollowingIterator(const AccelTree *const doc,
354 const AccelTree::PreNumber pre) : AccelIterator(doc, pre, pre)
358 virtual QXmlNodeModelIndex next();
359 virtual QXmlNodeModelIndex::Iterator::Ptr copy() const;
363 * @short Implements axis @c preceding for the AccelTree.
365 * @author Frans Englich <frans.englich@nokia.com>
367 class PrecedingIterator : public AccelIterator
371 * @ pre must have at least one child.
373 inline PrecedingIterator(const AccelTree *const doc,
374 const AccelTree::PreNumber pre) : AccelIterator(doc, pre,
375 pre - 1 /* currentPre */)
376 , m_postNumber(m_document->postNumber(m_preNumber))
380 virtual QXmlNodeModelIndex next();
381 virtual QXmlNodeModelIndex::Iterator::Ptr copy() const;
384 const AccelTree::PreNumber m_postNumber;
388 * @short Implements axis @c attribute for the AccelTree.
390 * @author Frans Englich <frans.englich@nokia.com>
392 class AttributeIterator : public AccelIterator
396 * @p pre must have at least one child.
398 inline AttributeIterator(const AccelTree *const doc, const AccelTree::PreNumber pre) : AccelIterator(doc, pre, pre + 1)
400 Q_ASSERT(m_document->hasChildren(pre));
401 Q_ASSERT(m_document->kind(m_currentPre) == QXmlNodeModelIndex::Attribute);
404 virtual QXmlNodeModelIndex next();
405 virtual QXmlNodeModelIndex::Iterator::Ptr copy() const;