LCOV - code coverage report
Current view: top level - dom/xul/templates - nsTreeRows.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 240 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 20 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "nsString.h"
       7             : #include "nsTreeRows.h"
       8             : #include <algorithm>
       9             : 
      10             : nsTreeRows::Subtree*
      11           0 : nsTreeRows::EnsureSubtreeFor(Subtree* aParent,
      12             :                              int32_t aChildIndex)
      13             : {
      14           0 :     Subtree* subtree = GetSubtreeFor(aParent, aChildIndex);
      15             : 
      16           0 :     if (! subtree) {
      17           0 :         subtree = aParent->mRows[aChildIndex].mSubtree = new Subtree(aParent);
      18           0 :         InvalidateCachedRow();
      19             :     }
      20             : 
      21           0 :     return subtree;
      22             : }
      23             : 
      24             : nsTreeRows::Subtree*
      25           0 : nsTreeRows::GetSubtreeFor(const Subtree* aParent,
      26             :                               int32_t aChildIndex,
      27             :                               int32_t* aSubtreeSize)
      28             : {
      29           0 :     NS_PRECONDITION(aParent, "no parent");
      30           0 :     NS_PRECONDITION(aChildIndex >= 0, "bad child index");
      31             : 
      32           0 :     Subtree* result = nullptr;
      33             : 
      34           0 :     if (aChildIndex < aParent->mCount)
      35           0 :         result = aParent->mRows[aChildIndex].mSubtree;
      36             : 
      37           0 :     if (aSubtreeSize)
      38           0 :         *aSubtreeSize = result ? result->mSubtreeSize : 0;
      39             : 
      40           0 :     return result;
      41             : }
      42             : 
      43             : void
      44           0 : nsTreeRows::RemoveSubtreeFor(Subtree* aParent, int32_t aChildIndex)
      45             : {
      46           0 :     NS_PRECONDITION(aParent, "no parent");
      47           0 :     NS_PRECONDITION(aChildIndex >= 0 && aChildIndex < aParent->mCount, "bad child index");
      48             : 
      49           0 :     Row& row = aParent->mRows[aChildIndex];
      50             : 
      51           0 :     if (row.mSubtree) {
      52           0 :         int32_t subtreeSize = row.mSubtree->GetSubtreeSize();
      53             : 
      54           0 :         delete row.mSubtree;
      55           0 :         row.mSubtree = nullptr;
      56             : 
      57           0 :         for (Subtree* subtree = aParent; subtree != nullptr; subtree = subtree->mParent)
      58           0 :             subtree->mSubtreeSize -= subtreeSize;
      59             :     }
      60             : 
      61           0 :     InvalidateCachedRow();
      62           0 : }
      63             : 
      64             : nsTreeRows::iterator
      65           0 : nsTreeRows::First()
      66             : {
      67           0 :     iterator result;
      68           0 :     result.Append(&mRoot, 0);
      69           0 :     result.SetRowIndex(0);
      70           0 :     return result;
      71             : }
      72             : 
      73             : nsTreeRows::iterator
      74           0 : nsTreeRows::Last()
      75             : {
      76           0 :     iterator result;
      77             : 
      78             :     // Build up a path along the rightmost edge of the tree
      79           0 :     Subtree* current = &mRoot;
      80           0 :     int32_t count = current->Count();
      81           0 :     do  {
      82           0 :         int32_t last = count - 1;
      83           0 :         result.Append(current, last);
      84           0 :         current = count ? GetSubtreeFor(current, last) : nullptr;
      85           0 :     } while (current && ((count = current->Count()) != 0));
      86             : 
      87             :     // Now, at the bottom rightmost leaf, advance us one off the end.
      88           0 :     result.GetTop().mChildIndex++;
      89             : 
      90             :     // Our row index will be the size of the root subree, plus one.
      91           0 :     result.SetRowIndex(mRoot.GetSubtreeSize() + 1);
      92             : 
      93           0 :     return result;
      94             : }
      95             : 
      96             : nsTreeRows::iterator
      97           0 : nsTreeRows::operator[](int32_t aRow)
      98             : {
      99             :     // See if we're just lucky, and end up with something
     100             :     // nearby. (This tends to happen a lot due to the way that we get
     101             :     // asked for rows n' stuff.)
     102           0 :     int32_t last = mLastRow.GetRowIndex();
     103           0 :     if (last != -1) {
     104           0 :         if (aRow == last)
     105           0 :             return mLastRow;
     106           0 :         else if (last + 1 == aRow)
     107           0 :             return ++mLastRow;
     108           0 :         else if (last - 1 == aRow)
     109           0 :             return --mLastRow;
     110             :     }
     111             : 
     112             :     // Nope. Construct a path to the specified index. This is a little
     113             :     // bit better than O(n), because we can skip over subtrees. (So it
     114             :     // ends up being approximately linear in the subtree size, instead
     115             :     // of the entire view size. But, most of the time, big views are
     116             :     // flat. Oh well.)
     117           0 :     iterator result;
     118           0 :     Subtree* current = &mRoot;
     119             : 
     120           0 :     int32_t index = 0;
     121           0 :     result.SetRowIndex(aRow);
     122             : 
     123           0 :     do {
     124             :         int32_t subtreeSize;
     125           0 :         Subtree* subtree = GetSubtreeFor(current, index, &subtreeSize);
     126             : 
     127           0 :         if (subtreeSize >= aRow) {
     128           0 :             result.Append(current, index);
     129           0 :             current = subtree;
     130           0 :             index = 0;
     131           0 :             --aRow;
     132             :         }
     133             :         else {
     134           0 :             ++index;
     135           0 :             aRow -= subtreeSize + 1;
     136             :         }
     137           0 :     } while (aRow >= 0);
     138             : 
     139           0 :     mLastRow = result;
     140           0 :     return result;
     141             : }
     142             : 
     143             : nsTreeRows::iterator
     144           0 : nsTreeRows::FindByResource(nsIRDFResource* aResource)
     145             : {
     146             :     // XXX Mmm, scan through the rows one-by-one...
     147           0 :     iterator last = Last();
     148           0 :     iterator iter;
     149             : 
     150             :     nsresult rv;
     151           0 :     nsAutoString resourceid;
     152           0 :     bool stringmode = false;
     153             : 
     154           0 :     for (iter = First(); iter != last; ++iter) {
     155           0 :         if (!stringmode) {
     156           0 :             nsCOMPtr<nsIRDFResource> findres;
     157           0 :             rv = iter->mMatch->mResult->GetResource(getter_AddRefs(findres));
     158           0 :             if (NS_FAILED(rv)) return last;
     159             : 
     160           0 :             if (findres == aResource)
     161           0 :                 break;
     162             : 
     163           0 :             if (! findres) {
     164             :                 const char *uri;
     165           0 :                 aResource->GetValueConst(&uri);
     166           0 :                 CopyUTF8toUTF16(uri, resourceid);
     167             : 
     168             :                 // set stringmode and fall through
     169           0 :                 stringmode = true;
     170             :             }
     171             :         }
     172             : 
     173             :         // additional check because previous block could change stringmode
     174           0 :         if (stringmode) {
     175           0 :             nsAutoString findid;
     176           0 :             rv = iter->mMatch->mResult->GetId(findid);
     177           0 :             if (NS_FAILED(rv)) return last;
     178             : 
     179           0 :             if (resourceid.Equals(findid))
     180           0 :                 break;
     181             :         }
     182             :     }
     183             : 
     184           0 :     return iter;
     185             : }
     186             : 
     187             : nsTreeRows::iterator
     188           0 : nsTreeRows::Find(nsIXULTemplateResult *aResult)
     189             : {
     190             :     // XXX Mmm, scan through the rows one-by-one...
     191           0 :     iterator last = Last();
     192           0 :     iterator iter;
     193             : 
     194           0 :     for (iter = First(); iter != last; ++iter) {
     195           0 :         if (aResult == iter->mMatch->mResult)
     196           0 :           break;
     197             :     }
     198             : 
     199           0 :     return iter;
     200             : }
     201             : 
     202             : void
     203           0 : nsTreeRows::Clear()
     204             : {
     205           0 :     mRoot.Clear();
     206           0 :     InvalidateCachedRow();
     207           0 : }
     208             : 
     209             : //----------------------------------------------------------------------
     210             : //
     211             : // nsTreeRows::Subtree
     212             : //
     213             : 
     214           0 : nsTreeRows::Subtree::~Subtree()
     215             : {
     216           0 :     Clear();
     217           0 : }
     218             : 
     219             : void
     220           0 : nsTreeRows::Subtree::Clear()
     221             : {
     222           0 :     for (int32_t i = mCount - 1; i >= 0; --i)
     223           0 :         delete mRows[i].mSubtree;
     224             : 
     225           0 :     delete[] mRows;
     226             : 
     227           0 :     mRows = nullptr;
     228           0 :     mCount = mCapacity = mSubtreeSize = 0;
     229           0 : }
     230             : 
     231             : nsTreeRows::iterator
     232           0 : nsTreeRows::Subtree::InsertRowAt(nsTemplateMatch* aMatch, int32_t aIndex)
     233             : {
     234           0 :     if (mCount >= mCapacity || aIndex >= mCapacity) {
     235           0 :         int32_t newCapacity = std::max(mCapacity * 2, aIndex + 1);
     236           0 :         Row* newRows = new Row[newCapacity];
     237           0 :         if (! newRows)
     238           0 :             return iterator();
     239             : 
     240           0 :         for (int32_t i = mCount - 1; i >= 0; --i)
     241           0 :             newRows[i] = mRows[i];
     242             : 
     243           0 :         delete[] mRows;
     244             : 
     245           0 :         mRows = newRows;
     246           0 :         mCapacity = newCapacity;
     247             :     }
     248             : 
     249           0 :     for (int32_t i = mCount - 1; i >= aIndex; --i)
     250           0 :         mRows[i + 1] = mRows[i];
     251             : 
     252           0 :     mRows[aIndex].mMatch = aMatch;
     253           0 :     mRows[aIndex].mContainerType = eContainerType_Unknown;
     254           0 :     mRows[aIndex].mContainerState = eContainerState_Unknown;
     255           0 :     mRows[aIndex].mContainerFill = eContainerFill_Unknown;
     256           0 :     mRows[aIndex].mSubtree = nullptr;
     257           0 :     ++mCount;
     258             : 
     259             :     // Now build an iterator that points to the newly inserted element.
     260           0 :     int32_t rowIndex = 0;
     261           0 :     iterator result;
     262           0 :     result.Push(this, aIndex);
     263             : 
     264           0 :     for ( ; --aIndex >= 0; ++rowIndex) {
     265             :         // Account for open subtrees in the absolute row index.
     266           0 :         const Subtree *subtree = mRows[aIndex].mSubtree;
     267           0 :         if (subtree)
     268           0 :             rowIndex += subtree->mSubtreeSize;
     269             :     }
     270             : 
     271           0 :     Subtree *subtree = this;
     272             :     do {
     273             :         // Note that the subtree's size has expanded.
     274           0 :         ++subtree->mSubtreeSize;
     275             : 
     276           0 :         Subtree *parent = subtree->mParent;
     277           0 :         if (! parent)
     278           0 :             break;
     279             : 
     280             :         // Account for open subtrees in the absolute row index.
     281           0 :         int32_t count = parent->Count();
     282           0 :         for (aIndex = 0; aIndex < count; ++aIndex, ++rowIndex) {
     283           0 :             const Subtree *child = (*parent)[aIndex].mSubtree;
     284           0 :             if (subtree == child)
     285           0 :                 break;
     286             : 
     287           0 :             if (child)
     288           0 :                 rowIndex += child->mSubtreeSize;
     289             :         }
     290             : 
     291           0 :         NS_ASSERTION(aIndex < count, "couldn't find subtree in parent");
     292             : 
     293           0 :         result.Push(parent, aIndex);
     294           0 :         subtree = parent;
     295           0 :         ++rowIndex; // One for the parent row.
     296             :     } while (1);
     297             : 
     298           0 :     result.SetRowIndex(rowIndex);
     299           0 :     return result;
     300             : }
     301             : 
     302             : void
     303           0 : nsTreeRows::Subtree::RemoveRowAt(int32_t aIndex)
     304             : {
     305           0 :     NS_PRECONDITION(aIndex >= 0 && aIndex < Count(), "bad index");
     306           0 :     if (aIndex < 0 || aIndex >= Count())
     307           0 :         return;
     308             : 
     309             :     // How big is the subtree we're going to be removing?
     310           0 :     int32_t subtreeSize = mRows[aIndex].mSubtree
     311           0 :         ? mRows[aIndex].mSubtree->GetSubtreeSize()
     312           0 :         : 0;
     313             : 
     314           0 :     ++subtreeSize;
     315             : 
     316           0 :     delete mRows[aIndex].mSubtree;
     317             : 
     318           0 :     for (int32_t i = aIndex + 1; i < mCount; ++i)
     319           0 :         mRows[i - 1] = mRows[i];
     320             : 
     321           0 :     --mCount;
     322             : 
     323           0 :     for (Subtree* subtree = this; subtree != nullptr; subtree = subtree->mParent)
     324           0 :         subtree->mSubtreeSize -= subtreeSize;
     325             : }
     326             : 
     327             : //----------------------------------------------------------------------
     328             : //
     329             : // nsTreeRows::iterator
     330             : //
     331             : 
     332           0 : nsTreeRows::iterator::iterator(const iterator& aIterator)
     333           0 :     : mRowIndex(aIterator.mRowIndex),
     334           0 :       mLink(aIterator.mLink)
     335             : {
     336           0 : }
     337             : 
     338             : nsTreeRows::iterator&
     339           0 : nsTreeRows::iterator::operator=(const iterator& aIterator)
     340             : {
     341           0 :     mRowIndex = aIterator.mRowIndex;
     342           0 :     mLink = aIterator.mLink;
     343           0 :     return *this;
     344             : }
     345             : 
     346             : void
     347           0 : nsTreeRows::iterator::Append(Subtree* aParent, int32_t aChildIndex)
     348             : {
     349           0 :     Link *link = mLink.AppendElement();
     350           0 :     if (link) {
     351           0 :         link->mParent     = aParent;
     352           0 :         link->mChildIndex = aChildIndex;
     353             :     }
     354             :     else
     355           0 :         NS_ERROR("out of memory");
     356           0 : }
     357             : 
     358             : void
     359           0 : nsTreeRows::iterator::Push(Subtree *aParent, int32_t aChildIndex)
     360             : {
     361           0 :     Link *link = mLink.InsertElementAt(0);
     362           0 :     if (link) {
     363           0 :         link->mParent     = aParent;
     364           0 :         link->mChildIndex = aChildIndex;
     365             :     }
     366             :     else
     367           0 :         NS_ERROR("out of memory");
     368           0 : }
     369             : 
     370             : bool
     371           0 : nsTreeRows::iterator::operator==(const iterator& aIterator) const
     372             : {
     373           0 :     if (GetDepth() != aIterator.GetDepth())
     374           0 :         return false;
     375             : 
     376           0 :     if (GetDepth() == 0)
     377           0 :         return true;
     378             : 
     379           0 :     return GetTop() == aIterator.GetTop();
     380             : }
     381             : 
     382             : void
     383           0 : nsTreeRows::iterator::Next()
     384             : {
     385           0 :     NS_PRECONDITION(GetDepth() > 0, "cannot increment an uninitialized iterator");
     386             : 
     387             :     // Increment the absolute row index
     388           0 :     ++mRowIndex;
     389             : 
     390           0 :     Link& top = GetTop();
     391             : 
     392             :     // Is there a child subtree? If so, descend into the child
     393             :     // subtree.
     394           0 :     Subtree* subtree = top.GetRow().mSubtree;
     395             : 
     396           0 :     if (subtree && subtree->Count()) {
     397           0 :         Append(subtree, 0);
     398           0 :         return;
     399             :     }
     400             : 
     401             :     // Have we exhausted the current subtree?
     402           0 :     if (top.mChildIndex >= top.mParent->Count() - 1) {
     403             :         // Yep. See if we've just iterated path the last element in
     404             :         // the tree, period. Walk back up the stack, looking for any
     405             :         // unfinished subtrees.
     406             :         int32_t unfinished;
     407           0 :         for (unfinished = GetDepth() - 2; unfinished >= 0; --unfinished) {
     408           0 :             const Link& link = mLink[unfinished];
     409           0 :             if (link.mChildIndex < link.mParent->Count() - 1)
     410           0 :                 break;
     411             :         }
     412             : 
     413             :         // If there are no unfinished subtrees in the stack, then this
     414             :         // iterator is exhausted. Leave it in the same state that
     415             :         // Last() does.
     416           0 :         if (unfinished < 0) {
     417           0 :             top.mChildIndex++;
     418           0 :             return;
     419             :         }
     420             : 
     421             :         // Otherwise, we ran off the end of one of the inner
     422             :         // subtrees. Pop up to the next unfinished level in the stack.
     423           0 :         mLink.SetLength(unfinished + 1);
     424             :     }
     425             : 
     426             :     // Advance to the next child in this subtree
     427           0 :     ++(GetTop().mChildIndex);
     428             : }
     429             : 
     430             : void
     431           0 : nsTreeRows::iterator::Prev()
     432             : {
     433           0 :     NS_PRECONDITION(GetDepth() > 0, "cannot increment an uninitialized iterator");
     434             : 
     435             :     // Decrement the absolute row index
     436           0 :     --mRowIndex;
     437             : 
     438             :     // Move to the previous child in this subtree
     439           0 :     --(GetTop().mChildIndex);
     440             : 
     441             :     // Have we exhausted the current subtree?
     442           0 :     if (GetTop().mChildIndex < 0) {
     443             :         // Yep. See if we've just iterated back to the first element
     444             :         // in the tree, period. Walk back up the stack, looking for
     445             :         // any unfinished subtrees.
     446             :         int32_t unfinished;
     447           0 :         for (unfinished = GetDepth() - 2; unfinished >= 0; --unfinished) {
     448           0 :             const Link& link = mLink[unfinished];
     449           0 :             if (link.mChildIndex >= 0)
     450           0 :                 break;
     451             :         }
     452             : 
     453             :         // If there are no unfinished subtrees in the stack, then this
     454             :         // iterator is exhausted. Leave it in the same state that
     455             :         // First() does.
     456           0 :         if (unfinished < 0)
     457           0 :             return;
     458             : 
     459             :         // Otherwise, we ran off the end of one of the inner
     460             :         // subtrees. Pop up to the next unfinished level in the stack.
     461           0 :         mLink.SetLength(unfinished + 1);
     462           0 :         return;
     463             :     }
     464             : 
     465             :     // Is there a child subtree immediately prior to our current
     466             :     // position? If so, descend into it, grovelling down to the
     467             :     // deepest, rightmost left edge.
     468           0 :     Subtree* parent = GetTop().GetParent();
     469           0 :     int32_t index = GetTop().GetChildIndex();
     470             : 
     471           0 :     Subtree* subtree = (*parent)[index].mSubtree;
     472             : 
     473           0 :     if (subtree && subtree->Count()) {
     474           0 :         do {
     475           0 :             index = subtree->Count() - 1;
     476           0 :             Append(subtree, index);
     477             : 
     478           0 :             parent = subtree;
     479           0 :             subtree = (*parent)[index].mSubtree;
     480           0 :         } while (subtree && subtree->Count());
     481             :     }
     482             : }

Generated by: LCOV version 1.13