Re-implemented DST code to use separate objects for leaf nodes and
internal nodes. This reduces the per node size from 16 bytes to (on
average) 13 bytes per node
This commit is contained in:
troy%netscape.com 1999-10-15 03:18:28 +00:00
parent f80550c400
commit bf8c6d860d
2 changed files with 523 additions and 187 deletions

View File

@ -15,7 +15,7 @@
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#define PL_ARENA_CONST_ALIGN_MASK 7
#define PL_ARENA_CONST_ALIGN_MASK 3
#include "nslayout.h"
#include "nsDST.h"
#include "nsISupports.h"
@ -24,38 +24,110 @@
#endif
/////////////////////////////////////////////////////////////////////////////
// Structure that represents a node in the DST
// Classes that represents nodes in the DST
// To reduce the amount of memory we use there are two types of nodes:
// - leaf nodes
// - two nodes (left and right child)
//
// We distinguish the two types of nodes by looking at the low-order
// bit of the key. If it is 0, then the node is a leaf node. If it is
// 1, then the node is a two node. Use function Key() when retrieving
// the key, and function IsLeaf() to tell what type of node it is
//
// It's an invariant of the tree that a two node can not have both child links
// NULL. In that case it must be converted back to a leaf node
// Leaf node class
class nsDST::LeafNode {
public:
void* mKey;
void* mValue;
// Constructors
LeafNode(void* aKey, void* aValue);
LeafNode(const LeafNode& aLeafNode);
// Accessor for getting the key. Clears the bit used to tell if the
// node is a leaf. This function can be safely used on any node without
// knowing whether it's a leaf or a two node
void* Key() const {return (void*)(PtrBits(mKey) & ~0x1);}
// Helper function that returns TRUE if the node is a leaf
int IsLeaf() const {return 0 == (PtrBits(mKey) & 0x1);}
// Overloaded placement operator for allocating from an arena
void* operator new(size_t aSize, NodeArena& aArena) {return aArena.AllocLeafNode();}
private:
void operator delete(void*); // no implementation
};
// Constructors
inline nsDST::LeafNode::LeafNode(void* aKey, void* aValue)
: mKey(aKey), mValue(aValue)
{
}
inline nsDST::LeafNode::LeafNode(const LeafNode& aNode)
: mKey(aNode.Key()), // don't assume it's a leaf node
mValue(aNode.mValue)
{
}
// Two node class
class nsDST::TwoNode : public nsDST::LeafNode {
public:
LeafNode* mLeft; // left subtree
LeafNode* mRight; // right subtree
TwoNode(const LeafNode& aLeafNode);
void SetKeyAndValue(void* aKey, void* aValue) {
mKey = (void*)(PtrBits(aKey) | 0x01);
mValue = aValue;
}
// Overloaded placement operator for allocating from an arena
void* operator new(size_t aSize, NodeArena& aArena) {return aArena.AllocTwoNode();}
private:
TwoNode(const TwoNode&); // no implementation
void operator=(const TwoNode&); // no implementation
void operator delete(void*); // no implementation
};
// Constructor
inline nsDST::Node::Node(void* aKey, void* aValue)
: mKey(aKey), mValue(aValue), mLeft(0), mRight(0)
inline nsDST::TwoNode::TwoNode(const LeafNode& aLeafNode)
: LeafNode((void*)(PtrBits(aLeafNode.mKey) | 0x1), aLeafNode.mValue),
mLeft(0), mRight(0)
{
}
// Helper function that returns TRUE if the node is a leaf (i.e., no left or
// right child), and FALSE otherwise
inline int nsDST::Node::IsLeaf() const
{
return !mLeft && !mRight;
}
// If you know that the node is a leaf node, then you can quickly access
// the key without clearing the bit that indicates whether it's a leaf or
// a two node
#define DST_GET_LEAF_KEY(leaf) ((leaf)->mKey)
// Overloaded placement operator for allocating from an arena
inline void* nsDST::Node::operator new(size_t aSize, NodeArena& aArena)
{
return aArena.AllocNode(aSize);
}
// Macros to check whether we branch left or branch right for a given
// key and bit mask
#define DST_BRANCHES_LEFT(key, mask) \
(0 == (PtrBits(key) & (mask)))
#define DST_BRANCHES_RIGHT(key, mask) \
((mask) == (PtrBits(key) & (mask)))
/////////////////////////////////////////////////////////////////////////////
// Arena used for fast allocation and deallocation of Node structures.
// Maintains a free-list of freed objects
// Maintains free-list of freed objects
#define NS_DST_ARENA_BLOCK_SIZE 1024
#define NS_DST_ARENA_BLOCK_SIZE 512
MOZ_DECL_CTOR_COUNTER(NodeArena);
// Constructor
nsDST::NodeArena::NodeArena()
: mFreeList(0)
: mLeafNodeFreeList(0), mTwoNodeFreeList(0)
{
MOZ_COUNT_CTOR(NodeArena);
PL_INIT_ARENA_POOL(&mPool, "DSTNodeArena", NS_DST_ARENA_BLOCK_SIZE);
@ -70,35 +142,70 @@ nsDST::NodeArena::~NodeArena()
PL_FinishArenaPool(&mPool);
}
// Called by the nsDST::Node's overloaded placement operator when allocating
// a new node. First checks the free list. If the free list is empty, then
// it allocates memory from the arena
// Called by the nsDST::LeafNode's overloaded placement operator when
// allocating a new node. First checks the free list. If the free list is
// empty, then it allocates memory from the arena
void*
nsDST::NodeArena::AllocNode(size_t aSize)
nsDST::NodeArena::AllocLeafNode()
{
void* p;
if (mFreeList) {
if (mLeafNodeFreeList) {
// Remove the node at the head of the free-list
p = mFreeList;
mFreeList = mFreeList->mLeft;
p = mLeafNodeFreeList;
mLeafNodeFreeList = (LeafNode*)mLeafNodeFreeList->mKey;
} else {
PL_ARENA_ALLOCATE(p, &mPool, aSize);
PL_ARENA_ALLOCATE(p, &mPool, sizeof(nsDST::LeafNode));
}
return p;
}
// Called by the nsDST::TwoNode's overloaded placement operator when
// allocating a new node. First checks the free list. If the free list is
// empty, then it allocates memory from the arena
void*
nsDST::NodeArena::AllocTwoNode()
{
void* p;
if (mTwoNodeFreeList) {
// Remove the node at the head of the free-list
p = mTwoNodeFreeList;
mTwoNodeFreeList = (TwoNode*)mTwoNodeFreeList->mKey;
} else {
PL_ARENA_ALLOCATE(p, &mPool, sizeof(nsDST::TwoNode));
}
return p;
}
// Called by the DST's DestroyNode() function. Adds the node to the head
// of the free list where it can be reused by AllocateNode()
void
nsDST::NodeArena::FreeNode(void* p)
nsDST::NodeArena::FreeNode(LeafNode* aLeafNode)
{
#ifdef NS_DEBUG
memset(p, 0xde, sizeof(Node));
memset(aLeafNode, 0xde, sizeof(*aLeafNode));
#endif
// Add this node to the head of the free-list
((Node*)p)->mLeft = mFreeList;
mFreeList = (Node*)p;
aLeafNode->mKey = mLeafNodeFreeList;
mLeafNodeFreeList = aLeafNode;
}
// Called by the DST's DestroyNode() function. Adds the node to the head
// of the free list where it can be reused by AllocateNode()
void
nsDST::NodeArena::FreeNode(TwoNode* aTwoNode)
{
#ifdef NS_DEBUG
memset(aTwoNode, 0xde, sizeof(*aTwoNode));
#endif
// Add this node to the head of the free-list
aTwoNode->mKey = mTwoNodeFreeList;
mTwoNodeFreeList = aTwoNode;
}
// Called by the DST's Clear() function when we want to free the memory
@ -109,8 +216,9 @@ nsDST::NodeArena::FreeArenaPool()
// Free the arena in the pool, but continue using it
PL_FreeArenaPool(&mPool);
// Clear the free list
mFreeList = 0;
// Clear the free lists
mLeafNodeFreeList = 0;
mTwoNodeFreeList = 0;
}
/////////////////////////////////////////////////////////////////////////////
@ -139,26 +247,196 @@ nsDST::Clear()
mRoot = 0;
}
// Called by Remove() to destroy a node. Explicitly calls the destructor
// and then asks the memory arena to free the memory
inline void
nsDST::DestroyNode(LeafNode* aLeafNode)
{
aLeafNode->~LeafNode(); // call destructor
mArena.FreeNode(aLeafNode); // free memory
}
// Called by Remove() to destroy a node. Explicitly calls the destructor
// and then asks the memory arena to free the memory
inline void
nsDST::DestroyNode(TwoNode* aTwoNode)
{
aTwoNode->~TwoNode(); // call destructor
mArena.FreeNode(aTwoNode); // free memory
}
nsDST::LeafNode*
nsDST::ConvertToLeafNode(TwoNode** aTwoNode)
{
LeafNode* leaf = new (mArena)LeafNode((*aTwoNode)->Key(), (*aTwoNode)->mValue);
DestroyNode(*aTwoNode);
*aTwoNode = (TwoNode*)leaf;
return leaf;
}
nsDST::TwoNode*
nsDST::ConvertToTwoNode(LeafNode** aLeafNode)
{
TwoNode* twoNode = new (mArena)TwoNode(**aLeafNode);
DestroyNode(*aLeafNode);
*aLeafNode = (LeafNode*)twoNode;
return twoNode;
}
// Searches the tree for a node with the specified key. Return the value
// or NULL if the key is not in the tree
void*
nsDST::Search(void* aKey) const
{
NS_PRECONDITION(0 == (PtrBits(aKey) & (mLevelZeroBit - 1)),
"ignored low-order bits are not zero");
if (mRoot) {
LeafNode* node = mRoot;
PtrBits bitMask = mLevelZeroBit;
while (1) {
// Check if the key matches
if (node->Key() == aKey) {
return node->mValue;
}
// See if this is a leaf node
if (node->IsLeaf()) {
// We didn't find a matching key
break;
}
// Check whether we search the left branch or the right branch
if (DST_BRANCHES_LEFT(aKey, bitMask)) {
node = ((TwoNode*)node)->mLeft;
} else {
node = ((TwoNode*)node)->mRight;
}
if (!node) {
break; // we reached a null link
}
// Move to the next bit in the key
bitMask <<= 1;
}
#ifdef DEBUG_troy
// We didn't find a matching node. Use an alternative algorithm to verify
// that the key is not in the tree
NS_POSTCONDITION(!DepthFirstSearch(mRoot, aKey), "DST search failed");
#endif
}
return 0;
}
// Adds a new key to the tree. If the specified key is already in the
// tree, then the existing value is replaced by the new value. Returns
// the old value, or NULL if this is a new key
void*
nsDST::Insert(void* aKey, void* aValue)
{
// See if there's a matching key
Node** node = SearchTree(aKey);
void* previousValue;
NS_PRECONDITION(0 == (PtrBits(aKey) & (mLevelZeroBit - 1)),
"ignored low-order bits are not zero");
LeafNode** node = (LeafNode**)&mRoot;
void* previousValue = 0;
TwoNode* branchReduction = 0;
// See if there's an existing node with a matching key
if (*node) {
PtrBits bitMask = mLevelZeroBit;
while (1) {
// See if the key matches
if ((*node)->Key() == aKey) {
break;
}
// Is this a leaf node?
if ((*node)->IsLeaf()) {
if (!branchReduction) {
// Replace the leaf node with a two node and destroy the
// leaf node
TwoNode* twoNode = ConvertToTwoNode(node);
// Exit the loop and allocate a new leaf node and set its
// key and value
node = DST_BRANCHES_LEFT(aKey, bitMask) ? &twoNode->mLeft :
&twoNode->mRight;
}
break;
} else {
TwoNode*& twoNode = *(TwoNode**)node;
// Check whether we search the left branch or the right branch
if (DST_BRANCHES_LEFT(aKey, bitMask)) {
// If there's a left node and no right node, then see if we
// can reduce the one way braching in the tree
if (twoNode->mLeft && !twoNode->mRight) {
if (DST_BRANCHES_RIGHT(twoNode->mKey, bitMask)) {
// Yes, this node can become the right node of the tree. Remember
// this for later in case we don't find a matching node
branchReduction = twoNode;
}
}
node = &twoNode->mLeft;
} else {
// If there's a right node and no left node, then see if we
// can reduce the one way braching in the tree
if (twoNode->mRight && !twoNode->mLeft) {
if (DST_BRANCHES_LEFT(twoNode->mKey, bitMask)) {
// Yes, this node can become the left node of the tree. Remember
// this for later in case we don't find a matching node
branchReduction = twoNode;
}
}
node = &twoNode->mRight;
}
// Did we reach a null link?
if (!*node) {
break;
}
}
// Move to the next bit in the key
bitMask <<= 1;
}
}
if (branchReduction) {
// Reduce the one way branching by moving the existing key and
// value to either the right or left node
if (!branchReduction->mLeft) {
NS_ASSERTION(branchReduction->mRight, "bad state");
branchReduction->mLeft = new (mArena)LeafNode(*branchReduction);
} else {
NS_ASSERTION(!branchReduction->mRight, "bad state");
branchReduction->mRight = new (mArena)LeafNode(*branchReduction);
}
// Replace the existing key and value with the new key and value
branchReduction->SetKeyAndValue(aKey, aValue);
} else if (*node) {
// We found an existing node with a matching key. Replace the current
// value with the new value
previousValue = (*node)->mValue;
// Replace the current value with the new value
(*node)->mValue = aValue;
} else {
// Allocate a new node and insert it into the tree
*node = new (mArena)Node(aKey, aValue);
previousValue = 0;
// Allocate a new leaf node and insert it into the tree
*node = new (mArena)LeafNode(aKey, aValue);
}
#ifdef DEBUG_troy
@ -167,36 +445,65 @@ nsDST::Insert(void* aKey, void* aValue)
return previousValue;
}
// Helper function that returns the left most leaf node of the specified
// subtree
nsDST::Node**
nsDST::GetLeftMostLeafNode(Node** aNode) const
// Helper function that removes and returns the left most leaf node
// of the specified subtree.
// Note: if the parent of the node that is removed is now a leaf,
// it will be converted to a leaf node...
nsDST::LeafNode*
nsDST::RemoveLeftMostLeafNode(TwoNode** aTwoNode)
{
keepLooking:
// See if the node has none, one, or two child nodes
if ((*aNode)->mLeft) {
// Walk down the left branch
aNode = &(*aNode)->mLeft;
goto keepLooking;
NS_PRECONDITION(!(*aTwoNode)->IsLeaf(), "bad parameter");
} else if ((*aNode)->mRight) {
keepLooking:
LeafNode** child;
if ((*aTwoNode)->mLeft) {
// Walk down the left branch
child = &(*aTwoNode)->mLeft;
// See if it's a leaf
if ((*child)->IsLeaf()) {
// Remove the child from its parent
LeafNode* result = *child;
*child = 0;
// If there's no right node then the parent is now a leaf so
// convert it to a leaf node
if (!(*aTwoNode)->mRight) {
ConvertToLeafNode(aTwoNode);
}
// Return the leaf node
return result;
}
} else if ((*aTwoNode)->mRight) {
// No left branch, so walk down the right branch
aNode = &(*aNode)->mRight;
goto keepLooking;
child = &(*aTwoNode)->mRight;
if ((*child)->IsLeaf()) {
// Remove the child from its parent
LeafNode* result = *child;
*child = 0;
// That was the parent's only child node so convert the parent
// node to a leaf node
ConvertToLeafNode(aTwoNode);
// Return the leaf node
return result;
}
} else {
// We found a leaf node
return aNode;
// We should never encounter a two node with both links NULL. It should
// have been coverted to a leaf instead...
NS_ASSERTION(0, "bad node type");
return 0;
}
}
// Called by Remove() to destroy a node. Explicitly calls the destructor
// and then asks the memory arena to free the memory
inline void
nsDST::DestroyNode(Node* aNode)
{
aNode->~Node(); // call destructor
mArena.FreeNode(aNode); // free memory
aTwoNode = (TwoNode**)child;
goto keepLooking;
}
// Removes a key from the tree. Returns the current value, or NULL if
@ -204,36 +511,88 @@ nsDST::DestroyNode(Node* aNode)
void*
nsDST::Remove(void* aKey)
{
Node** node = SearchTree(aKey);
NS_PRECONDITION(0 == (PtrBits(aKey) & (mLevelZeroBit - 1)),
"ignored low-order bits are not zero");
if (mRoot) {
LeafNode** node;
TwoNode** parentNode = 0;
PtrBits bitMask = mLevelZeroBit;
if (mRoot->Key() == aKey) {
node = (LeafNode**)&mRoot;
if (*node) {
Node* tmp = *node;
} else if (!mRoot->IsLeaf()) {
// Look for a node with a matching key
node = (LeafNode**)&mRoot;
while (1) {
NS_ASSERTION(!(*node)->IsLeaf(), "unexpected leaf mode");
parentNode = (TwoNode**)node;
// Check whether we search the left branch or the right branch
if (DST_BRANCHES_LEFT(aKey, bitMask)) {
node = &(*(TwoNode**)node)->mLeft;
} else {
node = &(*(TwoNode**)node)->mRight;
}
if (!*node) {
// We found a NULL link which means no node with a matching key
return 0;
}
// Check if the key matches
if ((*node)->Key() == aKey) {
break;
}
// The key doesn't match. If this is a leaf node that means no
// node with a matching key
if ((*node)->IsLeaf()) {
return 0;
}
// Move to the next bit in the key
bitMask <<= 1;
}
}
// We found a matching node
void* value = (*node)->mValue;
if ((*node)->IsLeaf()) {
// Just disconnect the node from its parent node
// Delete the leaf node
DestroyNode(*node);
// Disconnect the node from its parent node
*node = 0;
// If the parent now has no child nodes, then convert it to a
// leaf frame
if (parentNode && !(*parentNode)->mLeft && !(*parentNode)->mRight) {
ConvertToLeafNode(parentNode);
}
} else {
// We can't just move the left or right subtree up one level, because
// then we would have to re-sort the tree. Instead replace the node
// with the left most leaf node
Node** leaf = GetLeftMostLeafNode(node);
// then we would have to re-sort the tree. Instead replace the node's
// key and value with that of its left most leaf node (any leaf frame
// would do)
LeafNode* leaf = RemoveLeftMostLeafNode((TwoNode**)node);
// Copy over both the left and right subtree pointers
if ((*node)->mLeft != (*leaf)) {
(*leaf)->mLeft = (*node)->mLeft;
}
if ((*node)->mRight != (*leaf)) {
(*leaf)->mRight = (*node)->mRight;
// Copy over the leaf's key and value
// Note: RemoveLeftMostLeafNode() may have converted "node" to a
// leaf node so don't make any assumptions here
if ((*node)->IsLeaf()) {
(*node)->mKey = DST_GET_LEAF_KEY(leaf);
} else {
(*node)->mKey = (void*)(PtrBits(DST_GET_LEAF_KEY(leaf)) | 0x01);
}
(*node)->mValue = leaf->mValue;
// Insert the leaf node in its new level, and disconnect it from its old
// parent node
*node = *leaf;
*leaf = 0;
// Delete the leaf node
DestroyNode(leaf);
}
DestroyNode(tmp);
#ifdef DEBUG_troy
VerifyTree(mRoot);
#endif
@ -243,71 +602,24 @@ nsDST::Remove(void* aKey)
return 0;
}
// Searches the tree for a node with the specified key. Return the value
// or NULL if the key is not in the tree
void*
nsDST::Search(void* aKey) const
{
Node** result = SearchTree(aKey);
#ifdef DEBUG_troy
if (!*result) {
// Use an alternative algorithm to verify that the key is not in
// the tree
NS_POSTCONDITION(!DepthFirstSearch(mRoot, aKey), "DST search failed");
}
#endif
return (*result) ? (*result)->mValue : 0;
}
// Non-recursive search function. Returns a pointer to the pointer to the
// node. Called by Search(), Insert(), and Remove()
nsDST::Node**
nsDST::SearchTree(void* aKey) const
{
NS_PRECONDITION(0 == (PtrBits(aKey) & (mLevelZeroBit - 1)),
"ignored low-order bits are not zero");
Node** result = (Node**)&mRoot;
PtrBits bitMask = mLevelZeroBit;
while (*result) {
// Check if the node matches
if ((*result)->mKey == aKey) {
return result;
}
// Check whether we search the left branch or the right branch
if (0 == (PtrBits(aKey) & bitMask)) {
result = &(*result)->mLeft;
} else {
result = &(*result)->mRight;
}
// Move to the next bit in the key
bitMask <<= 1;
}
// We failed to find the key: return where the node would be inserted
return result;
}
#ifdef NS_DEBUG
// Helper function used to verify the integrity of the tree. Does a
// depth-first search of the tree looking for a node with the specified
// key. Called by Search() if we don't find the key using the radix-search
nsDST::Node*
nsDST::DepthFirstSearch(Node* aNode, void* aKey) const
nsDST::LeafNode*
nsDST::DepthFirstSearch(LeafNode* aNode, void* aKey) const
{
if (!aNode) {
return 0;
} else if (aNode->mKey == aKey) {
} else if (aNode->Key() == aKey) {
return aNode;
} else if (aNode->IsLeaf()) {
return 0;
} else {
Node* result = DepthFirstSearch(aNode->mLeft, aKey);
LeafNode* result = DepthFirstSearch(((TwoNode*)aNode)->mLeft, aKey);
if (!result) {
result = DepthFirstSearch(aNode->mRight, aKey);
result = DepthFirstSearch(((TwoNode*)aNode)->mRight, aKey);
}
return result;
@ -317,7 +629,7 @@ nsDST::DepthFirstSearch(Node* aNode, void* aKey) const
// Helper function that verifies the integrity of the tree. Called
// by Insert() and Remove()
void
nsDST::VerifyTree(Node* aNode, int aLevel, PtrBits aLevelKeyBits) const
nsDST::VerifyTree(LeafNode* aNode, int aLevel, PtrBits aLevelKeyBits) const
{
if (aNode) {
// Verify that the first "aLevel" bits of this node's key agree with the
@ -327,31 +639,42 @@ nsDST::VerifyTree(Node* aNode, int aLevel, PtrBits aLevelKeyBits) const
// When calculating the bit mask, take into consideration the low-order
// bits we ignore
PtrBits bitMask = (mLevelZeroBit << aLevel) - 1;
NS_ASSERTION(aLevelKeyBits == (PtrBits(aNode->mKey) & bitMask),
NS_ASSERTION(aLevelKeyBits == (PtrBits(aNode->Key()) & bitMask),
"key's bits don't match");
}
// All node keys in the left subtree should have the next bit set to 0
VerifyTree(aNode->mLeft, aLevel + 1, aLevelKeyBits);
if (!aNode->IsLeaf()) {
const TwoNode* twoNode = (TwoNode*)aNode;
NS_ASSERTION(twoNode->mLeft || twoNode->mRight,
"two node with no child nodes");
// All node keys in the left subtree should have the next bit set to 1
VerifyTree(aNode->mRight, aLevel + 1, aLevelKeyBits | (mLevelZeroBit << aLevel));
// All node keys in the left subtree should have the next bit set to 0
VerifyTree(twoNode->mLeft, aLevel + 1, aLevelKeyBits);
// All node keys in the left subtree should have the next bit set to 1
VerifyTree(twoNode->mRight, aLevel + 1, aLevelKeyBits | (mLevelZeroBit << aLevel));
}
}
}
void
nsDST::GatherStatistics(Node* aNode,
int aLevel,
int& aNumNodes,
int aNodesPerLevel[]) const
nsDST::GatherStatistics(LeafNode* aNode,
int aLevel,
int& aNumLeafNodes,
int& aNumTwoNodes,
int aNodesPerLevel[]) const
{
aNumNodes++;
aNodesPerLevel[aLevel]++;
if (aNode->mLeft) {
GatherStatistics(aNode->mLeft, aLevel + 1, aNumNodes, aNodesPerLevel);
}
if (aNode->mRight) {
GatherStatistics(aNode->mRight, aLevel + 1, aNumNodes, aNodesPerLevel);
if (aNode) {
aNodesPerLevel[aLevel]++;
if (aNode->IsLeaf()) {
aNumLeafNodes++;
} else {
aNumTwoNodes++;
GatherStatistics(((TwoNode*)aNode)->mLeft, aLevel + 1, aNumLeafNodes,
aNumTwoNodes, aNodesPerLevel);
GatherStatistics(((TwoNode*)aNode)->mRight, aLevel + 1, aNumLeafNodes,
aNumTwoNodes, aNodesPerLevel);
}
}
}
@ -363,12 +686,13 @@ nsDST::Dump(FILE* out) const
// node level
static const int maxLevels = sizeof(void*) * 8;
int numNodes = 0;
int numLeafNodes = 0;
int numTwoNodes = 0;
int nodesPerLevel[maxLevels]; // count of the number of nodes at a given level
memset(&nodesPerLevel, 0, sizeof(int) * maxLevels);
// Walk each node in the tree recording its node level
GatherStatistics(mRoot, 0, numNodes, nodesPerLevel);
GatherStatistics(mRoot, 0, numLeafNodes, numTwoNodes, nodesPerLevel);
// Calculate the height, average node level, and median node level
int height, medianLevel = 0, pathLength = 0;
@ -387,11 +711,28 @@ nsDST::Dump(FILE* out) const
pathLength += height * count;
}
// Calculate the number of arenas in use
int numArenas = 0;
for (PLArena* arena = mArena.mPool.first.next; arena; arena = arena->next) {
numArenas++;
}
// Output the statistics
int numTotalNodes = numLeafNodes + numTwoNodes;
fputs("DST statistics\n", out);
fprintf(out, " Number of nodes: %d\n", numNodes);
fprintf(out, " Number of leaf nodes: %d\n", numLeafNodes);
fprintf(out, " Number of tree nodes: %d\n", numTwoNodes);
if (numTotalNodes > 0) {
fprintf(out, " Average node size: %.1f\n",
float(numLeafNodes * sizeof(LeafNode) + numTwoNodes * sizeof(TwoNode)) /
float(numTotalNodes));
}
fprintf(out, " Number of arenas: %d(%d)\n", numArenas, mArena.mPool.arenasize);
fprintf(out, " Height (maximum node level) of the tree: %d\n", height - 1);
fprintf(out, " Average node level: %.1f\n", float(pathLength) / float(numNodes));
if (numTotalNodes > 0) {
fprintf(out, " Average node level: %.1f\n", float(pathLength) / float(numTotalNodes));
}
fprintf(out, " Median node level: %d\n", medianLevel);
fprintf(out, " Path length: %d\n", pathLength);

View File

@ -50,54 +50,49 @@ public:
#endif
private:
struct Node;
class LeafNode;
class TwoNode;
struct NodeArena;
friend struct Node; // needs access to struct NodeArena
friend struct NodeArena; // needs access to struct Node
struct Node {
void* mKey;
void* mValue;
Node* mLeft; // left subtree
Node* mRight; // right subtree
Node(void* aKey, void* aValue);
int IsLeaf() const;
// Overloaded placement operator for allocating from an arena
void* operator new(size_t aSize, NodeArena& aArena);
};
friend class LeafNode;
friend class TwoNode;
friend struct NodeArena; // needs access to structs LeafNode and TwoNode
struct NodeArena {
PLArenaPool mPool;
Node* mFreeList;
LeafNode* mLeafNodeFreeList;
TwoNode* mTwoNodeFreeList;
NodeArena();
~NodeArena();
void* AllocNode(size_t);
void FreeNode(void*);
void FreeArenaPool();
void* AllocLeafNode();
void* AllocTwoNode();
void FreeNode(LeafNode*);
void FreeNode(TwoNode*);
void FreeArenaPool();
};
Node* mRoot; // root node of the tree
LeafNode* mRoot; // root node of the tree
NodeArena mArena;
PtrBits mLevelZeroBit;
private:
// Helper functions
Node** SearchTree(void* aKey) const;
Node** GetLeftMostLeafNode(Node** aNode) const;
void DestroyNode(Node* aNode);
LeafNode* RemoveLeftMostLeafNode(TwoNode** aTwoNode);
void DestroyNode(LeafNode* aLeafNode);
void DestroyNode(TwoNode* aTwoNode);
LeafNode* ConvertToLeafNode(TwoNode** aTwoNode);
TwoNode* ConvertToTwoNode(LeafNode** aLeafNode);
#ifdef NS_DEBUG
// Diagnostic functions
Node* DepthFirstSearch(Node* aNode, void* aKey) const;
void VerifyTree(Node* aNode, int aLevel = 0, PtrBits aLevelKeyBits = 0) const;
void GatherStatistics(Node* aNode,
int aLevel,
int& aNumNodes,
int aNodesPerLevel[]) const;
void VerifyTree(LeafNode* aNode, int aLevel = 0, PtrBits aLevelKeyBits = 0) const;
LeafNode* DepthFirstSearch(LeafNode* aNode, void* aKey) const;
void GatherStatistics(LeafNode* aNode,
int aLevel,
int& aNumLeafNodes,
int& aNumTwoNodes,
int aNodesPerLevel[]) const;
#endif
nsDST(const nsDST&); // no implementation