|
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(¤t, &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(¤t, &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(¤t, &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(¤t, &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(¤t, &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(¤t, &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.