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.