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