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_AccelIterators_H 51 #define Patternist_AccelIterators_H 52 53 #include <private/qacceltree_p.h> 54 #include <private/qitem_p.h> 55 56 QT_BEGIN_NAMESPACE 57 58 namespace QPatternist 59 { 60 /** 61 * @short Abstract base class for Iterators for the AccelTree, that 62 * contains common functions and members. 63 * 64 * @author Frans Englich<frans.englich@nokia.com> 65 */ 66 class AccelIterator : public QXmlNodeModelIndex::Iterator 67 { 68 public: 69 virtual xsInteger position() const; 70 virtual QXmlNodeModelIndex current() const; 71 72 protected: AccelIterator(const AccelTree * const doc,const AccelTree::PreNumber pre,const AccelTree::PreNumber currentPre)73 inline AccelIterator(const AccelTree *const doc, 74 const AccelTree::PreNumber pre, 75 const AccelTree::PreNumber currentPre) : m_document(doc) 76 , m_preNumber(pre) 77 , m_currentPre(currentPre) 78 , m_position(0) 79 80 { 81 Q_ASSERT(m_document); 82 Q_ASSERT(m_preNumber >= 0); 83 } 84 closedExit()85 inline QXmlNodeModelIndex closedExit() 86 { 87 m_position = -1; 88 m_current.reset(); 89 return QXmlNodeModelIndex(); 90 } 91 92 /** 93 * We do not own it. 94 */ 95 const AccelTree *const m_document; 96 97 /** 98 * The pre number of the node that should be navigated from. 99 */ 100 const AccelTree::PreNumber m_preNumber; 101 AccelTree::PreNumber m_currentPre; 102 xsInteger m_position; 103 QXmlNodeModelIndex m_current; 104 }; 105 106 /** 107 * @short Iterates along the @c ancestor or @c ancestor-or-self axis in an AccelTree. 108 * 109 * @author Frans Englich<frans.englich@nokia.com> 110 */ 111 template<const bool IncludeSelf> 112 class AncestorIterator : public AccelIterator 113 { 114 public: 115 /** 116 * @p pre is the node from which iteration starts 117 * from. In the @c ancestor axis it is excluded, 118 * while in @c ancestor-or-self it is included. @p pre 119 * must have at least one ancestor. 120 */ AncestorIterator(const AccelTree * const doc,const AccelTree::PreNumber pre)121 inline AncestorIterator(const AccelTree *const doc, 122 const AccelTree::PreNumber pre) : AccelIterator(doc, pre, IncludeSelf ? pre : doc->basicData.at(pre).parent()) 123 { 124 Q_ASSERT(IncludeSelf || m_document->hasParent(pre)); 125 } 126 next()127 virtual QXmlNodeModelIndex next() 128 { 129 if(m_currentPre == -1) 130 return closedExit(); 131 else 132 { 133 ++m_position; 134 m_current = m_document->createIndex(m_currentPre); 135 m_currentPre = m_document->basicData.at(m_currentPre).parent(); 136 137 return m_current; 138 } 139 } 140 copy()141 virtual QXmlNodeModelIndex::Iterator::Ptr copy() const 142 { 143 return QXmlNodeModelIndex::Iterator::Ptr(new AncestorIterator<IncludeSelf>(m_document, m_preNumber)); 144 } 145 }; 146 147 /** 148 * @short Iterates along the @c child axis in an AccelTree. 149 * 150 * @author Frans Englich<frans.englich@nokia.com> 151 */ 152 class ChildIterator : public AccelIterator 153 { 154 public: 155 /** 156 * @p pre must have at least one child. 157 */ ChildIterator(const AccelTree * const doc,const AccelTree::PreNumber pre)158 inline ChildIterator(const AccelTree *const doc, 159 const AccelTree::PreNumber pre) : AccelIterator(doc, pre, pre + 1), 160 m_depth(m_document->depth(m_currentPre)) 161 { 162 Q_ASSERT(m_document->hasChildren(pre)); 163 164 /* Skip the attributes, that are children in the pre/post plane, of 165 * the node we're applying the child axis to. */ 166 while(m_document->kind(m_currentPre) == QXmlNodeModelIndex::Attribute) 167 { 168 ++m_currentPre; 169 /* We check the depth here because we would otherwise include 170 * following siblings. */ 171 if(m_currentPre > m_document->maximumPreNumber() || m_document->depth(m_currentPre) != m_depth) 172 { 173 m_currentPre = -1; 174 break; 175 } 176 } 177 } 178 179 virtual QXmlNodeModelIndex next(); 180 virtual QXmlNodeModelIndex::Iterator::Ptr copy() const; 181 182 private: 183 const AccelTree::Depth m_depth; 184 }; 185 186 /** 187 * @short Iterates along the sibling axes in an AccelTree. 188 * 189 * @author Frans Englich<frans.englich@nokia.com> 190 */ 191 template<const bool IsFollowing> 192 class SiblingIterator : public AccelIterator 193 { 194 public: SiblingIterator(const AccelTree * const doc,const AccelTree::PreNumber pre)195 inline SiblingIterator(const AccelTree *const doc, 196 const AccelTree::PreNumber pre) : AccelIterator(doc, pre, pre + (IsFollowing ? 0 : -1)), 197 m_depth(doc->depth(pre)) 198 { 199 Q_ASSERT_X(IsFollowing || pre != 0, "", 200 "When being preceding-sibling, the context node cannot be the first node in the document."); 201 Q_ASSERT_X(!IsFollowing || pre != m_document->maximumPreNumber(), "", 202 "When being following-sibling, the context node cannot be the last node in the document."); 203 } 204 next()205 virtual QXmlNodeModelIndex next() 206 { 207 if(m_currentPre == -1) 208 return QXmlNodeModelIndex(); 209 210 if(IsFollowing) 211 { 212 /* Skip the descendants, and jump to the next node. */ 213 m_currentPre += m_document->size(m_currentPre) + 1; 214 215 if(m_currentPre > m_document->maximumPreNumber() || m_document->depth(m_currentPre) != m_depth) 216 return closedExit(); 217 else 218 { 219 ++m_position; 220 m_current = m_document->createIndex(m_currentPre); 221 return m_current; 222 } 223 } 224 else 225 { 226 while(m_document->depth(m_currentPre) > m_depth) 227 --m_currentPre; 228 229 while(m_document->kind(m_currentPre) == QXmlNodeModelIndex::Attribute) 230 --m_currentPre; 231 232 if(m_document->depth(m_currentPre) == m_depth && 233 m_document->kind(m_currentPre) != QXmlNodeModelIndex::Attribute) 234 { 235 m_current = m_document->createIndex(m_currentPre); 236 ++m_position; 237 --m_currentPre; 238 return m_current; 239 } 240 else 241 { 242 m_currentPre = -1; 243 return closedExit(); 244 } 245 } 246 } 247 copy()248 virtual QXmlNodeModelIndex::Iterator::Ptr copy() const 249 { 250 return QXmlNodeModelIndex::Iterator::Ptr(new SiblingIterator<IsFollowing>(m_document, m_preNumber)); 251 } 252 253 private: 254 const AccelTree::Depth m_depth; 255 }; 256 257 /** 258 * @short Implements axis @c descendant and @c descendant-or-self for the 259 * AccelTree. 260 * 261 * @author Frans Englich <frans.englich@nokia.com> 262 */ 263 template<const bool IncludeSelf> 264 class DescendantIterator : public AccelIterator 265 { 266 public: 267 /** 268 * @p pre must have at least one child. 269 */ DescendantIterator(const AccelTree * const doc,const AccelTree::PreNumber pre)270 inline DescendantIterator(const AccelTree *const doc, 271 const AccelTree::PreNumber pre) : AccelIterator(doc, pre, pre + (IncludeSelf ? 0 : 1)), 272 m_postNumber(doc->postNumber(pre)) 273 { 274 Q_ASSERT(IncludeSelf || m_document->hasChildren(pre)); 275 276 /* Make sure that m_currentPre is the first node part of this axis. 277 * Since we're not including ourself, advance to the node after our 278 * attributes, if any. */ 279 if(!IncludeSelf) 280 { 281 while(m_document->kind(m_currentPre) == QXmlNodeModelIndex::Attribute) 282 { 283 ++m_currentPre; 284 /* We check the depth here because we would otherwise include 285 * following siblings. */ 286 if(m_currentPre > m_document->maximumPreNumber() || m_document->postNumber(m_currentPre) > m_postNumber) 287 { 288 m_currentPre = -1; 289 break; 290 } 291 } 292 } 293 } 294 next()295 virtual QXmlNodeModelIndex next() 296 { 297 if(m_currentPre == -1) 298 return closedExit(); 299 300 ++m_position; 301 m_current = m_document->createIndex(m_currentPre); 302 303 ++m_currentPre; 304 305 if(m_currentPre > m_document->maximumPreNumber()) 306 { 307 m_currentPre = -1; 308 return m_current; 309 } 310 311 if(m_document->postNumber(m_currentPre) < m_postNumber) 312 { 313 while(m_document->kind(m_currentPre) == QXmlNodeModelIndex::Attribute) 314 { 315 ++m_currentPre; 316 if(m_currentPre > m_document->maximumPreNumber()) 317 { 318 m_currentPre = -1; 319 break; 320 } 321 } 322 } 323 else 324 m_currentPre = -1; 325 326 return m_current; 327 } 328 copy()329 virtual QXmlNodeModelIndex::Iterator::Ptr copy() const 330 { 331 return QXmlNodeModelIndex::Iterator::Ptr(new DescendantIterator<IncludeSelf>(m_document, m_preNumber)); 332 } 333 334 private: 335 const AccelTree::PreNumber m_postNumber; 336 }; 337 338 /** 339 * @short Implements axis @c following for the AccelTree. 340 * 341 * @author Frans Englich <frans.englich@nokia.com> 342 */ 343 class FollowingIterator : public AccelIterator 344 { 345 public: 346 /** 347 * @ pre must have at least one child. 348 */ FollowingIterator(const AccelTree * const doc,const AccelTree::PreNumber pre)349 inline FollowingIterator(const AccelTree *const doc, 350 const AccelTree::PreNumber pre) : AccelIterator(doc, pre, pre) 351 { 352 } 353 354 virtual QXmlNodeModelIndex next(); 355 virtual QXmlNodeModelIndex::Iterator::Ptr copy() const; 356 }; 357 358 /** 359 * @short Implements axis @c preceding for the AccelTree. 360 * 361 * @author Frans Englich <frans.englich@nokia.com> 362 */ 363 class PrecedingIterator : public AccelIterator 364 { 365 public: 366 /** 367 * @ pre must have at least one child. 368 */ PrecedingIterator(const AccelTree * const doc,const AccelTree::PreNumber pre)369 inline PrecedingIterator(const AccelTree *const doc, 370 const AccelTree::PreNumber pre) : AccelIterator(doc, pre, 371 pre - 1 /* currentPre */) 372 , m_postNumber(m_document->postNumber(m_preNumber)) 373 { 374 } 375 376 virtual QXmlNodeModelIndex next(); 377 virtual QXmlNodeModelIndex::Iterator::Ptr copy() const; 378 379 private: 380 const AccelTree::PreNumber m_postNumber; 381 }; 382 383 /** 384 * @short Implements axis @c attribute for the AccelTree. 385 * 386 * @author Frans Englich <frans.englich@nokia.com> 387 */ 388 class AttributeIterator : public AccelIterator 389 { 390 public: 391 /** 392 * @p pre must have at least one child. 393 */ AttributeIterator(const AccelTree * const doc,const AccelTree::PreNumber pre)394 inline AttributeIterator(const AccelTree *const doc, const AccelTree::PreNumber pre) : AccelIterator(doc, pre, pre + 1) 395 { 396 Q_ASSERT(m_document->hasChildren(pre)); 397 Q_ASSERT(m_document->kind(m_currentPre) == QXmlNodeModelIndex::Attribute); 398 } 399 400 virtual QXmlNodeModelIndex next(); 401 virtual QXmlNodeModelIndex::Iterator::Ptr copy() const; 402 }; 403 } 404 405 QT_END_NAMESPACE 406 407 #endif 408