зеркало из https://github.com/mozilla/gecko-dev.git
Initial check-in
This commit is contained in:
Родитель
7dfe5f86ed
Коммит
32d96e8d86
|
@ -0,0 +1,357 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
#define PL_ARENA_CONST_ALIGN_MASK 7
|
||||
#include "nslayout.h"
|
||||
#include "nsDST.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Structure that represents a node in the DST
|
||||
|
||||
struct nsDST::Node {
|
||||
void* mKey;
|
||||
void* mValue;
|
||||
Node* mLeft; // left subtree
|
||||
Node* mRight; // right subtree
|
||||
|
||||
Node(void* aKey, void* aValue)
|
||||
: mKey(aKey), mValue(aValue), mLeft(0), mRight(0) {}
|
||||
|
||||
int IsLeaf() {return !mLeft && !mRight;}
|
||||
|
||||
// Overloaded placement operator for allocating from an arena
|
||||
void* operator new(size_t aSize, nsDST::NodeArena& aArena) {
|
||||
return aArena.AllocNode(aSize);
|
||||
}
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Arena used for fast allocation and deallocation of Node structures.
|
||||
// Maintains a free-list of freed objects
|
||||
|
||||
#define NS_DST_ARENA_BLOCK_SIZE 1024
|
||||
|
||||
nsDST::NodeArena::NodeArena()
|
||||
: mFreeList(0)
|
||||
{
|
||||
PL_INIT_ARENA_POOL(&mPool, "DSTNodeArena", NS_DST_ARENA_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
nsDST::NodeArena::~NodeArena()
|
||||
{
|
||||
// Free the arena in the pool and finish using it
|
||||
PL_FinishArenaPool(&mPool);
|
||||
}
|
||||
|
||||
void*
|
||||
nsDST::NodeArena::AllocNode(size_t aSize)
|
||||
{
|
||||
void* p;
|
||||
|
||||
if (mFreeList) {
|
||||
// Remove the node at the head of the free-list
|
||||
p = mFreeList;
|
||||
mFreeList = mFreeList->mLeft;
|
||||
} else {
|
||||
PL_ARENA_ALLOCATE(p, &mPool, aSize);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
nsDST::NodeArena::FreeNode(void* p)
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
memset(p, 0xde, sizeof(Node));
|
||||
#endif
|
||||
// Add this node to the head of the free-list
|
||||
((Node*)p)->mLeft = mFreeList;
|
||||
mFreeList = (Node*)p;
|
||||
}
|
||||
|
||||
void
|
||||
nsDST::NodeArena::FreeArenaPool()
|
||||
{
|
||||
// Free the arena in the pool, but continue using it
|
||||
PL_FreeArenaPool(&mPool);
|
||||
mFreeList = 0;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Digital search tree for doing a radix-search of pointer-based keys
|
||||
|
||||
nsDST::nsDST(PtrBits aLevelZeroBit)
|
||||
: mRoot(0), mLevelZeroBit(aLevelZeroBit)
|
||||
{
|
||||
}
|
||||
|
||||
nsDST::~nsDST()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
nsDST::Clear()
|
||||
{
|
||||
mArena.FreeArenaPool();
|
||||
mRoot = 0;
|
||||
}
|
||||
|
||||
void*
|
||||
nsDST::Insert(void* aKey, void* aValue)
|
||||
{
|
||||
// See if there's a matching key
|
||||
Node** node = SearchTree(aKey);
|
||||
void* previousValue;
|
||||
|
||||
if (*node) {
|
||||
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;
|
||||
}
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
VerifyTree(mRoot, mLevelZeroBit);
|
||||
#endif
|
||||
return previousValue;
|
||||
}
|
||||
|
||||
// Helper function that returns one of the leaf nodes of the specified
|
||||
// subtree
|
||||
nsDST::Node**
|
||||
nsDST::FindLeafNode(Node** aNode) const
|
||||
{
|
||||
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;
|
||||
|
||||
} else if ((*aNode)->mRight) {
|
||||
// Walk down the right branch
|
||||
aNode = &(*aNode)->mRight;
|
||||
goto keepLooking;
|
||||
|
||||
} else {
|
||||
// We found a leaf node
|
||||
return aNode;
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
nsDST::DestroyNode(Node* aNode)
|
||||
{
|
||||
aNode->~Node(); // call destructor
|
||||
mArena.FreeNode(aNode); // free memory
|
||||
}
|
||||
|
||||
void*
|
||||
nsDST::Remove(void* aKey)
|
||||
{
|
||||
Node** node = SearchTree(aKey);
|
||||
|
||||
if (*node) {
|
||||
Node* tmp = *node;
|
||||
void* value = (*node)->mValue;
|
||||
|
||||
if ((*node)->IsLeaf()) {
|
||||
// Just disconnect the node from its parent node
|
||||
*node = 0;
|
||||
} 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 any leaf node below it in the tree
|
||||
Node** leaf = FindLeafNode(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;
|
||||
}
|
||||
|
||||
// Insert the leaf node in its new level, and disconnect it from its old
|
||||
// parent node
|
||||
*node = *leaf;
|
||||
*leaf = 0;
|
||||
}
|
||||
|
||||
DestroyNode(tmp);
|
||||
#ifdef NS_DEBUG
|
||||
VerifyTree(mRoot, mLevelZeroBit);
|
||||
#endif
|
||||
return value;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void*
|
||||
nsDST::Search(void* aKey) const
|
||||
{
|
||||
Node** result = SearchTree(aKey);
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
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
|
||||
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;
|
||||
}
|
||||
bitMask <<= 1;
|
||||
}
|
||||
|
||||
// We failed to find the key: return where the node would be inserted
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
nsDST::Node*
|
||||
nsDST::DepthFirstSearch(Node* aNode, void* aKey) const
|
||||
{
|
||||
if (!aNode) {
|
||||
return 0;
|
||||
} else if (aNode->mKey == aKey) {
|
||||
return aNode;
|
||||
} else {
|
||||
Node* result = DepthFirstSearch(aNode->mLeft, aKey);
|
||||
|
||||
if (!result) {
|
||||
result = DepthFirstSearch(aNode->mRight, aKey);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsDST::VerifyTree(Node* aNode, PtrBits aBitMask) const
|
||||
{
|
||||
if (aNode->mLeft) {
|
||||
// Verify that the bit in the left child's pointer is 0
|
||||
NS_ASSERTION(0 == (PtrBits(aNode->mLeft->mKey) & aBitMask),
|
||||
"child in left subtree is invalid");
|
||||
VerifyTree(aNode->mLeft, aBitMask << 1);
|
||||
}
|
||||
if (aNode->mRight) {
|
||||
// Verify that the bit in the right child's pointer is 1
|
||||
NS_ASSERTION((PtrBits(aNode->mRight->mKey) & aBitMask),
|
||||
"child in right subtree is invalid");
|
||||
VerifyTree(aNode->mRight, aBitMask << 1);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsDST::GatherStatistics(Node* aNode,
|
||||
int aLevel,
|
||||
int& aNumNodes,
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsDST::Dump(FILE* out) const
|
||||
{
|
||||
// Walk the tree gathering statistics about the number of nodes, the height
|
||||
// of the tree (maximum node level), the average node level, and the median
|
||||
// node level
|
||||
static const int maxLevels = sizeof(void*) * 8;
|
||||
|
||||
int numNodes = 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);
|
||||
|
||||
// Calculate the height, average node level, and median node level
|
||||
int height, medianLevel = 0, pathLength = 0;
|
||||
for (height = 0; height < maxLevels; height++) {
|
||||
int count = nodesPerLevel[height];
|
||||
if (0 == count) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Update the median node level
|
||||
if (count > nodesPerLevel[medianLevel]) {
|
||||
medianLevel = height;
|
||||
}
|
||||
|
||||
// Update the path length
|
||||
pathLength += height * count;
|
||||
}
|
||||
|
||||
// Output the statistics
|
||||
fputs("DST statistics\n", out);
|
||||
fprintf(out, " Number of nodes: %d\n", numNodes);
|
||||
fprintf(out, " Height (maximum node level) of the tree: %d\n", height - 1);
|
||||
fprintf(out, " Average node level: %.1f\n", float(pathLength) / float(numNodes));
|
||||
fprintf(out, " Median node level: %d\n", medianLevel);
|
||||
fprintf(out, " Path length: %d\n", pathLength);
|
||||
|
||||
// Output the number of nodes at each level of the tree
|
||||
fputs(" Nodes per level: ", out);
|
||||
fprintf(out, "%d", nodesPerLevel[0]);
|
||||
for (int i = 1; i < height; i++) {
|
||||
fprintf(out, ", %d", nodesPerLevel[i]);
|
||||
}
|
||||
fputs("\n", out);
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
#ifndef nsDST_h___
|
||||
#define nsDST_h___
|
||||
|
||||
#include <memory.h>
|
||||
#include "plarena.h"
|
||||
#ifdef NS_DEBUG
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Digital search tree for doing a radix-search of pointer-based keys
|
||||
*/
|
||||
class nsDST {
|
||||
public:
|
||||
typedef unsigned long PtrBits;
|
||||
|
||||
// By ignoring low-order pointer bits that are always 0, the tree height can
|
||||
// be reduced. Because pointer memory should be at least 32-bit aligned, the
|
||||
// default is for level 0 of the tree to start with bit 0x04 (i.e., we ignore
|
||||
// the two low-order bits)
|
||||
nsDST(PtrBits aLevelZeroBit = 0x04);
|
||||
~nsDST();
|
||||
|
||||
void* Search(void* aKey) const;
|
||||
void* Insert(void* aKey, void* aValue); // returns the previous value (or 0)
|
||||
void* Remove(void* aKey);
|
||||
void Clear();
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
void Dump(FILE*) const;
|
||||
#endif
|
||||
|
||||
private:
|
||||
struct Node;
|
||||
struct NodeArena {
|
||||
PLArenaPool mPool;
|
||||
Node* mFreeList;
|
||||
|
||||
NodeArena();
|
||||
~NodeArena();
|
||||
|
||||
void* AllocNode(size_t);
|
||||
void FreeNode(void*);
|
||||
void FreeArenaPool();
|
||||
};
|
||||
Node* mRoot; // root node of the tree
|
||||
NodeArena mArena;
|
||||
PtrBits mLevelZeroBit;
|
||||
|
||||
private:
|
||||
Node** SearchTree(void* aKey) const;
|
||||
Node** FindLeafNode(Node** aNode) const;
|
||||
void DestroyNode(Node* aNode);
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
Node* DepthFirstSearch(Node* aNode, void* aKey) const;
|
||||
void VerifyTree(Node* aNode, PtrBits aBitMask) const;
|
||||
void GatherStatistics(Node* aNode,
|
||||
int aLevel,
|
||||
int& aNumNodes,
|
||||
int aNodesPerLevel[]) const;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif /* nsDST_h___ */
|
||||
|
Загрузка…
Ссылка в новой задаче