mozilla/xpcom/ds/nsVoidBTree.cpp

Mozilla Cross Reference: seamonkey mozilla/ xpcom/ ds/ nsVoidBTree.cpp |
CVS Log CVS Blame
changes to this file in the last: | day week month

      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
      2 /*
      3  * The contents of this file are subject to the Mozilla Public License
      4  * Version 1.1 (the "MPL"); you may not use this file except in
      5  * compliance with the MPL.  You may obtain a copy of the MPL at
      6  * http://www.mozilla.org/MPL/
      7  *
      8  * Software distributed under the MPL is distributed on an "AS IS" basis,
      9  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the MPL
     10  * for the specific language governing rights and limitations under the
     11  * MPL.
     12  *
     13  * The Initial Developer of this code under the MPL is Netscape
     14  * Communications Corporation.  Portions created by Netscape are
     15  * Copyright (C) 1999 Netscape Communications Corporation.  All Rights
     16  * Reserved.
     17  *
     18  * Original Author:
     19  *   Chris Waterson <waterson@netscape.com>
     20  */
     21
     22 #include "nsVoidBTree.h"
     23
     24 #ifdef DEBUG
     25 #include <stdio.h>
     26 #endif
     27
     28 // Set this to force the tree to be verified after every insertion and
     29 // removal.
     30 //#define PARANOID 1
     31
     32
     33 //----------------------------------------------------------------------
     34 // nsVoidBTree::Node
     35 //
     36 //   Implementation methods
     37 //
     38
     39 nsresult
     40 nsVoidBTree::Node::Create(Type aType, PRInt32 aCapacity, Node** aResult)
     41 {
     42     // So we only ever have to do one allocation for a Node, we do a
     43     // "naked" heap allocation, computing the size of the node and
     44     // "padding" it out so that it can hold aCapacity slots.
     45     char* bytes = new char[sizeof(Node) + (aCapacity - 1) * sizeof(void*)];
     46     if (! bytes)
     47         return NS_ERROR_OUT_OF_MEMORY;
     48
     49     Node* result = NS_REINTERPRET_CAST(Node*, bytes);
     50     result->mBits = 0;
     51     result->SetType(aType);
     52
     53     *aResult = result;
     54     return NS_OK;
     55 }
     56
     57 nsresult
     58 nsVoidBTree::Node::Destroy(Node* aNode)
     59 {
     60     char* bytes = NS_REINTERPRET_CAST(char*, aNode);
     61     delete[] bytes;
     62     return NS_OK;
     63 }
     64
     65 void
     66 nsVoidBTree::Node::InsertElementAt(void* aElement, PRInt32 aIndex)
     67 {
     68     NS_PRECONDITION(aIndex >= 0 && aIndex <= GetCount(), "bad index");
     69
     70     PRInt32 count = GetCount();
     71     SetCount(count + 1);
     72
     73     while (count > aIndex) {
     74         mData[count] = mData[count - 1];
     75         --count;
     76     }
     77
     78     mData[aIndex] = aElement;
     79 }
     80
     81 void
     82 nsVoidBTree::Node::RemoveElementAt(PRInt32 aIndex)
     83 {
     84     NS_PRECONDITION(aIndex >= 0 && aIndex < GetCount(), "bad index");
     85
     86     PRInt32 count = GetCount();
     87     SetCount(count - 1);
     88
     89     while (aIndex < count) {
     90         mData[aIndex] = mData[aIndex + 1];
     91         ++aIndex;
     92     }
     93 }
     94
     95
     96 //----------------------------------------------------------------------
     97 //
     98 // nsVoidBTree::Path
     99 //
    100 //   Implementation methods
    101 //
    102
    103 nsVoidBTree::Path::Path(const Path& aOther)
    104     : mTop(aOther.mTop)
    105 {
    106     for (PRInt32 i = 0; i < mTop; ++i)
    107         mLink[i] = aOther.mLink[i];
    108 }
    109
    110 nsVoidBTree::Path&
    111 nsVoidBTree::Path::operator=(const Path& aOther)
    112 {
    113     mTop = aOther.mTop;
    114     for (PRInt32 i = 0; i < mTop; ++i)
    115         mLink[i] = aOther.mLink[i];
    116     return *this;
    117 }
    118
    119 inline nsresult
    120 nsVoidBTree::Path::Push(Node* aNode, PRInt32 aIndex)
    121 {
    122     // XXX If you overflow this thing, think about making larger index
    123     // or data nodes. You can pack a _lot_ of data into a pretty flat
    124     // tree.
    125     NS_PRECONDITION(mTop <= kMaxDepth, "overflow");
    126     if (mTop > kMaxDepth)
    127         return NS_ERROR_OUT_OF_MEMORY;
    128
    129     mLink[mTop].mNode  = aNode;
    130     mLink[mTop].mIndex = aIndex;
    131     ++mTop;
    132
    133     return NS_OK;
    134 }
    135
    136
    137 inline void
    138 nsVoidBTree::Path::Pop(Node** aNode, PRInt32* aIndex)
    139 {
    140     --mTop;
    141     *aNode  = mLink[mTop].mNode;
    142     *aIndex = mLink[mTop].mIndex;
    143 }
    144
    145 //----------------------------------------------------------------------
    146 //
    147 //    nsVoidBTree methods
    148 //
    149
    150 nsVoidBTree::nsVoidBTree(const nsVoidBTree& aOther)
    151 {
    152     ConstIterator last = aOther.Last();
    153     for (ConstIterator element = aOther.First(); element != last; ++element)
    154         AppendElement(*element);
    155 }
    156
    157 nsVoidBTree&
    158 nsVoidBTree::operator=(const nsVoidBTree& aOther)
    159 {
    160     Clear();
    161     ConstIterator last = aOther.Last();
    162     for (ConstIterator element = aOther.First(); element != last; ++element)
    163         AppendElement(*element);
    164     return *this;
    165 }
    166
    167 PRInt32
    168 nsVoidBTree::Count() const
    169 {
    170     if (IsEmpty())
    171         return 0;
    172
    173     if (IsSingleElement())
    174         return 1;
    175
    176     Node* root = NS_REINTERPRET_CAST(Node*, mRoot & kRoot_PointerMask);
    177     return root->GetSubTreeSize();
    178 }
    179
    180 void*
    181 nsVoidBTree::ElementAt(PRInt32 aIndex) const
    182 {
    183     if (aIndex < 0 || aIndex >= Count())
    184         return nsnull;
    185
    186     if (IsSingleElement())
    187         return NS_REINTERPRET_CAST(void*, mRoot & kRoot_PointerMask);
    188
    189     Node* current = NS_REINTERPRET_CAST(Node*, mRoot & kRoot_PointerMask);
    190     while (current->GetType() != Node::eType_Data) {
    191         // We're still in the index. Find the right leaf.
    192         Node* next = nsnull;
    193
    194         PRInt32 count = current->GetCount();
    195         for (PRInt32 i = 0; i < count; ++i) {
    196             Node* child = NS_REINTERPRET_CAST(Node*, current->GetElementAt(i));
    197
    198             PRInt32 childcount = child->GetSubTreeSize();
    199             if (PRInt32(aIndex) < childcount) {
    200                 next = child;
    201                 break;
    202             }
    203
    204             aIndex -= childcount;
    205         }
    206
    207         if (! next) {
    208             NS_ERROR("corrupted");
    209             return nsnull;
    210         }
    211
    212         current = next;
    213     }
    214
    215     return current->GetElementAt(aIndex);
    216 }
    217
    218
    219 PRInt32
    220 nsVoidBTree::IndexOf(void* aPossibleElement) const
    221 {
    222     NS_PRECONDITION((PRWord(aPossibleElement) & ~kRoot_PointerMask) == 0,
    223                     "uh oh, someone wants to use the pointer bits");
    224
    225     NS_PRECONDITION(aPossibleElement != nsnull, "nsVoidBTree can't handle null elements");
    226     if (aPossibleElement == nsnull)
    227         return -1;
    228
    229     PRInt32 result = 0;
    230     ConstIterator last = Last();
    231     for (ConstIterator element = First(); element != last; ++element, ++result) {
    232         if (aPossibleElement == *element)
    233             return result;
    234     }
    235
    236     return -1;
    237 }
    238
    239
    240 PRBool
    241 nsVoidBTree::InsertElementAt(void* aElement, PRInt32 aIndex)
    242 {
    243     NS_PRECONDITION((PRWord(aElement) & ~kRoot_PointerMask) == 0,
    244                     "uh oh, someone wants to use the pointer bits");
    245
    246     if ((PRWord(aElement) & ~kRoot_PointerMask) != 0)
    247         return PR_FALSE;
    248
    249     NS_PRECONDITION(aElement != nsnull, "nsVoidBTree can't handle null elements");
    250     if (aElement == nsnull)
    251         return PR_FALSE;
    252
    253     PRInt32 count = Count();
    254
    255     if (aIndex < 0 || aIndex > count)
    256         return PR_FALSE;
    257
    258     nsresult rv;
    259
    260     if (IsSingleElement()) {
    261         // We're only a single element holder, and haven't yet
    262         // "faulted" to create the btree.
    263
    264         if (count == 0) {
    265             // If we have *no* elements, then just set the root
    266             // pointer and we're done.
    267             mRoot = PRWord(aElement);
    268             return PR_TRUE;
    269         }
    270
    271         // If we already had an element, and now we're adding
    272         // another. Fault and start creating the btree.
    273         void* element = NS_REINTERPRET_CAST(void*, mRoot & kRoot_PointerMask);
    274
    275         Node* newroot;
    276         rv = Node::Create(Node::eType_Data, kDataCapacity, &newroot);
    277         if (NS_FAILED(rv)) return PR_FALSE;
    278
    279         newroot->InsertElementAt(element, 0);
    280         newroot->SetSubTreeSize(1);
    281         SetRoot(newroot);
    282     }
    283
    284     Path path;
    285
    286     Node* current = NS_REINTERPRET_CAST(Node*, mRoot & kRoot_PointerMask);
    287     while (current->GetType() != Node::eType_Data) {
    288         // We're still in the index. Find the right leaf.
    289         Node* next = nsnull;
    290
    291         count = current->GetCount();
    292         for (PRInt32 i = 0; i < count; ++i) {
    293             Node* child = NS_REINTERPRET_CAST(Node*, current->GetElementAt(i));
    294
    295             PRInt32 childcount = child->GetSubTreeSize();
    296             if (PRInt32(aIndex) <= childcount) {
    297                 rv = path.Push(current, i + 1);
    298                 if (NS_FAILED(rv)) return PR_FALSE;
    299
    300                 next = child;
    301                 break;
    302             }
    303
    304             aIndex -= childcount;
    305         }
    306
    307         if (! next) {
    308             NS_ERROR("corrupted");
    309             return PR_FALSE;
    310         }
    311
    312         current = next;
    313     }
    314
    315     if (current->GetCount() >= kDataCapacity) {
    316         // We just blew the data node's buffer. Create another
    317         // datanode and split.
    318         rv = Split(path, current, aElement, aIndex);
    319         if (NS_FAILED(rv)) return PR_FALSE;
    320     }
    321     else {
    322         current->InsertElementAt(aElement, aIndex);
    323         current->SetSubTreeSize(current->GetSubTreeSize() + 1);
    324     }
    325
    326     while (path.Length() > 0) {
    327         PRInt32 index;
    328         path.Pop(&current, &index);
    329         current->SetSubTreeSize(current->GetSubTreeSize() + 1);
    330     }
    331
    332 #ifdef PARANOID
    333     Verify(NS_REINTERPRET_CAST(Node*, mRoot & kRoot_PointerMask));
    334 #endif
    335
    336     return PR_TRUE;
    337 }
    338
    339 PRBool
    340 nsVoidBTree::ReplaceElementAt(void* aElement, PRInt32 aIndex)
    341 {
    342     NS_PRECONDITION((PRWord(aElement) & ~kRoot_PointerMask) == 0,
    343                     "uh oh, someone wants to use the pointer bits");
    344
    345     if ((PRWord(aElement) & ~kRoot_PointerMask) != 0)
    346         return PR_FALSE;
    347
    348     NS_PRECONDITION(aElement != nsnull, "nsVoidBTree can't handle null elements");
    349     if (aElement == nsnull)
    350         return PR_FALSE;
    351
    352     if (aIndex < 0 || aIndex >= Count())
    353         return PR_FALSE;
    354
    355     if (IsSingleElement()) {
    356         mRoot = PRWord(aElement);
    357         return PR_TRUE;
    358     }
    359
    360     Node* current = NS_REINTERPRET_CAST(Node*, mRoot & kRoot_PointerMask);
    361     while (current->GetType() != Node::eType_Data) {
    362         // We're still in the index. Find the right leaf.
    363         Node* next = nsnull;
    364
    365         PRInt32 count = current->GetCount();
    366         for (PRInt32 i = 0; i < count; ++i) {
    367             Node* child = NS_REINTERPRET_CAST(Node*, current->GetElementAt(i));
    368
    369             PRInt32 childcount = child->GetSubTreeSize();
    370             if (PRInt32(aIndex) < childcount) {
    371                 next = child;
    372                 break;
    373             }
    374
    375             aIndex -= childcount;
    376         }
    377
    378         if (! next) {
    379             NS_ERROR("corrupted");
    380             return PR_FALSE;
    381         }
    382
    383         current = next;
    384     }
    385
    386     current->SetElementAt(aElement, aIndex);
    387     return PR_TRUE;
    388 }
    389
    390 PRBool
    391 nsVoidBTree::RemoveElement(void* aElement)
    392 {
    393     PRInt32 index = IndexOf(aElement);
    394     return (index >= 0) ? RemoveElementAt(index) : PR_FALSE;
    395 }
    396
    397 PRBool
    398 nsVoidBTree::RemoveElementAt(PRInt32 aIndex)
    399 {
    400     PRInt32 count = Count();
    401
    402     if (aIndex < 0 || aIndex >= count)
    403         return PR_FALSE;
    404
    405     if (IsSingleElement()) {
    406         // We're removing the one and only element
    407         mRoot = 0;
    408         return PR_TRUE;
    409     }
    410
    411     // We've got more than one element, and we're removing it.
    412     nsresult rv;
    413     Path path;
    414
    415     Node* root = NS_REINTERPRET_CAST(Node*, mRoot & kRoot_PointerMask);
    416
    417     Node* current = root;
    418     while (current->GetType() != Node::eType_Data) {
    419         // We're still in the index. Find the right leaf.
    420         Node* next = nsnull;
    421
    422         count = current->GetCount();
    423         for (PRInt32 i = 0; i < count; ++i) {
    424             Node* child = NS_REINTERPRET_CAST(Node*, current->GetElementAt(i));
    425
    426             PRInt32 childcount = child->GetSubTreeSize();
    427             if (PRInt32(aIndex) < childcount) {
    428                 rv = path.Push(current, i);
    429                 if (NS_FAILED(rv)) return PR_FALSE;
    430
    431                 next = child;
    432                 break;
    433             }
    434
    435             aIndex -= childcount;
    436         }
    437
    438         if (! next) {
    439             NS_ERROR("corrupted");
    440             return PR_FALSE;
    441         }
    442
    443         current = next;
    444     }
    445
    446     current->RemoveElementAt(aIndex);
    447
    448     while ((current->GetCount() == 0) && (current != root)) {
    449         Node* doomed = current;
    450
    451         PRInt32 index;
    452         path.Pop(&current, &index);
    453         current->RemoveElementAt(index);
    454
    455         Node::Destroy(doomed);
    456     }
    457
    458     current->SetSubTreeSize(current->GetSubTreeSize() - 1);
    459
    460     while (path.Length() > 0) {
    461         PRInt32 index;
    462         path.Pop(&current, &index);
    463         current->SetSubTreeSize(current->GetSubTreeSize() - 1);
    464     }
    465
    466     while ((root->GetType() == Node::eType_Index) && (root->GetCount() == 1)) {
    467         Node* doomed = root;
    468         root = NS_REINTERPRET_CAST(Node*, root->GetElementAt(0));
    469         SetRoot(root);
    470         Node::Destroy(doomed);
    471     }
    472
    473 #ifdef PARANOID
    474     Verify(root);
    475 #endif
    476
    477     return PR_TRUE;
    478 }
    479
    480 void
    481 nsVoidBTree::Clear(void)
    482 {
    483     if (IsEmpty())
    484         return;
    485
    486     if (! IsSingleElement()) {
    487         Node* root = NS_REINTERPRET_CAST(Node*, mRoot & kRoot_PointerMask);
    488
    489 #ifdef PARANOID
    490         Dump(root, 0);
    491 #endif
    492
    493         DestroySubtree(root);
    494     }
    495
    496     mRoot = 0;
    497 }
    498
    499
    500 void
    501 nsVoidBTree::Compact(void)
    502 {
    503     // XXX We could go through and try to merge datanodes.
    504 }
    505
    506 PRBool
    507 nsVoidBTree::EnumerateForwards(EnumFunc aFunc, void* aData) const
    508 {
    509     PRBool running = PR_TRUE;
    510
    511     ConstIterator last = Last();
    512     for (ConstIterator element = First(); running && element != last; ++element)
    513         running = (*aFunc)(*element, aData);
    514
    515     return running;
    516 }
    517
    518 PRBool
    519 nsVoidBTree::EnumerateBackwards(EnumFunc aFunc, void* aData) const
    520 {
    521     PRBool running = PR_TRUE;
    522
    523     ConstIterator element = Last();
    524     ConstIterator first = First();
    525
    526     if (element != first) {
    527         do {
    528             running = (*aFunc)(*--element, aData);
    529         } while (running && element != first);
    530     }
    531
    532     return running;
    533 }
    534
    535
    536 void
    537 nsVoidBTree::SizeOf(nsISizeOfHandler* aHandler, PRUint32* aResult) const
    538 {
    539     if (! aResult)
    540         return;
    541
    542     *aResult = sizeof(*this);
    543
    544     if (IsSingleElement())
    545         return;
    546
    547     Path path;
    548     path.Push(NS_REINTERPRET_CAST(Node*, mRoot & kRoot_PointerMask), 0);
    549
    550     while (path.Length()) {
    551         Node* current;
    552         PRInt32 index;
    553         path.Pop(&current, &index);
    554
    555         if (current->GetType() == Node::eType_Data) {
    556             *aResult += sizeof(Node) + (sizeof(void*) * (kDataCapacity - 1));
    557         }
    558         else {
    559             *aResult += sizeof(Node) + (sizeof(void*) * (kIndexCapacity - 1));
    560
    561             // If we're in an index node, and there are still kids to
    562             // traverse, well, traverse 'em.
    563             if (index < current->GetCount()) {
    564                 path.Push(current, index + 1);
    565                 path.Push(NS_STATIC_CAST(Node*, current->GetElementAt(index)), 0);
    566             }
    567         }
    568     }
    569 }
    570
    571 //----------------------------------------------------------------------
    572
    573 nsresult
    574 nsVoidBTree::Split(Path& path, Node* aOldNode, void* aElementToInsert, PRInt32 aSplitIndex)
    575 {
    576     nsresult rv;
    577
    578     PRInt32 capacity = (aOldNode->GetType() == Node::eType_Data) ? kDataCapacity : kIndexCapacity;
    579     PRInt32 delta = 0;
    580
    581
    582     Node* newnode;
    583     rv = Node::Create(aOldNode->GetType(), capacity, &newnode);
    584     if (NS_FAILED(rv)) return rv;
    585
    586     if (aSplitIndex == capacity) {
    587         // If aSplitIndex is the same as the capacity of the node,
    588         // then there'll be nothing to copy from the old node to the
    589         // new node, and the element is really meant to be inserted in
    590         // the newnode. In that case, do it _now_ so that newnode's
    591         // subtree size will be correct.
    592         newnode->InsertElementAt(aElementToInsert, 0);
    593
    594         if (newnode->GetType() == Node::eType_Data) {
    595             newnode->SetSubTreeSize(1);
    596         }
    597         else {
    598             Node* child = NS_REINTERPRET_CAST(Node*, aElementToInsert);
    599             newnode->SetSubTreeSize(child->GetSubTreeSize());
    600         }
    601     }
    602     else {
    603         // We're meant to insert the element into the oldnode at
    604         // aSplitIndex. Copy data from aOldNode to the newnode but
    605         // _don't_ insert newnode yet. We may need to recursively
    606         // split parents, an operation that allocs, and hence, may
    607         // fail. If it does fail, we wan't to not screw up the
    608         // existing datastructure.
    609         //
    610         // Note that it should be the case that count == capacity, but
    611         // who knows, we may decide at some point to prematurely split
    612         // nodes for some reason or another.
    613         PRInt32 count = aOldNode->GetCount();
    614         PRInt32 i = aSplitIndex;
    615         PRInt32 j = 0;
    616
    617         newnode->SetCount(count - aSplitIndex);
    618         while (i < count) {
    619             if (aOldNode->GetType() == Node::eType_Data) {
    620                 ++delta;
    621             }
    622             else {
    623                 Node* migrating = NS_REINTERPRET_CAST(Node*, aOldNode->GetElementAt(i));
    624                 delta += migrating->GetSubTreeSize();
    625             }
    626
    627             newnode->SetElementAt(aOldNode->GetElementAt(i), j);
    628             ++i;
    629             ++j;
    630         }
    631         newnode->SetSubTreeSize(delta);
    632     }
    633
    634     // Now we split the node.
    635
    636     if (path.Length() == 0) {
    637         // We made it all the way up to the root! Ok, so, create a new
    638         // root
    639         Node* newroot;
    640         rv = Node::Create(Node::eType_Index, kIndexCapacity, &newroot);
    641         if (NS_FAILED(rv)) return rv;
    642
    643         newroot->SetCount(2);
    644         newroot->SetElementAt(aOldNode, 0);
    645         newroot->SetElementAt(newnode, 1);
    646         newroot->SetSubTreeSize(aOldNode->GetSubTreeSize() + 1);
    647         SetRoot(newroot);
    648     }
    649     else {
    650         // Otherwise, use the "path" to pop off the next thing above us.
    651         Node* parent;
    652         PRInt32 indx;
    653         path.Pop(&parent, &indx);
    654
    655         if (parent->GetCount() >= kIndexCapacity) {
    656             // Parent is full, too. Recursively split it.
    657             rv = Split(path, parent, newnode, indx);
    658             if (NS_FAILED(rv)) {
    659                 Node::Destroy(newnode);
    660                 return rv;
    661             }
    662         }
    663         else {
    664             // Room in the parent, so just smack it on up there.
    665             parent->InsertElementAt(newnode, indx);
    666             parent->SetSubTreeSize(parent->GetSubTreeSize() + 1);
    667         }
    668     }
    669
    670     // Now, since all our operations that might fail have finished, we
    671     // can go ahead and monkey with the old node.
    672
    673     if (aSplitIndex == capacity) {
    674         PRInt32 nodeslost = newnode->GetSubTreeSize() - 1;
    675         PRInt32 subtreesize = aOldNode->GetSubTreeSize() - nodeslost;
    676         aOldNode->SetSubTreeSize(subtreesize);
    677     }
    678     else {
    679         aOldNode->SetCount(aSplitIndex);
    680         aOldNode->InsertElementAt(aElementToInsert, aSplitIndex);
    681         PRInt32 subtreesize = aOldNode->GetSubTreeSize() - delta + 1;
    682         aOldNode->SetSubTreeSize(subtreesize);
    683     }
    684
    685     return NS_OK;
    686 }
    687
    688
    689 PRInt32
    690 nsVoidBTree::Verify(Node* aNode)
    691 {
    692     // Sanity check the tree by verifying that the subtree sizes all
    693     // add up correctly.
    694     if (aNode->GetType() == Node::eType_Data) {
    695         NS_ASSERTION(aNode->GetCount() == aNode->GetSubTreeSize(), "corrupted");
    696         return aNode->GetCount();
    697     }
    698
    699     PRInt32 childcount = 0;
    700     for (PRInt32 i = 0; i < aNode->GetCount(); ++i) {
    701         Node* child = NS_REINTERPRET_CAST(Node*, aNode->GetElementAt(i));
    702         childcount += Verify(child);
    703     }
    704
    705     NS_ASSERTION(childcount == aNode->GetSubTreeSize(), "corrupted");
    706     return childcount;
    707 }
    708
    709
    710 void
    711 nsVoidBTree::DestroySubtree(Node* aNode)
    712 {
    713     PRInt32 count = aNode->GetCount() - 1;
    714     while (count >= 0) {
    715         if (aNode->GetType() == Node::eType_Index)
    716             DestroySubtree(NS_REINTERPRET_CAST(Node*, aNode->GetElementAt(count)));
    717
    718         --count;
    719     }
    720
    721     Node::Destroy(aNode);
    722 }
    723
    724 #ifdef DEBUG
    725 void
    726 nsVoidBTree::Dump(Node* aNode, PRInt32 aIndent)
    727 {
    728     for (PRInt32 i = 0; i < aIndent; ++i)
    729         printf("  ");
    730
    731     if (aNode->GetType() == Node::eType_Data) {
    732         printf("data(%d/%d)\n", aNode->GetCount(), aNode->GetSubTreeSize());
    733     }
    734     else {
    735         printf("index(%d/%d)\n", aNode->GetCount(), aNode->GetSubTreeSize());
    736         for (PRInt32 j = 0; j < aNode->GetCount(); ++j)
    737             Dump(NS_REINTERPRET_CAST(Node*, aNode->GetElementAt(j)), aIndent + 1);
    738     }
    739 }
    740 #endif
    741
    742 //----------------------------------------------------------------------
    743 //
    744 // nsVoidBTree::ConstIterator and Iterator methods
    745 //
    746
    747 void* nsVoidBTree::kDummyLast;
    748
    749 void
    750 nsVoidBTree::ConstIterator::Next()
    751 {
    752     if (mIsSingleton) {
    753         mIsExhausted = PR_TRUE;
    754         return;
    755     }
    756
    757     // Otherwise we're a real b-tree iterator, and we need to pull and
    758     // pop our path stack appropriately to gyrate into the right
    759     // position.
    760     while (1) {
    761         Node* current;
    762         PRInt32 index;
    763         mPath.Pop(&current, &index);
    764
    765         PRInt32 count = current->GetCount();
    766
    767         NS_ASSERTION(index < count, "ran off the end, pal");
    768
    769         if (++index >= count) {
    770             // XXXwaterson Oh, this is so ugly. I wish I was smart
    771             // enough to figure out a prettier way to do it.
    772             //
    773             // See if we've just iterated past the last element in the
    774             // b-tree, and now need to leave ourselves in the magical
    775             // state that is equal to nsVoidBTree::Last().
    776             if (current->GetType() == Node::eType_Data) {
    777                 PRBool rightmost = PR_TRUE;
    778                 for (PRInt32 slot = mPath.mTop - 1; slot >= 0; --slot) {
    779                     const Link& link = mPath.mLink[slot];
    780                     if (link.mIndex != link.mNode->GetCount() - 1) {
    781                         rightmost = PR_FALSE;
    782                         break;
    783                     }
    784                 }
    785
    786                 if (rightmost) {
    787                     // It's the last one. Make the path look exactly
    788                     // like nsVoidBTree::Last().
    789                     mPath.Push(current, index);
    790                     return;
    791                 }
    792             }
    793
    794             // Otherwise, we just ran off the end of a "middling"
    795             // node. Loop around, to pop back up the b-tree to its
    796             // parent.
    797             continue;
    798         }
    799
    800         // We're somewhere in the middle. Push the new location onto
    801         // the stack.
    802         mPath.Push(current, index);
    803
    804         // If we're in a data node, we're done: break out of the loop
    805         // here leaving the top of the stack pointing to the next data
    806         // element in the b-tree.
    807         if (current->GetType() == Node::eType_Data)
    808             break;
    809
    810         // Otherwise, we're still in an index node. Push next node
    811         // down onto the stack, starting "one off" to the left, and
    812         // continue around.
    813         mPath.Push(NS_STATIC_CAST(Node*, current->GetElementAt(index)), -1);
    814     }
    815 }
    816
    817 void
    818 nsVoidBTree::ConstIterator::Prev()
    819 {
    820     if (mIsSingleton) {
    821         mIsExhausted = PR_FALSE;
    822         return;
    823     }
    824
    825     // Otherwise we're a real b-tree iterator, and we need to pull and
    826     // pop our path stack appropriately to gyrate into the right
    827     // position. This is just like nsVoidBTree::ConstIterator::Next(),
    828     // but in reverse.
    829     while (1) {
    830         Node* current;
    831         PRInt32 index;
    832         mPath.Pop(&current, &index);
    833
    834         NS_ASSERTION(index >= 0, "ran off the front, pal");
    835
    836         if (--index < 0)
    837             continue;
    838
    839         mPath.Push(current, index);
    840
    841         if (current->GetType() == Node::eType_Data)
    842             break;
    843
    844         current = NS_STATIC_CAST(Node*, current->GetElementAt(index));
    845         mPath.Push(current, current->GetCount());
    846     }
    847 }
    848
    849 const nsVoidBTree::Path
    850 nsVoidBTree::LeftMostPath() const
    851 {
    852     Path path;
    853     Node* current = NS_REINTERPRET_CAST(Node*, mRoot & kRoot_PointerMask);
    854
    855     while (1) {
    856         path.Push(current, 0);
    857
    858         if (current->GetType() == Node::eType_Data)
    859             break;
    860
    861         current = NS_STATIC_CAST(Node*, current->GetElementAt(0));
    862     }
    863
    864     return path;
    865 }
    866
    867
    868 const nsVoidBTree::Path
    869 nsVoidBTree::RightMostPath() const
    870 {
    871     Path path;
    872     Node* current = NS_REINTERPRET_CAST(Node*, mRoot & kRoot_PointerMask);
    873
    874     while (1) {
    875         PRInt32 count = current->GetCount();
    876
    877         if (current->GetType() == Node::eType_Data) {
    878             path.Push(current, count);
    879             break;
    880         }
    881
    882         path.Push(current, count - 1);
    883         current = NS_STATIC_CAST(Node*, current->GetElementAt(count - 1));
    884     }
    885
    886     return path;
    887 }
    888

This page was automatically generated by LXR.