123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594 |
- /* A splay-tree datatype.
- Copyright (C) 1998, 1999, 2000, 2001, 2009,
- 2010, 2011 Free Software Foundation, Inc.
- Contributed by Mark Mitchell (mark@markmitchell.com).
- This file is part of GNU CC.
-
- GNU CC is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
- GNU CC 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
- General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with GNU CC; see the file COPYING. If not, write to
- the Free Software Foundation, 51 Franklin Street - Fifth Floor,
- Boston, MA 02110-1301, USA. */
- /* For an easily readable description of splay-trees, see:
- Lewis, Harry R. and Denenberg, Larry. Data Structures and Their
- Algorithms. Harper-Collins, Inc. 1991. */
- #ifdef HAVE_CONFIG_H
- #include "config.h"
- #endif
- #ifdef HAVE_STDLIB_H
- #include <stdlib.h>
- #endif
- #include <stdio.h>
- #include "libiberty.h"
- #include "splay-tree.h"
- static void splay_tree_delete_helper (splay_tree, splay_tree_node);
- static inline void rotate_left (splay_tree_node *,
- splay_tree_node, splay_tree_node);
- static inline void rotate_right (splay_tree_node *,
- splay_tree_node, splay_tree_node);
- static void splay_tree_splay (splay_tree, splay_tree_key);
- static int splay_tree_foreach_helper (splay_tree_node,
- splay_tree_foreach_fn, void*);
- /* Deallocate NODE (a member of SP), and all its sub-trees. */
- static void
- splay_tree_delete_helper (splay_tree sp, splay_tree_node node)
- {
- splay_tree_node pending = 0;
- splay_tree_node active = 0;
- if (!node)
- return;
- #define KDEL(x) if (sp->delete_key) (*sp->delete_key)(x);
- #define VDEL(x) if (sp->delete_value) (*sp->delete_value)(x);
- KDEL (node->key);
- VDEL (node->value);
- /* We use the "key" field to hold the "next" pointer. */
- node->key = (splay_tree_key)pending;
- pending = (splay_tree_node)node;
- /* Now, keep processing the pending list until there aren't any
- more. This is a little more complicated than just recursing, but
- it doesn't toast the stack for large trees. */
- while (pending)
- {
- active = pending;
- pending = 0;
- while (active)
- {
- splay_tree_node temp;
- /* active points to a node which has its key and value
- deallocated, we just need to process left and right. */
- if (active->left)
- {
- KDEL (active->left->key);
- VDEL (active->left->value);
- active->left->key = (splay_tree_key)pending;
- pending = (splay_tree_node)(active->left);
- }
- if (active->right)
- {
- KDEL (active->right->key);
- VDEL (active->right->value);
- active->right->key = (splay_tree_key)pending;
- pending = (splay_tree_node)(active->right);
- }
- temp = active;
- active = (splay_tree_node)(temp->key);
- (*sp->deallocate) ((char*) temp, sp->allocate_data);
- }
- }
- #undef KDEL
- #undef VDEL
- }
- /* Rotate the edge joining the left child N with its parent P. PP is the
- grandparents' pointer to P. */
- static inline void
- rotate_left (splay_tree_node *pp, splay_tree_node p, splay_tree_node n)
- {
- splay_tree_node tmp;
- tmp = n->right;
- n->right = p;
- p->left = tmp;
- *pp = n;
- }
- /* Rotate the edge joining the right child N with its parent P. PP is the
- grandparents' pointer to P. */
- static inline void
- rotate_right (splay_tree_node *pp, splay_tree_node p, splay_tree_node n)
- {
- splay_tree_node tmp;
- tmp = n->left;
- n->left = p;
- p->right = tmp;
- *pp = n;
- }
- /* Bottom up splay of key. */
- static void
- splay_tree_splay (splay_tree sp, splay_tree_key key)
- {
- if (sp->root == 0)
- return;
- do {
- int cmp1, cmp2;
- splay_tree_node n, c;
- n = sp->root;
- cmp1 = (*sp->comp) (key, n->key);
- /* Found. */
- if (cmp1 == 0)
- return;
- /* Left or right? If no child, then we're done. */
- if (cmp1 < 0)
- c = n->left;
- else
- c = n->right;
- if (!c)
- return;
- /* Next one left or right? If found or no child, we're done
- after one rotation. */
- cmp2 = (*sp->comp) (key, c->key);
- if (cmp2 == 0
- || (cmp2 < 0 && !c->left)
- || (cmp2 > 0 && !c->right))
- {
- if (cmp1 < 0)
- rotate_left (&sp->root, n, c);
- else
- rotate_right (&sp->root, n, c);
- return;
- }
- /* Now we have the four cases of double-rotation. */
- if (cmp1 < 0 && cmp2 < 0)
- {
- rotate_left (&n->left, c, c->left);
- rotate_left (&sp->root, n, n->left);
- }
- else if (cmp1 > 0 && cmp2 > 0)
- {
- rotate_right (&n->right, c, c->right);
- rotate_right (&sp->root, n, n->right);
- }
- else if (cmp1 < 0 && cmp2 > 0)
- {
- rotate_right (&n->left, c, c->right);
- rotate_left (&sp->root, n, n->left);
- }
- else if (cmp1 > 0 && cmp2 < 0)
- {
- rotate_left (&n->right, c, c->left);
- rotate_right (&sp->root, n, n->right);
- }
- } while (1);
- }
- /* Call FN, passing it the DATA, for every node below NODE, all of
- which are from SP, following an in-order traversal. If FN every
- returns a non-zero value, the iteration ceases immediately, and the
- value is returned. Otherwise, this function returns 0. */
- static int
- splay_tree_foreach_helper (splay_tree_node node,
- splay_tree_foreach_fn fn, void *data)
- {
- int val;
- splay_tree_node *stack;
- int stack_ptr, stack_size;
- /* A non-recursive implementation is used to avoid filling the stack
- for large trees. Splay trees are worst case O(n) in the depth of
- the tree. */
- #define INITIAL_STACK_SIZE 100
- stack_size = INITIAL_STACK_SIZE;
- stack_ptr = 0;
- stack = XNEWVEC (splay_tree_node, stack_size);
- val = 0;
- for (;;)
- {
- while (node != NULL)
- {
- if (stack_ptr == stack_size)
- {
- stack_size *= 2;
- stack = XRESIZEVEC (splay_tree_node, stack, stack_size);
- }
- stack[stack_ptr++] = node;
- node = node->left;
- }
- if (stack_ptr == 0)
- break;
- node = stack[--stack_ptr];
- val = (*fn) (node, data);
- if (val)
- break;
- node = node->right;
- }
- XDELETEVEC (stack);
- return val;
- }
- /* An allocator and deallocator based on xmalloc. */
- static void *
- splay_tree_xmalloc_allocate (int size, void *data ATTRIBUTE_UNUSED)
- {
- return (void *) xmalloc (size);
- }
- static void
- splay_tree_xmalloc_deallocate (void *object, void *data ATTRIBUTE_UNUSED)
- {
- free (object);
- }
- /* Allocate a new splay tree, using COMPARE_FN to compare nodes,
- DELETE_KEY_FN to deallocate keys, and DELETE_VALUE_FN to deallocate
- values. Use xmalloc to allocate the splay tree structure, and any
- nodes added. */
- splay_tree
- splay_tree_new (splay_tree_compare_fn compare_fn,
- splay_tree_delete_key_fn delete_key_fn,
- splay_tree_delete_value_fn delete_value_fn)
- {
- return (splay_tree_new_with_allocator
- (compare_fn, delete_key_fn, delete_value_fn,
- splay_tree_xmalloc_allocate, splay_tree_xmalloc_deallocate, 0));
- }
- /* Allocate a new splay tree, using COMPARE_FN to compare nodes,
- DELETE_KEY_FN to deallocate keys, and DELETE_VALUE_FN to deallocate
- values. */
- splay_tree
- splay_tree_new_with_allocator (splay_tree_compare_fn compare_fn,
- splay_tree_delete_key_fn delete_key_fn,
- splay_tree_delete_value_fn delete_value_fn,
- splay_tree_allocate_fn allocate_fn,
- splay_tree_deallocate_fn deallocate_fn,
- void *allocate_data)
- {
- return
- splay_tree_new_typed_alloc (compare_fn, delete_key_fn, delete_value_fn,
- allocate_fn, allocate_fn, deallocate_fn,
- allocate_data);
- }
- /*
- @deftypefn Supplemental splay_tree splay_tree_new_with_typed_alloc @
- (splay_tree_compare_fn @var{compare_fn}, @
- splay_tree_delete_key_fn @var{delete_key_fn}, @
- splay_tree_delete_value_fn @var{delete_value_fn}, @
- splay_tree_allocate_fn @var{tree_allocate_fn}, @
- splay_tree_allocate_fn @var{node_allocate_fn}, @
- splay_tree_deallocate_fn @var{deallocate_fn}, @
- void * @var{allocate_data})
- This function creates a splay tree that uses two different allocators
- @var{tree_allocate_fn} and @var{node_allocate_fn} to use for allocating the
- tree itself and its nodes respectively. This is useful when variables of
- different types need to be allocated with different allocators.
- The splay tree will use @var{compare_fn} to compare nodes,
- @var{delete_key_fn} to deallocate keys, and @var{delete_value_fn} to
- deallocate values.
- @end deftypefn
- */
- splay_tree
- splay_tree_new_typed_alloc (splay_tree_compare_fn compare_fn,
- splay_tree_delete_key_fn delete_key_fn,
- splay_tree_delete_value_fn delete_value_fn,
- splay_tree_allocate_fn tree_allocate_fn,
- splay_tree_allocate_fn node_allocate_fn,
- splay_tree_deallocate_fn deallocate_fn,
- void * allocate_data)
- {
- splay_tree sp = (splay_tree) (*tree_allocate_fn)
- (sizeof (struct splay_tree_s), allocate_data);
- sp->root = 0;
- sp->comp = compare_fn;
- sp->delete_key = delete_key_fn;
- sp->delete_value = delete_value_fn;
- sp->allocate = node_allocate_fn;
- sp->deallocate = deallocate_fn;
- sp->allocate_data = allocate_data;
- return sp;
- }
- /* Deallocate SP. */
- void
- splay_tree_delete (splay_tree sp)
- {
- splay_tree_delete_helper (sp, sp->root);
- (*sp->deallocate) ((char*) sp, sp->allocate_data);
- }
- /* Insert a new node (associating KEY with DATA) into SP. If a
- previous node with the indicated KEY exists, its data is replaced
- with the new value. Returns the new node. */
- splay_tree_node
- splay_tree_insert (splay_tree sp, splay_tree_key key, splay_tree_value value)
- {
- int comparison = 0;
- splay_tree_splay (sp, key);
- if (sp->root)
- comparison = (*sp->comp)(sp->root->key, key);
- if (sp->root && comparison == 0)
- {
- /* If the root of the tree already has the indicated KEY, just
- replace the value with VALUE. */
- if (sp->delete_value)
- (*sp->delete_value)(sp->root->value);
- sp->root->value = value;
- }
- else
- {
- /* Create a new node, and insert it at the root. */
- splay_tree_node node;
- node = ((splay_tree_node)
- (*sp->allocate) (sizeof (struct splay_tree_node_s),
- sp->allocate_data));
- node->key = key;
- node->value = value;
-
- if (!sp->root)
- node->left = node->right = 0;
- else if (comparison < 0)
- {
- node->left = sp->root;
- node->right = node->left->right;
- node->left->right = 0;
- }
- else
- {
- node->right = sp->root;
- node->left = node->right->left;
- node->right->left = 0;
- }
- sp->root = node;
- }
- return sp->root;
- }
- /* Remove KEY from SP. It is not an error if it did not exist. */
- void
- splay_tree_remove (splay_tree sp, splay_tree_key key)
- {
- splay_tree_splay (sp, key);
- if (sp->root && (*sp->comp) (sp->root->key, key) == 0)
- {
- splay_tree_node left, right;
- left = sp->root->left;
- right = sp->root->right;
- /* Delete the root node itself. */
- if (sp->delete_value)
- (*sp->delete_value) (sp->root->value);
- (*sp->deallocate) (sp->root, sp->allocate_data);
- /* One of the children is now the root. Doesn't matter much
- which, so long as we preserve the properties of the tree. */
- if (left)
- {
- sp->root = left;
- /* If there was a right child as well, hang it off the
- right-most leaf of the left child. */
- if (right)
- {
- while (left->right)
- left = left->right;
- left->right = right;
- }
- }
- else
- sp->root = right;
- }
- }
- /* Lookup KEY in SP, returning VALUE if present, and NULL
- otherwise. */
- splay_tree_node
- splay_tree_lookup (splay_tree sp, splay_tree_key key)
- {
- splay_tree_splay (sp, key);
- if (sp->root && (*sp->comp)(sp->root->key, key) == 0)
- return sp->root;
- else
- return 0;
- }
- /* Return the node in SP with the greatest key. */
- splay_tree_node
- splay_tree_max (splay_tree sp)
- {
- splay_tree_node n = sp->root;
- if (!n)
- return NULL;
- while (n->right)
- n = n->right;
- return n;
- }
- /* Return the node in SP with the smallest key. */
- splay_tree_node
- splay_tree_min (splay_tree sp)
- {
- splay_tree_node n = sp->root;
- if (!n)
- return NULL;
- while (n->left)
- n = n->left;
- return n;
- }
- /* Return the immediate predecessor KEY, or NULL if there is no
- predecessor. KEY need not be present in the tree. */
- splay_tree_node
- splay_tree_predecessor (splay_tree sp, splay_tree_key key)
- {
- int comparison;
- splay_tree_node node;
- /* If the tree is empty, there is certainly no predecessor. */
- if (!sp->root)
- return NULL;
- /* Splay the tree around KEY. That will leave either the KEY
- itself, its predecessor, or its successor at the root. */
- splay_tree_splay (sp, key);
- comparison = (*sp->comp)(sp->root->key, key);
- /* If the predecessor is at the root, just return it. */
- if (comparison < 0)
- return sp->root;
- /* Otherwise, find the rightmost element of the left subtree. */
- node = sp->root->left;
- if (node)
- while (node->right)
- node = node->right;
- return node;
- }
- /* Return the immediate successor KEY, or NULL if there is no
- successor. KEY need not be present in the tree. */
- splay_tree_node
- splay_tree_successor (splay_tree sp, splay_tree_key key)
- {
- int comparison;
- splay_tree_node node;
- /* If the tree is empty, there is certainly no successor. */
- if (!sp->root)
- return NULL;
- /* Splay the tree around KEY. That will leave either the KEY
- itself, its predecessor, or its successor at the root. */
- splay_tree_splay (sp, key);
- comparison = (*sp->comp)(sp->root->key, key);
- /* If the successor is at the root, just return it. */
- if (comparison > 0)
- return sp->root;
- /* Otherwise, find the leftmost element of the right subtree. */
- node = sp->root->right;
- if (node)
- while (node->left)
- node = node->left;
- return node;
- }
- /* Call FN, passing it the DATA, for every node in SP, following an
- in-order traversal. If FN every returns a non-zero value, the
- iteration ceases immediately, and the value is returned.
- Otherwise, this function returns 0. */
- int
- splay_tree_foreach (splay_tree sp, splay_tree_foreach_fn fn, void *data)
- {
- return splay_tree_foreach_helper (sp->root, fn, data);
- }
- /* Splay-tree comparison function, treating the keys as ints. */
- int
- splay_tree_compare_ints (splay_tree_key k1, splay_tree_key k2)
- {
- if ((int) k1 < (int) k2)
- return -1;
- else if ((int) k1 > (int) k2)
- return 1;
- else
- return 0;
- }
- /* Splay-tree comparison function, treating the keys as pointers. */
- int
- splay_tree_compare_pointers (splay_tree_key k1, splay_tree_key k2)
- {
- if ((char*) k1 < (char*) k2)
- return -1;
- else if ((char*) k1 > (char*) k2)
- return 1;
- else
- return 0;
- }
|