splay-tree.c 14.7 KB
Newer Older
Mark Mitchell committed
1
/* A splay-tree datatype.  
2
   Copyright (C) 1998, 1999, 2000, 2001, 2009,
3
   2010, 2011 Free Software Foundation, Inc.
Mark Mitchell committed
4 5
   Contributed by Mark Mitchell (mark@markmitchell.com).

Jeff Law committed
6
This file is part of GNU CC.
Mark Mitchell committed
7
   
Jeff Law committed
8 9 10 11
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.
Mark Mitchell committed
12

Jeff Law committed
13 14 15 16
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.
Mark Mitchell committed
17

Jeff Law committed
18 19
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING.  If not, write to
20 21
the Free Software Foundation, 51 Franklin Street - Fifth Floor,
Boston, MA 02110-1301, USA.  */
Mark Mitchell committed
22

Jeff Law committed
23
/* For an easily readable description of splay-trees, see:
Mark Mitchell committed
24 25 26 27

     Lewis, Harry R. and Denenberg, Larry.  Data Structures and Their
     Algorithms.  Harper-Collins, Inc.  1991.  */

28
#ifdef HAVE_CONFIG_H
29 30 31 32 33 34 35
#include "config.h"
#endif

#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif

36 37
#include <stdio.h>

Mark Mitchell committed
38 39 40
#include "libiberty.h"
#include "splay-tree.h"

41
static void splay_tree_delete_helper (splay_tree, splay_tree_node);
42 43 44 45
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);
46
static void splay_tree_splay (splay_tree, splay_tree_key);
47
static int splay_tree_foreach_helper (splay_tree_node,
48
                                      splay_tree_foreach_fn, void*);
Mark Mitchell committed
49 50 51 52

/* Deallocate NODE (a member of SP), and all its sub-trees.  */

static void 
53
splay_tree_delete_helper (splay_tree sp, splay_tree_node node)
Mark Mitchell committed
54
{
55 56 57
  splay_tree_node pending = 0;
  splay_tree_node active = 0;

Mark Mitchell committed
58 59 60
  if (!node)
    return;

61 62 63 64 65
#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);
Mark Mitchell committed
66

67 68 69
  /* We use the "key" field to hold the "next" pointer.  */
  node->key = (splay_tree_key)pending;
  pending = (splay_tree_node)node;
Mark Mitchell committed
70

71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
  /* 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
Mark Mitchell committed
108 109
}

110
/* Rotate the edge joining the left child N with its parent P.  PP is the
111
   grandparents' pointer to P.  */
Mark Mitchell committed
112

113 114
static inline void
rotate_left (splay_tree_node *pp, splay_tree_node p, splay_tree_node n)
Mark Mitchell committed
115
{
116 117 118 119 120 121
  splay_tree_node tmp;
  tmp = n->right;
  n->right = p;
  p->left = tmp;
  *pp = n;
}
Mark Mitchell committed
122

123
/* Rotate the edge joining the right child N with its parent P.  PP is the
124
   grandparents' pointer to P.  */
Mark Mitchell committed
125

126 127 128 129 130 131 132 133
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;
Mark Mitchell committed
134 135
}

136
/* Bottom up splay of key.  */
Mark Mitchell committed
137 138

static void
139
splay_tree_splay (splay_tree sp, splay_tree_key key)
Mark Mitchell committed
140 141 142 143
{
  if (sp->root == 0)
    return;

144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
  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);
Mark Mitchell committed
199 200 201 202 203 204 205
}

/* 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.  */

206
static int
207
splay_tree_foreach_helper (splay_tree_node node,
208
                           splay_tree_foreach_fn fn, void *data)
Mark Mitchell committed
209 210
{
  int val;
211 212
  splay_tree_node *stack;
  int stack_ptr, stack_size;
Mark Mitchell committed
213

214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
  /* 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;
	}
Mark Mitchell committed
236

237 238
      if (stack_ptr == 0)
	break;
Mark Mitchell committed
239

240
      node = stack[--stack_ptr];
Mark Mitchell committed
241

242 243 244
      val = (*fn) (node, data);
      if (val)
	break;
Mark Mitchell committed
245

246 247 248 249 250 251
      node = node->right;
    }

  XDELETEVEC (stack);
  return val;
}
252 253 254

/* An allocator and deallocator based on xmalloc.  */
static void *
255
splay_tree_xmalloc_allocate (int size, void *data ATTRIBUTE_UNUSED)
256
{
257
  return (void *) xmalloc (size);
258 259 260
}

static void
261
splay_tree_xmalloc_deallocate (void *object, void *data ATTRIBUTE_UNUSED)
262 263 264 265 266
{
  free (object);
}


Mark Mitchell committed
267 268
/* Allocate a new splay tree, using COMPARE_FN to compare nodes,
   DELETE_KEY_FN to deallocate keys, and DELETE_VALUE_FN to deallocate
269 270
   values.  Use xmalloc to allocate the splay tree structure, and any
   nodes added.  */
Mark Mitchell committed
271 272

splay_tree 
273 274 275
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)
Mark Mitchell committed
276
{
277 278 279 280 281 282 283 284 285 286 287
  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 
288 289 290 291 292 293
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)
294
{
295 296 297 298 299 300 301 302
  return
    splay_tree_new_typed_alloc (compare_fn, delete_key_fn, delete_value_fn,
				allocate_fn, allocate_fn, deallocate_fn,
				allocate_data);
}

/*

303 304 305 306 307 308 309
@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}, @
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336
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);

Mark Mitchell committed
337 338 339 340
  sp->root = 0;
  sp->comp = compare_fn;
  sp->delete_key = delete_key_fn;
  sp->delete_value = delete_value_fn;
341
  sp->allocate = node_allocate_fn;
342 343
  sp->deallocate = deallocate_fn;
  sp->allocate_data = allocate_data;
Mark Mitchell committed
344 345 346 347 348 349 350

  return sp;
}

/* Deallocate SP.  */

void 
351
splay_tree_delete (splay_tree sp)
Mark Mitchell committed
352 353
{
  splay_tree_delete_helper (sp, sp->root);
354
  (*sp->deallocate) ((char*) sp, sp->allocate_data);
Mark Mitchell committed
355 356 357 358
}

/* Insert a new node (associating KEY with DATA) into SP.  If a
   previous node with the indicated KEY exists, its data is replaced
359
   with the new value.  Returns the new node.  */
Mark Mitchell committed
360

361
splay_tree_node
362
splay_tree_insert (splay_tree sp, splay_tree_key key, splay_tree_value value)
Mark Mitchell committed
363
{
364
  int comparison = 0;
Mark Mitchell committed
365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382

  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;
383

384
      node = ((splay_tree_node)
385 386
	      (*sp->allocate) (sizeof (struct splay_tree_node_s),
			       sp->allocate_data));
Mark Mitchell committed
387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404
      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;
	}

405 406
      sp->root = node;
    }
407 408

  return sp->root;
Mark Mitchell committed
409 410
}

411 412 413
/* Remove KEY from SP.  It is not an error if it did not exist.  */

void
414
splay_tree_remove (splay_tree sp, splay_tree_key key)
415 416 417 418 419 420 421 422 423 424 425 426 427
{
  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);
428
      (*sp->deallocate) (sp->root, sp->allocate_data);
429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449

      /* 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;
    }
}

Mark Mitchell committed
450 451 452 453
/* Lookup KEY in SP, returning VALUE if present, and NULL 
   otherwise.  */

splay_tree_node
454
splay_tree_lookup (splay_tree sp, splay_tree_key key)
Mark Mitchell committed
455 456 457 458 459 460 461 462 463
{
  splay_tree_splay (sp, key);

  if (sp->root && (*sp->comp)(sp->root->key, key) == 0)
    return sp->root;
  else
    return 0;
}

464 465 466
/* Return the node in SP with the greatest key.  */

splay_tree_node
467
splay_tree_max (splay_tree sp)
468 469 470 471 472 473 474 475 476 477 478 479 480 481 482
{
  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
483
splay_tree_min (splay_tree sp)
484 485 486 487 488 489 490 491 492 493 494 495
{
  splay_tree_node n = sp->root;

  if (!n)
    return NULL;

  while (n->left)
    n = n->left;

  return n;
}

496 497 498 499
/* Return the immediate predecessor KEY, or NULL if there is no
   predecessor.  KEY need not be present in the tree.  */

splay_tree_node
500
splay_tree_predecessor (splay_tree sp, splay_tree_key key)
501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517
{
  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;

518
  /* Otherwise, find the rightmost element of the left subtree.  */
519 520 521 522 523 524 525 526 527
  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
528
   successor.  KEY need not be present in the tree.  */
529 530

splay_tree_node
531
splay_tree_successor (splay_tree sp, splay_tree_key key)
532 533 534 535
{
  int comparison;
  splay_tree_node node;

536
  /* If the tree is empty, there is certainly no successor.  */
537 538 539 540 541 542 543 544 545 546 547 548
  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;

549
  /* Otherwise, find the leftmost element of the right subtree.  */
550 551 552 553 554 555 556 557
  node = sp->root->right;
  if (node)
    while (node->left)
      node = node->left;

  return node;
}

Mark Mitchell committed
558 559 560 561 562 563
/* 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
564
splay_tree_foreach (splay_tree sp, splay_tree_foreach_fn fn, void *data)
Mark Mitchell committed
565
{
566
  return splay_tree_foreach_helper (sp->root, fn, data);
Mark Mitchell committed
567
}
568 569 570 571

/* Splay-tree comparison function, treating the keys as ints.  */

int
572
splay_tree_compare_ints (splay_tree_key k1, splay_tree_key k2)
573 574 575 576 577 578 579 580
{
  if ((int) k1 < (int) k2)
    return -1;
  else if ((int) k1 > (int) k2)
    return 1;
  else 
    return 0;
}
581 582 583 584

/* Splay-tree comparison function, treating the keys as pointers.  */

int
585
splay_tree_compare_pointers (splay_tree_key k1, splay_tree_key k2)
586 587 588 589 590 591 592 593
{
  if ((char*) k1 < (char*) k2)
    return -1;
  else if ((char*) k1 > (char*) k2)
    return 1;
  else 
    return 0;
}