lyx_mirror/development/Win32/vld/src/tree.h
Peter Kümmel c0708a5c5e add leak tool for msvc 'Visual Leak Detection' 1.9f: original files
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@21911 a592a061-630c-0410-9148-cb99ea01b6c8
2007-12-02 11:05:21 +00:00

787 lines
27 KiB
C++

////////////////////////////////////////////////////////////////////////////////
// $Id: tree.h,v 1.13 2006/11/18 03:12:35 dmouldin Exp $
//
// Visual Leak Detector - Red-black Tree Template
// Copyright (c) 2005-2006 Dan Moulding
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
// See COPYING.txt for the full terms of the GNU Lesser General Public License.
//
////////////////////////////////////////////////////////////////////////////////
#pragma once
#ifndef VLDBUILD
#error \
"This header should only be included by Visual Leak Detector when building it from source. \
Applications should never include this header."
#endif
#include "vldheap.h" // Provides internal new and delete operators.
#define TREE_DEFAULT_RESERVE 32 // By default, trees reserve enough space, in advance, for this many nodes.
////////////////////////////////////////////////////////////////////////////////
//
// The Tree Template Class
//
// This data structure is the internal data structure behind the lightweight
// STL-like container classes. This is a red-black tree which provides for
// fast insert, find, and erase operations.
//
// The binary tree nodes are overlaid on top of larger chunks of allocated
// memory (called chunks) which are arranged in a simple linked list. This
// allows the tree to grow (add nodes) dynamically without incurring a heap
// hit each time a new node is added.
//
// The Tree class provides member functions which make it easily adaptable to
// an STL-like interface so that it can be used as the backend for STL-like
// container classes.
//
template <typename T>
class Tree
{
public:
// This is a red-black tree.
enum color_e {
red,
black
};
// The node is the basic data structure which the tree is built from.
typedef struct node_s {
color_e color; // The node's color.
T key; // The node's value, by which nodes are sorted.
union {
struct node_s *left; // For nodes in the tree, the node's left child.
struct node_s *next; // For nodes in the free list, the next node on the free list.
};
struct node_s *parent; // The node's parent.
struct node_s *right; // The node's right child.
} node_t;
// Reserve capacity for the tree is allocated in large chunks with room for
// many nodes.
typedef struct chunk_s {
struct chunk_s *next; // Pointer to the next node in the chunk list.
node_t *nodes; // Pointer to an array (of variable size) where nodes are stored.
} chunk_t;
// Constructor
Tree ()
{
m_freelist = NULL;
InitializeCriticalSection(&m_lock);
m_nil.color = black;
m_nil.key = T();
m_nil.left = &m_nil;
m_nil.parent = &m_nil;
m_nil.right = &m_nil;
m_reserve = TREE_DEFAULT_RESERVE;
m_root = &m_nil;
m_store = NULL;
m_storetail = NULL;
}
// Copy constructor - The sole purpose of this constructor's existence is
// to ensure that trees are not being inadvertently copied.
Tree (const Tree& source)
{
assert(FALSE); // Do not make copies of trees!
}
// Destructor
~Tree ()
{
chunk_t *cur;
chunk_t *temp;
// Free all the chunks in the chunk list.
EnterCriticalSection(&m_lock);
cur = m_store;
while (cur != NULL) {
temp = cur;
cur = cur->next;
delete [] temp->nodes;
delete temp;
}
LeaveCriticalSection(&m_lock);
DeleteCriticalSection(&m_lock);
}
// operator = - Assignment operator. For efficiency, we want to avoid ever
// making copies of Trees (only pointer passing or reference passing
// should be performed). The sole purpose of this assignment operator is
// to ensure that no copying is being done inadvertently.
//
Tree<T>& operator = (const Tree<T> &other)
{
// Don't make copies of Trees!
assert(FALSE);
return *this;
}
// begin - Obtains a pointer to the first node (the node with the smallest
// key value) in the tree.
//
// Return Value:
//
// Returns a pointer to the first node in the tree.
//
typename Tree::node_t* begin () const
{
node_t *cur;
EnterCriticalSection(&m_lock);
if (m_root == &m_nil) {
LeaveCriticalSection(&m_lock);
return NULL;
}
cur = m_root;
while (cur->left != &m_nil) {
cur = cur->left;
}
LeaveCriticalSection(&m_lock);
return cur;
}
// erase - Erases the specified node from the tree. Note that this does
// not cause the key associated with the erased node to be freed. The
// caller is responsible for freeing any dynamically allocated memory
// associated with the key.
//
// - node (IN): Pointer to the node to erase from the tree.
//
// Return Value:
//
// None.
//
VOID erase (typename Tree::node_t *node)
{
node_t *child;
node_t *cur;
node_t *erasure;
node_t *sibling;
EnterCriticalSection(&m_lock);
if ((node->left == &m_nil) || (node->right == &m_nil)) {
// The node to be erased has less than two children. It can be directly
// removed from the tree.
erasure = node;
}
else {
// The node to be erased has two children. It can only be removed
// indirectly. The actual node will stay where it is, but it's contents
// will be replaced by it's in-order successor's contents. The successor
// node will then be erased. Find the successor.
erasure = node->right;
while (erasure->left != &m_nil) {
erasure = erasure->left;
}
}
// Select the child node which will replace the node to be erased.
if (erasure->left != &m_nil) {
child = erasure->left;
}
else {
child = erasure->right;
}
// Replace the node to be erased with the selected child.
child->parent = erasure->parent;
if (child->parent == &m_nil) {
// The root of the tree is being erased. The child becomes root.
m_root = child;
}
else {
if (erasure == erasure->parent->left) {
erasure->parent->left = child;
}
else {
erasure->parent->right = child;
}
}
if (erasure != node) {
// The node being erased from the tree is the successor of the actual
// node to be erased. Replace the contents of the node to be erased
// with the successor's contents.
node->key = erasure->key;
}
if (erasure->color == black) {
// The node being erased from the tree is black. Restructuring of the
// tree may be needed so that black-height is maintained.
cur = child;
while ((cur != m_root) && (cur->color == black)) {
if (cur == cur->parent->left) {
// Current node is a left child.
sibling = cur->parent->right;
if (sibling->color == red) {
// Sibling is red. Rotate sibling up and color it black.
sibling->color = black;
cur->parent->color = red;
_rotateleft(cur->parent);
sibling = cur->parent->right;
}
if ((sibling->left->color == black) && (sibling->right->color == black)) {
// Both of sibling's children are black. Color sibling red.
sibling->color = red;
cur = cur->parent;
}
else {
// At least one of sibling's children is red.
if (sibling->right->color == black) {
sibling->left->color = black;
sibling->color = red;
_rotateright(sibling);
sibling = cur->parent->right;
}
sibling->color = cur->parent->color;
cur->parent->color = black;
sibling->right->color = black;
_rotateleft(cur->parent);
cur = m_root;
}
}
else {
// Current node is a right child.
sibling = cur->parent->left;
if (sibling->color == red) {
// Sibling is red. Rotate sibling up and color it black.
sibling->color = black;
cur->parent->color = red;
_rotateright(cur->parent);
sibling = cur->parent->left;
}
if ((sibling->left->color == black) && (sibling->right->color == black)) {
// Both of sibling's children are black. Color sibling red.
sibling->color = red;
cur = cur->parent;
}
else {
// At least one of sibling's children is red.
if (sibling->left->color == black) {
sibling->right->color = black;
sibling->color = red;
_rotateleft(sibling);
sibling = cur->parent->left;
}
sibling->color = cur->parent->color;
cur->parent->color = black;
sibling->left->color = black;
_rotateright(cur->parent);
cur = m_root;
}
}
}
cur->color = black;
}
// Put the erased node onto the free list.
erasure->next = m_freelist;
m_freelist = erasure;
LeaveCriticalSection(&m_lock);
}
// erase - Erases the specified key from the tree. Note that this does
// not cause the key associated with the erased node to be freed. The
// caller is responsible for freeing any dynamically allocated memory
// associated with the key.
//
// - key (IN): The key to erase from the tree. This value is treated as
// the key for sorting within the tree. It must therefore be of a type
// which supports the "<" operator.
//
// Return Value:
//
// None.
//
VOID erase (const T &key)
{
node_t *node;
// Find the node to erase.
EnterCriticalSection(&m_lock);
node = m_root;
while (node != &m_nil) {
if (node->key < key) {
// Go right.
node = node->right;
}
else if (key < node->key) {
// Go left.
node = node->left;
}
else {
// Found it.
erase(node);
LeaveCriticalSection(&m_lock);
return;
}
}
LeaveCriticalSection(&m_lock);
// 'key' is not in the tree.
return;
}
// find - Obtains a pointer to the node corresponding to the specified key.
//
// - key (IN): The value to search for in the tree. This value is treated
// as the key for sorting within the tree. It must therefore be of a
// type which supports the "<" operator.
//
// Return Value:
//
// Returns a pointer to the node corresponding to the specified key. If
// the key is not in the tree, then "find" returns NULL.
//
typename Tree::node_t* find (const T &key) const
{
node_t *cur;
EnterCriticalSection(&m_lock);
cur = m_root;
while (cur != &m_nil) {
if (cur->key < key) {
// Go right.
cur = cur->right;
}
else if (key < cur->key) {
// Go left.
cur = cur->left;
}
else {
// Found it.
LeaveCriticalSection(&m_lock);
return cur;
}
}
LeaveCriticalSection(&m_lock);
// 'key' is not in the tree.
return NULL;
}
// insert - Inserts a new key into the tree.
//
// - key (IN): The key to insert into the tree. This value is treated as
// the key for sorting within the tree. It must therefore be of a type
// which supports the "<" operator.
//
// Return Value:
//
// Returns a pointer to the node corresponding to the newly inserted
// key. If an attempt is made to insert a key which is already in the
// tree, then NULL is returned and the new key is not inserted.
//
typename Tree::node_t* insert (const T &key)
{
node_t *cur;
node_t *node;
node_t *parent;
node_t *uncle;
EnterCriticalSection(&m_lock);
// Find the location where the new node should be inserted..
cur = m_root;
parent = &m_nil;
while (cur != &m_nil) {
parent = cur;
if (cur->key < key) {
// Go right.
cur = cur->right;
}
else if (key < cur->key) {
// Go left.
cur = cur->left;
}
else {
// Keys in the tree must be unique.
LeaveCriticalSection(&m_lock);
return NULL;
}
}
// Obtain a new node from the free list.
if (m_freelist == NULL) {
// Allocate additional storage.
reserve(m_reserve);
}
node = m_freelist;
m_freelist = m_freelist->next;
// Initialize the new node and insert it.
node->color = red;
node->key = key;
node->left = &m_nil;
node->parent = parent;
node->right = &m_nil;
if (parent == &m_nil) {
// The tree is empty. The new node becomes root.
m_root = node;
}
else {
if (parent->key < key) {
// New node is a right child.
parent->right = node;
}
else {
// New node is a left child.
parent->left = node;
}
}
// Rebalance and/or adjust the tree, if necessary.
cur = node;
while (cur->parent->color == red) {
// Double-red violation. Rebalancing/adjustment needed.
if (cur->parent == cur->parent->parent->left) {
// Parent is the left child. Uncle is the right child.
uncle = cur->parent->parent->right;
if (uncle->color == red) {
// Uncle is red. Recolor.
cur->parent->parent->color = red;
cur->parent->color = black;
uncle->color = black;
cur = cur->parent->parent;
}
else {
// Uncle is black. Restructure.
if (cur == cur->parent->right) {
cur = cur->parent;
_rotateleft(cur);
}
cur->parent->color = black;
cur->parent->parent->color = red;
_rotateright(cur->parent->parent);
}
}
else {
// Parent is the right child. Uncle is the left child.
uncle = cur->parent->parent->left;
if (uncle->color == red) {
// Uncle is red. Recolor.
cur->parent->parent->color = red;
cur->parent->color = black;
uncle->color = black;
cur = cur->parent->parent;
}
else {
// Uncle is black. Restructure.
if (cur == cur->parent->left) {
cur = cur->parent;
_rotateright(cur);
}
cur->parent->color = black;
cur->parent->parent->color = red;
_rotateleft(cur->parent->parent);
}
}
}
// The root node is always colored black.
m_root->color = black;
LeaveCriticalSection(&m_lock);
return node;
}
// next - Obtains a pointer to the in-order successor of the specified
// node.
//
// - node (IN): Pointer to the node whose in-order successor to retrieve.
//
// Return Value:
//
// Returns a pointer to the node's in-order successor. If the specified
// node corresponds to the largest value in the tree, then the specified
// node has no successor and "next" will return NULL.
//
typename Tree::node_t* next (typename Tree::node_t *node) const
{
node_t* cur;
if (node == NULL) {
return NULL;
}
EnterCriticalSection(&m_lock);
if (node->right != &m_nil) {
// 'node' has a right child. Successor is the far left node in
// the right subtree.
cur = node->right;
while (cur->left != &m_nil) {
cur = cur->left;
}
LeaveCriticalSection(&m_lock);
return cur;
}
else if (node->parent != &m_nil) {
// 'node' has no right child, but does have a parent.
if (node == node->parent->left) {
// 'node' is a left child; node's parent is successor.
LeaveCriticalSection(&m_lock);
return node->parent;
}
else {
// 'node' is a right child.
cur = node;
// Go up the tree until we find a parent to the right.
while (cur->parent != &m_nil) {
if (cur == cur->parent->right) {
cur = cur->parent;
continue;
}
else {
LeaveCriticalSection(&m_lock);
return cur->parent;
}
}
// There is no parent greater than 'node'. 'node' is the
// maximum node.
LeaveCriticalSection(&m_lock);
return NULL;
}
}
else {
// 'node' is root and root is the maximum node.
LeaveCriticalSection(&m_lock);
return NULL;
}
}
// prev - Obtains a pointer to the in-order predecessor of the specified
// node.
//
// - node (IN): Pointer to the node whose in-order predecessor to retrieve.
//
// Return Value:
//
// Returns a pointer to the node's in-order predecessor. If the specified
// node corresponds to the smallest value in the tree, then the specified
// node has no predecessor and "prev" will return NULL.
//
typename Tree::node_t* prev (typename Tree::node_t *node) const
{
node_t* cur;
if (node == NULL) {
return NULL;
}
EnterCriticalSection(&m_lock);
if (node->left != &m_nil) {
// 'node' has left child. Predecessor is the far right node in the
// left subtree.
cur = node->left;
while (cur->right != &m_nil) {
cur = cur->right;
}
LeaveCriticalSection(&m_lock);
return cur;
}
else if (node->parent != & m_nil) {
// 'node' has no left child, but does have a parent.
if (node == node->parent->right) {
// 'node' is a right child; node's parent is predecessor.
LeaveCriticalSection(&m_lock);
return node->parent;
}
else {
// 'node is a left child.
cur = node;
// Go up the tree until we find a parent to the left.
while (cur->parent != &m_nil) {
if (cur == cur->parent->left) {
cur = cur->parent;
continue;
}
else {
LeaveCriticalSection(&m_lock);
return cur->parent;
}
}
// There is no parent less than 'node'. 'node' is the minimum
// node.
LeaveCriticalSection(&m_lock);
return NULL;
}
}
else {
// 'node' is root and root is the minimum node.
LeaveCriticalSection(&m_lock);
return NULL;
}
}
// reserve - Reserves storage for a number of nodes in advance and/or sets
// the number of nodes for which the tree will automatically reserve
// storage when the tree needs to "grow" to accomodate new values being
// inserted into the tree. If this function is not called to set the
// reserve size to a specific value, then a pre-determined default value
// will be used. If this function is called when the tree currently has
// no reserve storage, then in addition to setting the tree's reserve
// value, it will also cause the tree to immediately reserve the
// specified amount of storage.
//
// - count (IN): The number of individual nodes' worth of storage to
// reserve.
//
// Return Value:
//
// Returns the previously defined reserve value.
//
UINT32 reserve (UINT32 count)
{
chunk_t *chunk;
UINT32 index;
UINT32 oldreserve = m_reserve;
if (count != m_reserve) {
if (count < 1) {
// Minimum reserve size is 1.
m_reserve = 1;
}
else {
m_reserve = count;
}
}
EnterCriticalSection(&m_lock);
if (m_freelist == NULL) {
// Allocate additional storage.
// Link a new chunk into the chunk list.
chunk = new Tree::chunk_t;
chunk->nodes = new Tree::node_s [m_reserve];
chunk->next = NULL;
if (m_store == NULL) {
m_store = chunk;
}
else {
m_storetail->next = chunk;
}
m_storetail = chunk;
// Link the individual nodes together to form a new free list.
for (index = 0; index < m_reserve - 1; index++) {
chunk->nodes[index].next = &chunk->nodes[index + 1];
}
chunk->nodes[index].next = NULL;
m_freelist = chunk->nodes;
}
LeaveCriticalSection(&m_lock);
return oldreserve;
}
private:
// _rotateleft: Rotates a pair of nodes counter-clockwise so that the parent
// node becomes the left child and the right child becomes the parent.
//
// - parent (IN): Pointer to the parent to rotate about.
//
// Return Value:
//
// None.
//
VOID _rotateleft (typename Tree::node_t *parent)
{
node_t *child = parent->right;
// Reassign the child's left subtree to the parent.
parent->right = child->left;
if (child->left != &m_nil) {
child->left->parent = parent;
}
// Reassign the child/parent relationship.
child->parent = parent->parent;
if (parent->parent == &m_nil) {
// The child becomes the new root node.
m_root = child;
}
else {
// Point the grandparent at the child.
if (parent == parent->parent->left) {
parent->parent->left = child;
}
else {
parent->parent->right = child;
}
}
child->left = parent;
parent->parent = child;
}
// _rotateright - Rotates a pair of nodes clockwise so that the parent node
// becomes the right child and the left child becomes the parent.
//
// - parent (IN): Pointer to the parent to rotate about.
//
// Return Value:
//
// None.
//
VOID _rotateright (typename Tree::node_t *parent)
{
node_t *child = parent->left;
// Reassign the child's right subtree to the parent.
parent->left = child->right;
if (child->right != &m_nil) {
child->right->parent = parent;
}
// Reassign the child/parent relationship.
child->parent = parent->parent;
if (parent->parent == &m_nil) {
// The child becomes the new root node.
m_root = child;
}
else {
// Point the grandparent at the child.
if (parent == parent->parent->left) {
parent->parent->left = child;
}
else {
parent->parent->right = child;
}
}
child->right = parent;
parent->parent = child;
}
// Private data members.
node_t *m_freelist; // Pointer to the list of free nodes (reserve storage).
mutable CRITICAL_SECTION m_lock; // Protects the tree's integrity against concurrent accesses.
node_t m_nil; // The tree's nil node. All leaf nodes point to this.
UINT32 m_reserve; // The size (in nodes) of the chunks of reserve storage.
node_t *m_root; // Pointer to the tree's root node.
chunk_t *m_store; // Pointer to the start of the chunk list.
chunk_t *m_storetail; // Pointer to the end of the chunk list.
};