Change copyrights from Nokia to Digia
[profile/ivi/qtxmlpatterns.git] / src / xmlpatterns / acceltree / qacceliterators_p.h
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtXmlPatterns module of the Qt Toolkit.
7 **
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.
16 **
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.
24 **
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.
28 **
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.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 //
43 //  W A R N I N G
44 //  -------------
45 //
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.
49 //
50 // We mean it.
51
52 #ifndef Patternist_AccelIterators_H
53 #define Patternist_AccelIterators_H
54
55 #include <private/qacceltree_p.h>
56 #include <private/qitem_p.h>
57
58 QT_BEGIN_HEADER
59
60 QT_BEGIN_NAMESPACE
61
62 namespace QPatternist
63 {
64     /**
65      * @short Abstract base class for Iterators for the AccelTree, that
66      * contains common functions and members.
67      *
68      * @author Frans Englich<frans.englich@nokia.com>
69      */
70     class AccelIterator : public QXmlNodeModelIndex::Iterator
71     {
72     public:
73         virtual xsInteger position() const;
74         virtual QXmlNodeModelIndex current() const;
75
76     protected:
77         inline AccelIterator(const AccelTree *const doc,
78                              const AccelTree::PreNumber pre,
79                              const AccelTree::PreNumber currentPre) : m_document(doc)
80                                                                     , m_preNumber(pre)
81                                                                     , m_currentPre(currentPre)
82                                                                     , m_position(0)
83
84         {
85             Q_ASSERT(m_document);
86             Q_ASSERT(m_preNumber >= 0);
87         }
88
89         inline QXmlNodeModelIndex closedExit()
90         {
91             m_position = -1;
92             m_current.reset();
93             return QXmlNodeModelIndex();
94         }
95
96         /**
97          * We do not own it.
98          */
99         const AccelTree *const      m_document;
100
101         /**
102          * The pre number of the node that should be navigated from.
103          */
104         const AccelTree::PreNumber  m_preNumber;
105         AccelTree::PreNumber        m_currentPre;
106         xsInteger                   m_position;
107         QXmlNodeModelIndex          m_current;
108     };
109
110     /**
111      * @short Iterates along the @c ancestor or @c ancestor-or-self axis in an AccelTree.
112      *
113      * @author Frans Englich<frans.englich@nokia.com>
114      */
115     template<const bool IncludeSelf>
116     class AncestorIterator : public AccelIterator
117     {
118     public:
119         /**
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.
124          */
125         inline AncestorIterator(const AccelTree *const doc,
126                                 const AccelTree::PreNumber pre) : AccelIterator(doc, pre, IncludeSelf ? pre : doc->basicData.at(pre).parent())
127         {
128             Q_ASSERT(IncludeSelf || m_document->hasParent(pre));
129         }
130
131         virtual QXmlNodeModelIndex next()
132         {
133             if(m_currentPre == -1)
134                 return closedExit();
135             else
136             {
137                 ++m_position;
138                 m_current = m_document->createIndex(m_currentPre);
139                 m_currentPre = m_document->basicData.at(m_currentPre).parent();
140
141                 return m_current;
142             }
143         }
144
145         virtual QXmlNodeModelIndex::Iterator::Ptr copy() const
146         {
147             return QXmlNodeModelIndex::Iterator::Ptr(new AncestorIterator<IncludeSelf>(m_document, m_preNumber));
148         }
149     };
150
151     /**
152      * @short Iterates along the @c child axis in an AccelTree.
153      *
154      * @author Frans Englich<frans.englich@nokia.com>
155      */
156     class ChildIterator : public AccelIterator
157     {
158     public:
159         /**
160          * @p pre must have at least one child.
161          */
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))
165         {
166             Q_ASSERT(m_document->hasChildren(pre));
167
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)
171             {
172                 ++m_currentPre;
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)
176                 {
177                     m_currentPre = -1;
178                     break;
179                 }
180             }
181         }
182
183         virtual QXmlNodeModelIndex next();
184         virtual QXmlNodeModelIndex::Iterator::Ptr copy() const;
185
186     private:
187         const AccelTree::Depth m_depth;
188     };
189
190     /**
191      * @short Iterates along the sibling axes in an AccelTree.
192      *
193      * @author Frans Englich<frans.englich@nokia.com>
194      */
195     template<const bool IsFollowing>
196     class SiblingIterator : public AccelIterator
197     {
198     public:
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))
202         {
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.");
207         }
208
209         virtual QXmlNodeModelIndex next()
210         {
211             if(m_currentPre == -1)
212                 return QXmlNodeModelIndex();
213
214             if(IsFollowing)
215             {
216                 /* Skip the descendants, and jump to the next node. */
217                 m_currentPre += m_document->size(m_currentPre) + 1;
218
219                 if(m_currentPre > m_document->maximumPreNumber() || m_document->depth(m_currentPre) != m_depth)
220                     return closedExit();
221                 else
222                 {
223                     ++m_position;
224                     m_current = m_document->createIndex(m_currentPre);
225                     return m_current;
226                 }
227             }
228             else
229             {
230                 while(m_document->depth(m_currentPre) > m_depth)
231                     --m_currentPre;
232
233                 while(m_document->kind(m_currentPre) == QXmlNodeModelIndex::Attribute)
234                     --m_currentPre;
235
236                 if(m_document->depth(m_currentPre) == m_depth &&
237                    m_document->kind(m_currentPre) != QXmlNodeModelIndex::Attribute)
238                 {
239                     m_current = m_document->createIndex(m_currentPre);
240                     ++m_position;
241                     --m_currentPre;
242                     return m_current;
243                 }
244                 else
245                 {
246                     m_currentPre = -1;
247                     return closedExit();
248                 }
249             }
250         }
251
252         virtual QXmlNodeModelIndex::Iterator::Ptr copy() const
253         {
254             return QXmlNodeModelIndex::Iterator::Ptr(new SiblingIterator<IsFollowing>(m_document, m_preNumber));
255         }
256
257     private:
258         const AccelTree::Depth m_depth;
259     };
260
261     /**
262      * @short Implements axis @c descendant and @c descendant-or-self for the
263      * AccelTree.
264      *
265      * @author Frans Englich <frans.englich@nokia.com>
266      */
267     template<const bool IncludeSelf>
268     class DescendantIterator : public AccelIterator
269     {
270     public:
271         /**
272          * @p pre must have at least one child.
273          */
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))
277         {
278             Q_ASSERT(IncludeSelf || m_document->hasChildren(pre));
279
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. */
283             if(!IncludeSelf)
284             {
285                 while(m_document->kind(m_currentPre) == QXmlNodeModelIndex::Attribute)
286                 {
287                     ++m_currentPre;
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)
291                     {
292                         m_currentPre = -1;
293                         break;
294                     }
295                 }
296             }
297         }
298
299         virtual QXmlNodeModelIndex next()
300         {
301             if(m_currentPre == -1)
302                 return closedExit();
303
304             ++m_position;
305             m_current = m_document->createIndex(m_currentPre);
306
307             ++m_currentPre;
308
309             if(m_currentPre > m_document->maximumPreNumber())
310             {
311                 m_currentPre = -1;
312                 return m_current;
313             }
314
315             if(m_document->postNumber(m_currentPre) < m_postNumber)
316             {
317                 while(m_document->kind(m_currentPre) == QXmlNodeModelIndex::Attribute)
318                 {
319                     ++m_currentPre;
320                     if(m_currentPre > m_document->maximumPreNumber())
321                     {
322                         m_currentPre = -1;
323                         break;
324                     }
325                 }
326             }
327             else
328                 m_currentPre = -1;
329
330             return m_current;
331         }
332
333         virtual QXmlNodeModelIndex::Iterator::Ptr copy() const
334         {
335             return QXmlNodeModelIndex::Iterator::Ptr(new DescendantIterator<IncludeSelf>(m_document, m_preNumber));
336         }
337
338     private:
339         const AccelTree::PreNumber m_postNumber;
340     };
341
342     /**
343      * @short Implements axis @c following for the AccelTree.
344      *
345      * @author Frans Englich <frans.englich@nokia.com>
346      */
347     class FollowingIterator : public AccelIterator
348     {
349     public:
350         /**
351          * @ pre must have at least one child.
352          */
353         inline FollowingIterator(const AccelTree *const doc,
354                                  const AccelTree::PreNumber pre) : AccelIterator(doc, pre, pre)
355         {
356         }
357
358         virtual QXmlNodeModelIndex next();
359         virtual QXmlNodeModelIndex::Iterator::Ptr copy() const;
360     };
361
362     /**
363      * @short Implements axis @c preceding for the AccelTree.
364      *
365      * @author Frans Englich <frans.englich@nokia.com>
366      */
367     class PrecedingIterator : public AccelIterator
368     {
369     public:
370         /**
371          * @ pre must have at least one child.
372          */
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))
377         {
378         }
379
380         virtual QXmlNodeModelIndex next();
381         virtual QXmlNodeModelIndex::Iterator::Ptr copy() const;
382
383     private:
384         const AccelTree::PreNumber  m_postNumber;
385     };
386
387     /**
388      * @short Implements axis @c attribute for the AccelTree.
389      *
390      * @author Frans Englich <frans.englich@nokia.com>
391      */
392     class AttributeIterator : public AccelIterator
393     {
394     public:
395         /**
396          * @p pre must have at least one child.
397          */
398         inline AttributeIterator(const AccelTree *const doc, const AccelTree::PreNumber pre) : AccelIterator(doc, pre, pre + 1)
399         {
400             Q_ASSERT(m_document->hasChildren(pre));
401             Q_ASSERT(m_document->kind(m_currentPre) == QXmlNodeModelIndex::Attribute);
402         }
403
404         virtual QXmlNodeModelIndex next();
405         virtual QXmlNodeModelIndex::Iterator::Ptr copy() const;
406     };
407 }
408
409 QT_END_NAMESPACE
410
411 QT_END_HEADER
412
413 #endif