mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-11-15 15:45:43 +00:00
786 lines
27 KiB
C
786 lines
27 KiB
C
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// 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.
|
||
|
};
|