From 16de08bc3fdad4affad3b06f4aeea3c876cd6406 Mon Sep 17 00:00:00 2001 From: "alecf%flett.org" Date: Fri, 30 May 2003 06:00:51 +0000 Subject: [PATCH] remove these files, they aren't built any more git-svn-id: svn://10.0.0.236/trunk@143087 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/xpcom/ds/nsVoidBTree.cpp | 853 ------------------------------- mozilla/xpcom/ds/nsVoidBTree.h | 443 ---------------- 2 files changed, 1296 deletions(-) delete mode 100644 mozilla/xpcom/ds/nsVoidBTree.cpp delete mode 100644 mozilla/xpcom/ds/nsVoidBTree.h diff --git a/mozilla/xpcom/ds/nsVoidBTree.cpp b/mozilla/xpcom/ds/nsVoidBTree.cpp deleted file mode 100644 index f5c43e687fe..00000000000 --- a/mozilla/xpcom/ds/nsVoidBTree.cpp +++ /dev/null @@ -1,853 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "MPL"); you may not use this file except in - * compliance with the MPL. You may obtain a copy of the MPL at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the MPL is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the MPL - * for the specific language governing rights and limitations under the - * MPL. - * - * The Initial Developer of this code under the MPL is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1999 Netscape Communications Corporation. All Rights - * Reserved. - * - * Original Author: - * Chris Waterson - */ - -#include "nsVoidBTree.h" - -#ifdef DEBUG -#include -#endif - -// Set this to force the tree to be verified after every insertion and -// removal. -//#define PARANOID 1 - - -//---------------------------------------------------------------------- -// nsVoidBTree::Node -// -// Implementation methods -// - -nsresult -nsVoidBTree::Node::Create(Type aType, PRInt32 aCapacity, Node** aResult) -{ - // So we only ever have to do one allocation for a Node, we do a - // "naked" heap allocation, computing the size of the node and - // "padding" it out so that it can hold aCapacity slots. - char* bytes = new char[sizeof(Node) + (aCapacity - 1) * sizeof(void*)]; - if (! bytes) - return NS_ERROR_OUT_OF_MEMORY; - - Node* result = NS_REINTERPRET_CAST(Node*, bytes); - result->mBits = 0; - result->SetType(aType); - - *aResult = result; - return NS_OK; -} - -nsresult -nsVoidBTree::Node::Destroy(Node* aNode) -{ - char* bytes = NS_REINTERPRET_CAST(char*, aNode); - delete[] bytes; - return NS_OK; -} - -void -nsVoidBTree::Node::InsertElementAt(void* aElement, PRInt32 aIndex) -{ - NS_PRECONDITION(aIndex >= 0 && aIndex <= GetCount(), "bad index"); - - PRInt32 count = GetCount(); - SetCount(count + 1); - - while (count > aIndex) { - mData[count] = mData[count - 1]; - --count; - } - - mData[aIndex] = aElement; -} - -void -nsVoidBTree::Node::RemoveElementAt(PRInt32 aIndex) -{ - NS_PRECONDITION(aIndex >= 0 && aIndex < GetCount(), "bad index"); - - PRInt32 count = GetCount(); - SetCount(count - 1); - - while (aIndex < count) { - mData[aIndex] = mData[aIndex + 1]; - ++aIndex; - } -} - - -//---------------------------------------------------------------------- -// -// nsVoidBTree::Path -// -// Implementation methods -// - -nsVoidBTree::Path::Path(const Path& aOther) - : mTop(aOther.mTop) -{ - for (PRInt32 i = 0; i < mTop; ++i) - mLink[i] = aOther.mLink[i]; -} - -nsVoidBTree::Path& -nsVoidBTree::Path::operator=(const Path& aOther) -{ - mTop = aOther.mTop; - for (PRInt32 i = 0; i < mTop; ++i) - mLink[i] = aOther.mLink[i]; - return *this; -} - -inline nsresult -nsVoidBTree::Path::Push(Node* aNode, PRInt32 aIndex) -{ - // XXX If you overflow this thing, think about making larger index - // or data nodes. You can pack a _lot_ of data into a pretty flat - // tree. - NS_PRECONDITION(mTop <= kMaxDepth, "overflow"); - if (mTop > kMaxDepth) - return NS_ERROR_OUT_OF_MEMORY; - - mLink[mTop].mNode = aNode; - mLink[mTop].mIndex = aIndex; - ++mTop; - - return NS_OK; -} - - -inline void -nsVoidBTree::Path::Pop(Node** aNode, PRInt32* aIndex) -{ - --mTop; - *aNode = mLink[mTop].mNode; - *aIndex = mLink[mTop].mIndex; -} - -//---------------------------------------------------------------------- -// -// nsVoidBTree methods -// - -nsVoidBTree::nsVoidBTree(const nsVoidBTree& aOther) -{ - ConstIterator last = aOther.Last(); - for (ConstIterator element = aOther.First(); element != last; ++element) - AppendElement(*element); -} - -nsVoidBTree& -nsVoidBTree::operator=(const nsVoidBTree& aOther) -{ - Clear(); - ConstIterator last = aOther.Last(); - for (ConstIterator element = aOther.First(); element != last; ++element) - AppendElement(*element); - return *this; -} - -PRInt32 -nsVoidBTree::Count() const -{ - if (IsEmpty()) - return 0; - - if (IsSingleElement()) - return 1; - - Node* root = NS_REINTERPRET_CAST(Node*, mRoot & kRoot_PointerMask); - return root->GetSubTreeSize(); -} - -void* -nsVoidBTree::ElementAt(PRInt32 aIndex) const -{ - NS_ASSERTION(aIndex >= 0,"nsVoidBTree::ElementAt negative index!"); - NS_ASSERTION(aIndex < Count(),"nsVoidBTree::ElementAt past end"); - if (aIndex < 0 || aIndex >= Count()) - return nsnull; - - if (IsSingleElement()) - return NS_REINTERPRET_CAST(void*, mRoot & kRoot_PointerMask); - - Node* current = NS_REINTERPRET_CAST(Node*, mRoot & kRoot_PointerMask); - while (current->GetType() != Node::eType_Data) { - // We're still in the index. Find the right leaf. - Node* next = nsnull; - - PRInt32 count = current->GetCount(); - for (PRInt32 i = 0; i < count; ++i) { - Node* child = NS_REINTERPRET_CAST(Node*, current->GetElementAt(i)); - - PRInt32 childcount = child->GetSubTreeSize(); - if (PRInt32(aIndex) < childcount) { - next = child; - break; - } - - aIndex -= childcount; - } - - if (! next) { - NS_ERROR("corrupted"); - return nsnull; - } - - current = next; - } - - return current->GetElementAt(aIndex); -} - - -PRInt32 -nsVoidBTree::IndexOf(void* aPossibleElement) const -{ - NS_PRECONDITION((PRWord(aPossibleElement) & ~kRoot_PointerMask) == 0, - "uh oh, someone wants to use the pointer bits"); - - NS_PRECONDITION(aPossibleElement != nsnull, "nsVoidBTree can't handle null elements"); - if (aPossibleElement == nsnull) - return -1; - - PRInt32 result = 0; - ConstIterator last = Last(); - for (ConstIterator element = First(); element != last; ++element, ++result) { - if (aPossibleElement == *element) - return result; - } - - return -1; -} - - -PRBool -nsVoidBTree::InsertElementAt(void* aElement, PRInt32 aIndex) -{ - NS_PRECONDITION((PRWord(aElement) & ~kRoot_PointerMask) == 0, - "uh oh, someone wants to use the pointer bits"); - - if ((PRWord(aElement) & ~kRoot_PointerMask) != 0) - return PR_FALSE; - - NS_PRECONDITION(aElement != nsnull, "nsVoidBTree can't handle null elements"); - if (aElement == nsnull) - return PR_FALSE; - - PRInt32 count = Count(); - - if (aIndex < 0 || aIndex > count) - return PR_FALSE; - - nsresult rv; - - if (IsSingleElement()) { - // We're only a single element holder, and haven't yet - // "faulted" to create the btree. - - if (count == 0) { - // If we have *no* elements, then just set the root - // pointer and we're done. - mRoot = PRWord(aElement); - return PR_TRUE; - } - - // If we already had an element, and now we're adding - // another. Fault and start creating the btree. - void* element = NS_REINTERPRET_CAST(void*, mRoot & kRoot_PointerMask); - - Node* newroot; - rv = Node::Create(Node::eType_Data, kDataCapacity, &newroot); - if (NS_FAILED(rv)) return PR_FALSE; - - newroot->InsertElementAt(element, 0); - newroot->SetSubTreeSize(1); - SetRoot(newroot); - } - - Path path; - - Node* current = NS_REINTERPRET_CAST(Node*, mRoot & kRoot_PointerMask); - while (current->GetType() != Node::eType_Data) { - // We're still in the index. Find the right leaf. - Node* next = nsnull; - - count = current->GetCount(); - for (PRInt32 i = 0; i < count; ++i) { - Node* child = NS_REINTERPRET_CAST(Node*, current->GetElementAt(i)); - - PRInt32 childcount = child->GetSubTreeSize(); - if (PRInt32(aIndex) <= childcount) { - rv = path.Push(current, i + 1); - if (NS_FAILED(rv)) return PR_FALSE; - - next = child; - break; - } - - aIndex -= childcount; - } - - if (! next) { - NS_ERROR("corrupted"); - return PR_FALSE; - } - - current = next; - } - - if (current->GetCount() >= kDataCapacity) { - // We just blew the data node's buffer. Create another - // datanode and split. - rv = Split(path, current, aElement, aIndex); - if (NS_FAILED(rv)) return PR_FALSE; - } - else { - current->InsertElementAt(aElement, aIndex); - current->SetSubTreeSize(current->GetSubTreeSize() + 1); - } - - while (path.Length() > 0) { - PRInt32 index; - path.Pop(¤t, &index); - current->SetSubTreeSize(current->GetSubTreeSize() + 1); - } - -#ifdef PARANOID - Verify(NS_REINTERPRET_CAST(Node*, mRoot & kRoot_PointerMask)); -#endif - - return PR_TRUE; -} - -PRBool -nsVoidBTree::ReplaceElementAt(void* aElement, PRInt32 aIndex) -{ - NS_PRECONDITION((PRWord(aElement) & ~kRoot_PointerMask) == 0, - "uh oh, someone wants to use the pointer bits"); - - if ((PRWord(aElement) & ~kRoot_PointerMask) != 0) - return PR_FALSE; - - NS_PRECONDITION(aElement != nsnull, "nsVoidBTree can't handle null elements"); - if (aElement == nsnull) - return PR_FALSE; - - if (aIndex < 0 || aIndex >= Count()) - return PR_FALSE; - - if (IsSingleElement()) { - mRoot = PRWord(aElement); - return PR_TRUE; - } - - Node* current = NS_REINTERPRET_CAST(Node*, mRoot & kRoot_PointerMask); - while (current->GetType() != Node::eType_Data) { - // We're still in the index. Find the right leaf. - Node* next = nsnull; - - PRInt32 count = current->GetCount(); - for (PRInt32 i = 0; i < count; ++i) { - Node* child = NS_REINTERPRET_CAST(Node*, current->GetElementAt(i)); - - PRInt32 childcount = child->GetSubTreeSize(); - if (PRInt32(aIndex) < childcount) { - next = child; - break; - } - - aIndex -= childcount; - } - - if (! next) { - NS_ERROR("corrupted"); - return PR_FALSE; - } - - current = next; - } - - current->SetElementAt(aElement, aIndex); - return PR_TRUE; -} - -PRBool -nsVoidBTree::RemoveElement(void* aElement) -{ - PRInt32 index = IndexOf(aElement); - return (index >= 0) ? RemoveElementAt(index) : PR_FALSE; -} - -PRBool -nsVoidBTree::RemoveElementAt(PRInt32 aIndex) -{ - PRInt32 count = Count(); - - if (aIndex < 0 || aIndex >= count) - return PR_FALSE; - - if (IsSingleElement()) { - // We're removing the one and only element - mRoot = 0; - return PR_TRUE; - } - - // We've got more than one element, and we're removing it. - nsresult rv; - Path path; - - Node* root = NS_REINTERPRET_CAST(Node*, mRoot & kRoot_PointerMask); - - Node* current = root; - while (current->GetType() != Node::eType_Data) { - // We're still in the index. Find the right leaf. - Node* next = nsnull; - - count = current->GetCount(); - for (PRInt32 i = 0; i < count; ++i) { - Node* child = NS_REINTERPRET_CAST(Node*, current->GetElementAt(i)); - - PRInt32 childcount = child->GetSubTreeSize(); - if (PRInt32(aIndex) < childcount) { - rv = path.Push(current, i); - if (NS_FAILED(rv)) return PR_FALSE; - - next = child; - break; - } - - aIndex -= childcount; - } - - if (! next) { - NS_ERROR("corrupted"); - return PR_FALSE; - } - - current = next; - } - - current->RemoveElementAt(aIndex); - - while ((current->GetCount() == 0) && (current != root)) { - Node* doomed = current; - - PRInt32 index; - path.Pop(¤t, &index); - current->RemoveElementAt(index); - - Node::Destroy(doomed); - } - - current->SetSubTreeSize(current->GetSubTreeSize() - 1); - - while (path.Length() > 0) { - PRInt32 index; - path.Pop(¤t, &index); - current->SetSubTreeSize(current->GetSubTreeSize() - 1); - } - - while ((root->GetType() == Node::eType_Index) && (root->GetCount() == 1)) { - Node* doomed = root; - root = NS_REINTERPRET_CAST(Node*, root->GetElementAt(0)); - SetRoot(root); - Node::Destroy(doomed); - } - -#ifdef PARANOID - Verify(root); -#endif - - return PR_TRUE; -} - -void -nsVoidBTree::Clear(void) -{ - if (IsEmpty()) - return; - - if (! IsSingleElement()) { - Node* root = NS_REINTERPRET_CAST(Node*, mRoot & kRoot_PointerMask); - -#ifdef PARANOID - Dump(root, 0); -#endif - - DestroySubtree(root); - } - - mRoot = 0; -} - - -void -nsVoidBTree::Compact(void) -{ - // XXX We could go through and try to merge datanodes. -} - -PRBool -nsVoidBTree::EnumerateForwards(EnumFunc aFunc, void* aData) const -{ - PRBool running = PR_TRUE; - - ConstIterator last = Last(); - for (ConstIterator element = First(); running && element != last; ++element) - running = (*aFunc)(*element, aData); - - return running; -} - -PRBool -nsVoidBTree::EnumerateBackwards(EnumFunc aFunc, void* aData) const -{ - PRBool running = PR_TRUE; - - ConstIterator element = Last(); - ConstIterator first = First(); - - if (element != first) { - do { - running = (*aFunc)(*--element, aData); - } while (running && element != first); - } - - return running; -} - -//---------------------------------------------------------------------- - -nsresult -nsVoidBTree::Split(Path& path, Node* aOldNode, void* aElementToInsert, PRInt32 aSplitIndex) -{ - nsresult rv; - - PRInt32 capacity = (aOldNode->GetType() == Node::eType_Data) ? kDataCapacity : kIndexCapacity; - PRInt32 delta = 0; - - - Node* newnode; - rv = Node::Create(aOldNode->GetType(), capacity, &newnode); - if (NS_FAILED(rv)) return rv; - - if (aSplitIndex == capacity) { - // If aSplitIndex is the same as the capacity of the node, - // then there'll be nothing to copy from the old node to the - // new node, and the element is really meant to be inserted in - // the newnode. In that case, do it _now_ so that newnode's - // subtree size will be correct. - newnode->InsertElementAt(aElementToInsert, 0); - - if (newnode->GetType() == Node::eType_Data) { - newnode->SetSubTreeSize(1); - } - else { - Node* child = NS_REINTERPRET_CAST(Node*, aElementToInsert); - newnode->SetSubTreeSize(child->GetSubTreeSize()); - } - } - else { - // We're meant to insert the element into the oldnode at - // aSplitIndex. Copy data from aOldNode to the newnode but - // _don't_ insert newnode yet. We may need to recursively - // split parents, an operation that allocs, and hence, may - // fail. If it does fail, we wan't to not screw up the - // existing datastructure. - // - // Note that it should be the case that count == capacity, but - // who knows, we may decide at some point to prematurely split - // nodes for some reason or another. - PRInt32 count = aOldNode->GetCount(); - PRInt32 i = aSplitIndex; - PRInt32 j = 0; - - newnode->SetCount(count - aSplitIndex); - while (i < count) { - if (aOldNode->GetType() == Node::eType_Data) { - ++delta; - } - else { - Node* migrating = NS_REINTERPRET_CAST(Node*, aOldNode->GetElementAt(i)); - delta += migrating->GetSubTreeSize(); - } - - newnode->SetElementAt(aOldNode->GetElementAt(i), j); - ++i; - ++j; - } - newnode->SetSubTreeSize(delta); - } - - // Now we split the node. - - if (path.Length() == 0) { - // We made it all the way up to the root! Ok, so, create a new - // root - Node* newroot; - rv = Node::Create(Node::eType_Index, kIndexCapacity, &newroot); - if (NS_FAILED(rv)) return rv; - - newroot->SetCount(2); - newroot->SetElementAt(aOldNode, 0); - newroot->SetElementAt(newnode, 1); - newroot->SetSubTreeSize(aOldNode->GetSubTreeSize() + 1); - SetRoot(newroot); - } - else { - // Otherwise, use the "path" to pop off the next thing above us. - Node* parent; - PRInt32 indx; - path.Pop(&parent, &indx); - - if (parent->GetCount() >= kIndexCapacity) { - // Parent is full, too. Recursively split it. - rv = Split(path, parent, newnode, indx); - if (NS_FAILED(rv)) { - Node::Destroy(newnode); - return rv; - } - } - else { - // Room in the parent, so just smack it on up there. - parent->InsertElementAt(newnode, indx); - parent->SetSubTreeSize(parent->GetSubTreeSize() + 1); - } - } - - // Now, since all our operations that might fail have finished, we - // can go ahead and monkey with the old node. - - if (aSplitIndex == capacity) { - PRInt32 nodeslost = newnode->GetSubTreeSize() - 1; - PRInt32 subtreesize = aOldNode->GetSubTreeSize() - nodeslost; - aOldNode->SetSubTreeSize(subtreesize); - } - else { - aOldNode->SetCount(aSplitIndex); - aOldNode->InsertElementAt(aElementToInsert, aSplitIndex); - PRInt32 subtreesize = aOldNode->GetSubTreeSize() - delta + 1; - aOldNode->SetSubTreeSize(subtreesize); - } - - return NS_OK; -} - - -PRInt32 -nsVoidBTree::Verify(Node* aNode) -{ - // Sanity check the tree by verifying that the subtree sizes all - // add up correctly. - if (aNode->GetType() == Node::eType_Data) { - NS_ASSERTION(aNode->GetCount() == aNode->GetSubTreeSize(), "corrupted"); - return aNode->GetCount(); - } - - PRInt32 childcount = 0; - for (PRInt32 i = 0; i < aNode->GetCount(); ++i) { - Node* child = NS_REINTERPRET_CAST(Node*, aNode->GetElementAt(i)); - childcount += Verify(child); - } - - NS_ASSERTION(childcount == aNode->GetSubTreeSize(), "corrupted"); - return childcount; -} - - -void -nsVoidBTree::DestroySubtree(Node* aNode) -{ - PRInt32 count = aNode->GetCount() - 1; - while (count >= 0) { - if (aNode->GetType() == Node::eType_Index) - DestroySubtree(NS_REINTERPRET_CAST(Node*, aNode->GetElementAt(count))); - - --count; - } - - Node::Destroy(aNode); -} - -#ifdef DEBUG -void -nsVoidBTree::Dump(Node* aNode, PRInt32 aIndent) -{ - for (PRInt32 i = 0; i < aIndent; ++i) - printf(" "); - - if (aNode->GetType() == Node::eType_Data) { - printf("data(%d/%d)\n", aNode->GetCount(), aNode->GetSubTreeSize()); - } - else { - printf("index(%d/%d)\n", aNode->GetCount(), aNode->GetSubTreeSize()); - for (PRInt32 j = 0; j < aNode->GetCount(); ++j) - Dump(NS_REINTERPRET_CAST(Node*, aNode->GetElementAt(j)), aIndent + 1); - } -} -#endif - -//---------------------------------------------------------------------- -// -// nsVoidBTree::ConstIterator and Iterator methods -// - -void* nsVoidBTree::kDummyLast; - -void -nsVoidBTree::ConstIterator::Next() -{ - if (mIsSingleton) { - mIsExhausted = PR_TRUE; - return; - } - - // Otherwise we're a real b-tree iterator, and we need to pull and - // pop our path stack appropriately to gyrate into the right - // position. - while (1) { - Node* current; - PRInt32 index; - mPath.Pop(¤t, &index); - - PRInt32 count = current->GetCount(); - - NS_ASSERTION(index < count, "ran off the end, pal"); - - if (++index >= count) { - // XXXwaterson Oh, this is so ugly. I wish I was smart - // enough to figure out a prettier way to do it. - // - // See if we've just iterated past the last element in the - // b-tree, and now need to leave ourselves in the magical - // state that is equal to nsVoidBTree::Last(). - if (current->GetType() == Node::eType_Data) { - PRBool rightmost = PR_TRUE; - for (PRInt32 slot = mPath.mTop - 1; slot >= 0; --slot) { - const Link& link = mPath.mLink[slot]; - if (link.mIndex != link.mNode->GetCount() - 1) { - rightmost = PR_FALSE; - break; - } - } - - if (rightmost) { - // It's the last one. Make the path look exactly - // like nsVoidBTree::Last(). - mPath.Push(current, index); - return; - } - } - - // Otherwise, we just ran off the end of a "middling" - // node. Loop around, to pop back up the b-tree to its - // parent. - continue; - } - - // We're somewhere in the middle. Push the new location onto - // the stack. - mPath.Push(current, index); - - // If we're in a data node, we're done: break out of the loop - // here leaving the top of the stack pointing to the next data - // element in the b-tree. - if (current->GetType() == Node::eType_Data) - break; - - // Otherwise, we're still in an index node. Push next node - // down onto the stack, starting "one off" to the left, and - // continue around. - mPath.Push(NS_STATIC_CAST(Node*, current->GetElementAt(index)), -1); - } -} - -void -nsVoidBTree::ConstIterator::Prev() -{ - if (mIsSingleton) { - mIsExhausted = PR_FALSE; - return; - } - - // Otherwise we're a real b-tree iterator, and we need to pull and - // pop our path stack appropriately to gyrate into the right - // position. This is just like nsVoidBTree::ConstIterator::Next(), - // but in reverse. - while (1) { - Node* current; - PRInt32 index; - mPath.Pop(¤t, &index); - - NS_ASSERTION(index >= 0, "ran off the front, pal"); - - if (--index < 0) - continue; - - mPath.Push(current, index); - - if (current->GetType() == Node::eType_Data) - break; - - current = NS_STATIC_CAST(Node*, current->GetElementAt(index)); - mPath.Push(current, current->GetCount()); - } -} - -const nsVoidBTree::Path -nsVoidBTree::LeftMostPath() const -{ - Path path; - Node* current = NS_REINTERPRET_CAST(Node*, mRoot & kRoot_PointerMask); - - while (1) { - path.Push(current, 0); - - if (current->GetType() == Node::eType_Data) - break; - - current = NS_STATIC_CAST(Node*, current->GetElementAt(0)); - } - - return path; -} - - -const nsVoidBTree::Path -nsVoidBTree::RightMostPath() const -{ - Path path; - Node* current = NS_REINTERPRET_CAST(Node*, mRoot & kRoot_PointerMask); - - while (1) { - PRInt32 count = current->GetCount(); - - if (current->GetType() == Node::eType_Data) { - path.Push(current, count); - break; - } - - path.Push(current, count - 1); - current = NS_STATIC_CAST(Node*, current->GetElementAt(count - 1)); - } - - return path; -} diff --git a/mozilla/xpcom/ds/nsVoidBTree.h b/mozilla/xpcom/ds/nsVoidBTree.h deleted file mode 100644 index 865f2974cb9..00000000000 --- a/mozilla/xpcom/ds/nsVoidBTree.h +++ /dev/null @@ -1,443 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "MPL"); you may not use this file except in - * compliance with the MPL. You may obtain a copy of the MPL at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the MPL is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the MPL - * for the specific language governing rights and limitations under the - * MPL. - * - * The Initial Developer of this code under the MPL is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1999 Netscape Communications Corporation. All Rights - * Reserved. - * - * Original Author: - * Chris Waterson - */ - -#ifndef nsVoidBTree_h__ -#define nsVoidBTree_h__ - -#include "nscore.h" -#include "nsDebug.h" -#include "nsError.h" - -/** - * An nsVoidArray-compatible class that is implemented as a B-tree - * rather than an array. - */ -class NS_COM nsVoidBTree -{ -public: - nsVoidBTree() : mRoot(0) {} - - virtual ~nsVoidBTree() { Clear(); } - - nsVoidBTree(const nsVoidBTree& aOther); - - nsVoidBTree& operator=(const nsVoidBTree& aOther); - - PRInt32 Count() const; - - void* ElementAt(PRInt32 aIndex) const; - - void* operator[](PRInt32 aIndex) const { - return ElementAt(aIndex); } - - PRInt32 IndexOf(void* aPossibleElement) const; - - PRBool InsertElementAt(void* aElement, PRInt32 aIndex); - - PRBool ReplaceElementAt(void* aElement, PRInt32 aIndex); - - PRBool AppendElement(void* aElement) { - return InsertElementAt(aElement, Count()); } - - PRBool RemoveElement(void* aElement); - - PRBool RemoveElementAt(PRInt32 aIndex); - - void Clear(); - - void Compact(); - - /** - * Enumerator callback function. Return PR_FALSE to stop - */ - typedef PRBool (*PR_CALLBACK EnumFunc)(void* aElement, void *aData); - - PRBool EnumerateForwards(EnumFunc aFunc, void* aData) const; - PRBool EnumerateBackwards(EnumFunc aFunc, void* aData) const; - -protected: - // This is as deep as a tree can ever grow, mostly because we use an - // automatic variable to keep track of the path we take through the - // tree while inserting and removing stuff. - enum { kMaxDepth = 8 }; - - //---------------------------------------- - - /** - * A node in the b-tree, either data or index - */ - class Node { - public: - enum Type { eType_Data = 0, eType_Index = 1 }; - - enum { - kTypeBit = 0x80000000, - kCountShift = 24, - kCountMask = 0x7f000000, - kMaxCapacity = kCountMask, - kSubTreeSizeMask = 0x00ffffff, - kMaxSubTreeSize = kSubTreeSizeMask - }; - - protected: - /** - * High bit is the type (data or index), next 7 bits are the - * number of elements in the node, low 24 bits is the subtree - * size. - */ - PRUint32 mBits; - - /** - * This node's data; when a Node allocated, this is actually - * filled in to contain kDataCapacity or kIndexCapacity slots. - */ - void* mData[1]; - - public: - static nsresult Create(Type aType, PRInt32 aCapacity, Node** aResult); - static nsresult Destroy(Node* aNode); - - Type GetType() const { - return (mBits & kTypeBit) ? eType_Index : eType_Data; } - - void SetType(Type aType) { - if (aType == eType_Data) - mBits &= ~kTypeBit; - else - mBits |= kTypeBit; - } - - PRInt32 GetSubTreeSize() const { - return PRInt32(mBits & kSubTreeSizeMask); } - - void SetSubTreeSize(PRInt32 aSubTreeSize) { - mBits &= ~kSubTreeSizeMask; - mBits |= PRUint32(aSubTreeSize) & kSubTreeSizeMask; } - - PRInt32 GetCount() const { return PRInt32((mBits & kCountMask) >> kCountShift); } - - void SetCount(PRInt32 aCount) { - NS_PRECONDITION(aCount < PRInt32(kMaxCapacity), "overflow"); - mBits &= ~kCountMask; - mBits |= (PRUint32(aCount) << kCountShift) & kCountMask; } - - void* GetElementAt(PRInt32 aIndex) const { - NS_PRECONDITION(aIndex >= 0 && aIndex < GetCount(), "bad index"); - return mData[aIndex]; } - - void*& GetElementAt(PRInt32 aIndex) { - NS_PRECONDITION(aIndex >= 0 && aIndex < GetCount(), "bad index"); - return mData[aIndex]; } - - void SetElementAt(void* aElement, PRInt32 aIndex) { - NS_PRECONDITION(aIndex >= 0 && aIndex < GetCount(), "bad index"); - mData[aIndex] = aElement; } - - void InsertElementAt(void* aElement, PRInt32 aIndex); - void RemoveElementAt(PRInt32 aIndex); - - protected: - // XXX Not to be implemented - Node(); - ~Node(); - }; - - //---------------------------------------- - class Path; - friend class Path; - - struct Link; - friend struct Link; - - // XXXwaterson Kinda gross this is all public, but I couldn't - // figure out a better way to detect termination in - // ConstIterator::Next(). It's a s3kret class anyway. This isn't - // contained inside nsVoidBTree::Path because doing so breaks some - // compilers. - struct Link { - Node* mNode; - PRInt32 mIndex; - - Link& - operator=(const Link& aOther) { - mNode = aOther.mNode; - mIndex = aOther.mIndex; - return *this; } - - PRBool operator==(const Link& aOther) const { - return mNode == aOther.mNode && mIndex == aOther.mIndex; } - - PRBool operator!=(const Link& aOther) const { - return !aOther.operator==(*this); } - }; - - /** - * A path through the b-tree, used to avoid recursion and - * maintain state in iterators. - */ - class NS_COM Path { - public: - Link mLink[kMaxDepth]; - PRInt32 mTop; - - Path() : mTop(0) {} - - Path(const Path& aOther); - Path& operator=(const Path& aOther); - - PRBool operator==(const Path& aOther) const { - if (mTop != aOther.mTop) - return PR_FALSE; - PRInt32 last = mTop - 1; - if (last >= 0 && mLink[last] != aOther.mLink[last]) - return PR_FALSE; - return PR_TRUE; } - - PRBool operator!=(const Path& aOther) const { - return !aOther.operator==(*this); } - - inline nsresult Push(Node* aNode, PRInt32 aIndex); - inline void Pop(Node** aNode, PRInt32* aIndex); - - PRInt32 Length() const { return mTop; } - - Node* TopNode() const { return mLink[mTop - 1].mNode; } - PRInt32 TopIndex() const { return mLink[mTop - 1].mIndex; } - }; - - /** - * A tagged pointer: if it's null, the b-tree is empty. If it's - * non-null, and the low-bit is clear, it points to a single - * element. If it's non-null, and the low-bit is set, it points to - * a Node object. - */ - PRWord mRoot; - - enum { - kRoot_TypeBit = 1, - kRoot_SingleElement = 0, - kRoot_Node = 1, - kRoot_PointerMask = ~kRoot_TypeBit - }; - - // Bit twiddlies - PRBool IsEmpty() const { return mRoot == 0; } - - PRBool IsSingleElement() const { - return (mRoot & kRoot_TypeBit) == kRoot_SingleElement; } - - void SetRoot(Node* aNode) { - mRoot = PRWord(aNode) | kRoot_Node; } - - enum { - // This is tuned based on distribution data from nsVoidArray - // that indicated that, during a "normal run" of mozilla, we'd - // be able to fit about 90% of the nsVoidArray's contents into - // an eight element array. - // - // If you decide to change these values, update kMaxDepth - // appropriately so that we can fit kMaxSubTreeSize elements - // in here. - kDataCapacity = 8, - kIndexCapacity = 8 - }; - - nsresult Split(Path& path, Node* aOldNode, void* aElementToInsert, PRInt32 aSplitIndex); - PRInt32 Verify(Node* aNode); - void DestroySubtree(Node* aNode); - -#ifdef DEBUG - void Dump(Node* aNode, PRInt32 aIndent); -#endif - -public: - - class ConstIterator; - friend class ConstIterator; - - class Iterator; - friend class Iterator; - - /** - * A "const" bidirectional iterator over the nsVoidBTree. Supports - * the usual iteration interface. - */ - class NS_COM ConstIterator { - protected: - friend class Iterator; // XXXwaterson broken - - PRPackedBool mIsSingleton; - PRPackedBool mIsExhausted; - PRWord mElement; - Path mPath; - - void Next(); - void Prev(); - - public: - ConstIterator() : mIsSingleton(PR_TRUE), mElement(nsnull) {} - - ConstIterator(const ConstIterator& aOther) : mIsSingleton(aOther.mIsSingleton) { - if (mIsSingleton) { - mElement = aOther.mElement; - mIsExhausted = aOther.mIsExhausted; - } - else { - mPath = aOther.mPath; } } - - ConstIterator& - operator=(const ConstIterator& aOther) { - mIsSingleton = aOther.mIsSingleton; - if (mIsSingleton) { - mElement = aOther.mElement; - mIsExhausted = aOther.mIsExhausted; - } - else { - mPath = aOther.mPath; - } - return *this; } - - void* operator*() const { - return mIsSingleton - ? NS_REINTERPRET_CAST(void*, !mIsExhausted ? mElement : 0) - : mPath.TopNode()->GetElementAt(mPath.TopIndex()); } - - ConstIterator& operator++() { - Next(); - return *this; } - - ConstIterator operator++(int) { - ConstIterator temp(*this); - Next(); - return temp; } - - ConstIterator& operator--() { - Prev(); - return *this; } - - ConstIterator operator--(int) { - ConstIterator temp(*this); - Prev(); - return temp; } - - PRBool operator==(const ConstIterator& aOther) const { - return mIsSingleton - ? (mElement == aOther.mElement && mIsExhausted == aOther.mIsExhausted) - : mPath == aOther.mPath; } - - PRBool operator!=(const ConstIterator& aOther) const { - return !aOther.operator==(*this); } - - protected: - friend class nsVoidBTree; - ConstIterator(PRWord aElement, PRBool aIsExhausted) - : mIsSingleton(PR_TRUE), mIsExhausted(aElement ? aIsExhausted : PR_TRUE), mElement(aElement) {} - - ConstIterator(const Path& aPath) - : mIsSingleton(PR_FALSE), mPath(aPath) {} - }; - - /** - * The first element in the nsVoidBTree - */ - ConstIterator First() const { - return IsSingleElement() ? ConstIterator(mRoot, PR_FALSE) : ConstIterator(LeftMostPath()); } - - /** - * "One past" the last element in the nsVoidBTree - */ - ConstIterator Last() const { - return IsSingleElement() ? ConstIterator(mRoot, PR_TRUE) : ConstIterator(RightMostPath()); } - - class Iterator : public ConstIterator { - protected: - void** mElementRef; - - public: - Iterator() {} - - Iterator(const Iterator& aOther) - : ConstIterator(aOther), - mElementRef(aOther.mElementRef) {} - - Iterator& - operator=(const Iterator& aOther) { - ConstIterator::operator=(aOther); - mElementRef = aOther.mElementRef; - return *this; } - - Iterator& operator++() { - Next(); - return *this; } - - Iterator operator++(int) { - Iterator temp(*this); - Next(); - return temp; } - - Iterator& operator--() { - Prev(); - return *this; } - - Iterator operator--(int) { - Iterator temp(*this); - Prev(); - return temp; } - - void*& operator*() const { - return mIsSingleton - ? (!mIsExhausted ? *mElementRef : kDummyLast) - : mPath.TopNode()->GetElementAt(mPath.TopIndex()); } - - PRBool operator==(const Iterator& aOther) const { - return mIsSingleton - ? (mElement == aOther.mElement && mIsExhausted == aOther.mIsExhausted) - : mPath == aOther.mPath; } - - PRBool operator!=(const Iterator& aOther) const { - return !aOther.operator==(*this); } - - protected: - Iterator(const Path& aPath) - : ConstIterator(aPath) {} - - Iterator(PRWord* aElementRef, PRBool aIsExhausted) - : ConstIterator(*aElementRef, aIsExhausted), - mElementRef(NS_REINTERPRET_CAST(void**, aElementRef)) {} - - friend class nsVoidBTree; - }; - - Iterator First() { - return IsSingleElement() ? Iterator(&mRoot, PR_FALSE) : Iterator(LeftMostPath()); } - - Iterator Last() { - return IsSingleElement() ? Iterator(&mRoot, PR_TRUE) : Iterator(RightMostPath()); } - -protected: - const Path LeftMostPath() const; - const Path RightMostPath() const; - - static void* kDummyLast; -}; - - -#endif // nsVoidBTree_h__