1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
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 The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 //
41 //  W A R N I N G
42 //  -------------
43 //
44 // This file is not part of the Qt API.  It exists purely as an
45 // implementation detail.  This header file may change from version to
46 // version without notice, or even be removed.
47 //
48 // We mean it.
49 
50 #ifndef Patternist_OperandsIterator_H
51 #define Patternist_OperandsIterator_H
52 
53 #include <QPair>
54 #include <QStack>
55 
56 #include <private/qexpression_p.h>
57 
58 QT_BEGIN_NAMESPACE
59 
60 namespace QPatternist
61 {
62     /**
63      * @short A helper class that iterates a tree of Expression instances. It
64      * is not a sub-class of QAbstractXmlForwardIterator.
65      *
66      * The OperandsIterator delivers all Expression instances that are children at any
67      * depth of the Expression passed in the constructor.
68      * The order is delivered in a defined way, from left to right and depth
69      * first.
70      *
71      * @author Frans Englich <frans.englich@nokia.com>
72      */
73     class OperandsIterator
74     {
75         /**
76          * The second value, the int, is the current position in the first.
77          */
78         typedef QPair<Expression::List, int> Level;
79 
80     public:
81         enum TreatParent
82         {
83             ExcludeParent,
84             IncludeParent
85         };
86 
87         /**
88          * if @p treatParent is @c IncludeParent, @p start is excluded.
89          *
90          * @p start must be a valid Expression.
91          */
OperandsIterator(const Expression::Ptr & start,const TreatParent treatParent)92         inline OperandsIterator(const Expression::Ptr &start,
93                                 const TreatParent treatParent)
94         {
95             Q_ASSERT(start);
96             if(treatParent == IncludeParent)
97             {
98                 Expression::List l;
99                 l.append(start);
100                 m_exprs.push(qMakePair(l, -1));
101             }
102 
103             m_exprs.push(qMakePair(start->operands(), -1));
104         }
105 
106         /**
107          * @short Returns the current Expression and advances the iterator.
108          *
109          * If the end has been reached, a default constructed pointer is
110          * returned.
111          *
112          * We intentionally return by reference.
113          */
next()114         inline Expression::Ptr next()
115         {
116             if(m_exprs.isEmpty())
117                 return Expression::Ptr();
118 
119             Level &lvl = m_exprs.top();
120             ++lvl.second;
121 
122             if(lvl.second == lvl.first.size())
123             {
124                 /* Resume iteration above us. */
125                 m_exprs.pop();
126 
127                 if(m_exprs.isEmpty())
128                     return Expression::Ptr();
129 
130                 while(true)
131                 {
132                     Level &previous = m_exprs.top();
133                     ++previous.second;
134 
135                     if(previous.second < previous.first.count())
136                     {
137                         const Expression::Ptr &op = previous.first.at(previous.second);
138                         m_exprs.push(qMakePair(op->operands(), -1));
139                         return op;
140                     }
141                     else
142                     {
143                         // We have already reached the end of this level.
144                         m_exprs.pop();
145                         if(m_exprs.isEmpty())
146                             return Expression::Ptr();
147                     }
148                 }
149             }
150             else
151             {
152                 const Expression::Ptr &op = lvl.first.at(lvl.second);
153                 m_exprs.push(qMakePair(op->operands(), -1));
154                 return op;
155             }
156         }
157 
158         /**
159          * Advances this iterator by the current expression and its operands.
160          */
skipOperands()161         Expression::Ptr skipOperands()
162         {
163             if(m_exprs.isEmpty())
164                 return Expression::Ptr();
165 
166             Level &lvl = m_exprs.top();
167             ++lvl.second;
168 
169             if(lvl.second == lvl.first.size())
170             {
171                 /* We've reached the end of this level, at least. */
172                 m_exprs.pop();
173             }
174 
175             return next();
176         }
177 
178     private:
179         Q_DISABLE_COPY(OperandsIterator)
180 
181         QStack<Level> m_exprs;
182     };
183 }
184 
185 
186 QT_END_NAMESPACE
187 
188 #endif
189