src/xmlpatterns/acceltree/qacceliterators_p.h
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtXmlPatterns module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    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 "qacceltree_p.h"
       
    56 #include "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