Coverage Report

Created: 2023-08-28 06:25

/src/binutils-gdb/libiberty/splay-tree.c
Line
Count
Source (jump to first uncovered line)
1
/* A splay-tree datatype.  
2
   Copyright (C) 1998-2023 Free Software Foundation, Inc.
3
   Contributed by Mark Mitchell (mark@markmitchell.com).
4
5
This file is part of GNU CC.
6
   
7
GNU CC is free software; you can redistribute it and/or modify it
8
under the terms of the GNU General Public License as published by
9
the Free Software Foundation; either version 2, or (at your option)
10
any later version.
11
12
GNU CC is distributed in the hope that it will be useful, but
13
WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
General Public License for more details.
16
17
You should have received a copy of the GNU General Public License
18
along with GNU CC; see the file COPYING.  If not, write to
19
the Free Software Foundation, 51 Franklin Street - Fifth Floor,
20
Boston, MA 02110-1301, USA.  */
21
22
/* For an easily readable description of splay-trees, see:
23
24
     Lewis, Harry R. and Denenberg, Larry.  Data Structures and Their
25
     Algorithms.  Harper-Collins, Inc.  1991.  */
26
27
#ifdef HAVE_CONFIG_H
28
#include "config.h"
29
#endif
30
31
#ifdef HAVE_STDLIB_H
32
#include <stdlib.h>
33
#endif
34
#ifdef HAVE_STRING_H
35
#include <string.h>
36
#endif
37
38
#include <stdio.h>
39
40
#include "libiberty.h"
41
#include "splay-tree.h"
42
43
static void splay_tree_delete_helper (splay_tree, splay_tree_node);
44
static inline void rotate_left (splay_tree_node *,
45
        splay_tree_node, splay_tree_node);
46
static inline void rotate_right (splay_tree_node *,
47
        splay_tree_node, splay_tree_node);
48
static void splay_tree_splay (splay_tree, splay_tree_key);
49
static int splay_tree_foreach_helper (splay_tree_node,
50
                                      splay_tree_foreach_fn, void*);
51
52
/* Deallocate NODE (a member of SP), and all its sub-trees.  */
53
54
static void 
55
splay_tree_delete_helper (splay_tree sp, splay_tree_node node)
56
387
{
57
387
  splay_tree_node pending = 0;
58
387
  splay_tree_node active = 0;
59
60
387
  if (!node)
61
0
    return;
62
63
3.53k
#define KDEL(x)  if (sp->delete_key) (*sp->delete_key)(x);
64
3.53k
#define VDEL(x)  if (sp->delete_value) (*sp->delete_value)(x);
65
66
387
  KDEL (node->key);
67
387
  VDEL (node->value);
68
69
  /* We use the "key" field to hold the "next" pointer.  */
70
387
  node->key = (splay_tree_key)pending;
71
387
  pending = (splay_tree_node)node;
72
73
  /* Now, keep processing the pending list until there aren't any
74
     more.  This is a little more complicated than just recursing, but
75
     it doesn't toast the stack for large trees.  */
76
77
3.91k
  while (pending)
78
3.53k
    {
79
3.53k
      active = pending;
80
3.53k
      pending = 0;
81
7.06k
      while (active)
82
3.53k
  {
83
3.53k
    splay_tree_node temp;
84
85
    /* active points to a node which has its key and value
86
       deallocated, we just need to process left and right.  */
87
88
3.53k
    if (active->left)
89
3.14k
      {
90
3.14k
        KDEL (active->left->key);
91
3.14k
        VDEL (active->left->value);
92
3.14k
        active->left->key = (splay_tree_key)pending;
93
3.14k
        pending = (splay_tree_node)(active->left);
94
3.14k
      }
95
3.53k
    if (active->right)
96
0
      {
97
0
        KDEL (active->right->key);
98
0
        VDEL (active->right->value);
99
0
        active->right->key = (splay_tree_key)pending;
100
0
        pending = (splay_tree_node)(active->right);
101
0
      }
102
103
3.53k
    temp = active;
104
3.53k
    active = (splay_tree_node)(temp->key);
105
3.53k
    (*sp->deallocate) ((char*) temp, sp->allocate_data);
106
3.53k
  }
107
3.53k
    }
108
387
#undef KDEL
109
387
#undef VDEL
110
387
}
111
112
/* Rotate the edge joining the left child N with its parent P.  PP is the
113
   grandparents' pointer to P.  */
114
115
static inline void
116
rotate_left (splay_tree_node *pp, splay_tree_node p, splay_tree_node n)
117
0
{
118
0
  splay_tree_node tmp;
119
0
  tmp = n->right;
120
0
  n->right = p;
121
0
  p->left = tmp;
122
0
  *pp = n;
123
0
}
124
125
/* Rotate the edge joining the right child N with its parent P.  PP is the
126
   grandparents' pointer to P.  */
127
128
static inline void
129
rotate_right (splay_tree_node *pp, splay_tree_node p, splay_tree_node n)
130
0
{
131
0
  splay_tree_node tmp;
132
0
  tmp = n->left;
133
0
  n->left = p;
134
0
  p->right = tmp;
135
0
  *pp = n;
136
0
}
137
138
/* Bottom up splay of key.  */
139
140
static void
141
splay_tree_splay (splay_tree sp, splay_tree_key key)
142
7.06k
{
143
7.06k
  if (sp->root == 0)
144
774
    return;
145
146
6.28k
  do {
147
6.28k
    int cmp1, cmp2;
148
6.28k
    splay_tree_node n, c;
149
150
6.28k
    n = sp->root;
151
6.28k
    cmp1 = (*sp->comp) (key, n->key);
152
153
    /* Found.  */
154
6.28k
    if (cmp1 == 0)
155
0
      return;
156
157
    /* Left or right?  If no child, then we're done.  */
158
6.28k
    if (cmp1 < 0)
159
0
      c = n->left;
160
6.28k
    else
161
6.28k
      c = n->right;
162
6.28k
    if (!c)
163
6.28k
      return;
164
165
    /* Next one left or right?  If found or no child, we're done
166
       after one rotation.  */
167
0
    cmp2 = (*sp->comp) (key, c->key);
168
0
    if (cmp2 == 0
169
0
        || (cmp2 < 0 && !c->left)
170
0
        || (cmp2 > 0 && !c->right))
171
0
      {
172
0
  if (cmp1 < 0)
173
0
    rotate_left (&sp->root, n, c);
174
0
  else
175
0
    rotate_right (&sp->root, n, c);
176
0
        return;
177
0
      }
178
179
    /* Now we have the four cases of double-rotation.  */
180
0
    if (cmp1 < 0 && cmp2 < 0)
181
0
      {
182
0
  rotate_left (&n->left, c, c->left);
183
0
  rotate_left (&sp->root, n, n->left);
184
0
      }
185
0
    else if (cmp1 > 0 && cmp2 > 0)
186
0
      {
187
0
  rotate_right (&n->right, c, c->right);
188
0
  rotate_right (&sp->root, n, n->right);
189
0
      }
190
0
    else if (cmp1 < 0 && cmp2 > 0)
191
0
      {
192
0
  rotate_right (&n->left, c, c->right);
193
0
  rotate_left (&sp->root, n, n->left);
194
0
      }
195
0
    else if (cmp1 > 0 && cmp2 < 0)
196
0
      {
197
0
  rotate_left (&n->right, c, c->left);
198
0
  rotate_right (&sp->root, n, n->right);
199
0
      }
200
0
  } while (1);
201
6.28k
}
202
203
/* Call FN, passing it the DATA, for every node below NODE, all of
204
   which are from SP, following an in-order traversal.  If FN every
205
   returns a non-zero value, the iteration ceases immediately, and the
206
   value is returned.  Otherwise, this function returns 0.  */
207
208
static int
209
splay_tree_foreach_helper (splay_tree_node node,
210
                           splay_tree_foreach_fn fn, void *data)
211
0
{
212
0
  int val;
213
0
  splay_tree_node *stack;
214
0
  int stack_ptr, stack_size;
215
216
  /* A non-recursive implementation is used to avoid filling the stack
217
     for large trees.  Splay trees are worst case O(n) in the depth of
218
     the tree.  */
219
220
0
#define INITIAL_STACK_SIZE 100
221
0
  stack_size = INITIAL_STACK_SIZE;
222
0
  stack_ptr = 0;
223
0
  stack = XNEWVEC (splay_tree_node, stack_size);
224
0
  val = 0;
225
226
0
  for (;;)
227
0
    {
228
0
      while (node != NULL)
229
0
  {
230
0
    if (stack_ptr == stack_size)
231
0
      {
232
0
        stack_size *= 2;
233
0
        stack = XRESIZEVEC (splay_tree_node, stack, stack_size);
234
0
      }
235
0
    stack[stack_ptr++] = node;
236
0
    node = node->left;
237
0
  }
238
239
0
      if (stack_ptr == 0)
240
0
  break;
241
242
0
      node = stack[--stack_ptr];
243
244
0
      val = (*fn) (node, data);
245
0
      if (val)
246
0
  break;
247
248
0
      node = node->right;
249
0
    }
250
251
0
  XDELETEVEC (stack);
252
0
  return val;
253
0
}
254
255
/* An allocator and deallocator based on xmalloc.  */
256
static void *
257
splay_tree_xmalloc_allocate (int size, void *data ATTRIBUTE_UNUSED)
258
3.91k
{
259
3.91k
  return (void *) xmalloc (size);
260
3.91k
}
261
262
static void
263
splay_tree_xmalloc_deallocate (void *object, void *data ATTRIBUTE_UNUSED)
264
3.91k
{
265
3.91k
  free (object);
266
3.91k
}
267
268
269
/* Allocate a new splay tree, using COMPARE_FN to compare nodes,
270
   DELETE_KEY_FN to deallocate keys, and DELETE_VALUE_FN to deallocate
271
   values.  Use xmalloc to allocate the splay tree structure, and any
272
   nodes added.  */
273
274
splay_tree 
275
splay_tree_new (splay_tree_compare_fn compare_fn,
276
                splay_tree_delete_key_fn delete_key_fn,
277
                splay_tree_delete_value_fn delete_value_fn)
278
387
{
279
387
  return (splay_tree_new_with_allocator
280
387
          (compare_fn, delete_key_fn, delete_value_fn,
281
387
           splay_tree_xmalloc_allocate, splay_tree_xmalloc_deallocate, 0));
282
387
}
283
284
285
/* Allocate a new splay tree, using COMPARE_FN to compare nodes,
286
   DELETE_KEY_FN to deallocate keys, and DELETE_VALUE_FN to deallocate
287
   values.  */
288
289
splay_tree 
290
splay_tree_new_with_allocator (splay_tree_compare_fn compare_fn,
291
                               splay_tree_delete_key_fn delete_key_fn,
292
                               splay_tree_delete_value_fn delete_value_fn,
293
                               splay_tree_allocate_fn allocate_fn,
294
                               splay_tree_deallocate_fn deallocate_fn,
295
                               void *allocate_data)
296
387
{
297
387
  return
298
387
    splay_tree_new_typed_alloc (compare_fn, delete_key_fn, delete_value_fn,
299
387
        allocate_fn, allocate_fn, deallocate_fn,
300
387
        allocate_data);
301
387
}
302
303
/*
304
305
@deftypefn Supplemental splay_tree splay_tree_new_with_typed_alloc @
306
(splay_tree_compare_fn @var{compare_fn}, @
307
splay_tree_delete_key_fn @var{delete_key_fn}, @
308
splay_tree_delete_value_fn @var{delete_value_fn}, @
309
splay_tree_allocate_fn @var{tree_allocate_fn}, @
310
splay_tree_allocate_fn @var{node_allocate_fn}, @
311
splay_tree_deallocate_fn @var{deallocate_fn}, @
312
void * @var{allocate_data})
313
314
This function creates a splay tree that uses two different allocators
315
@var{tree_allocate_fn} and @var{node_allocate_fn} to use for allocating the
316
tree itself and its nodes respectively.  This is useful when variables of
317
different types need to be allocated with different allocators.
318
319
The splay tree will use @var{compare_fn} to compare nodes,
320
@var{delete_key_fn} to deallocate keys, and @var{delete_value_fn} to
321
deallocate values.  Keys and values will be deallocated when the
322
tree is deleted using splay_tree_delete or when a node is removed
323
using splay_tree_remove.  splay_tree_insert will release the previously
324
inserted key and value using @var{delete_key_fn} and @var{delete_value_fn}
325
if the inserted key is already found in the tree.
326
327
@end deftypefn
328
329
*/
330
331
splay_tree
332
splay_tree_new_typed_alloc (splay_tree_compare_fn compare_fn,
333
          splay_tree_delete_key_fn delete_key_fn,
334
          splay_tree_delete_value_fn delete_value_fn,
335
          splay_tree_allocate_fn tree_allocate_fn,
336
          splay_tree_allocate_fn node_allocate_fn,
337
          splay_tree_deallocate_fn deallocate_fn,
338
          void * allocate_data)
339
387
{
340
387
  splay_tree sp = (splay_tree) (*tree_allocate_fn)
341
387
    (sizeof (struct splay_tree_s), allocate_data);
342
343
387
  sp->root = 0;
344
387
  sp->comp = compare_fn;
345
387
  sp->delete_key = delete_key_fn;
346
387
  sp->delete_value = delete_value_fn;
347
387
  sp->allocate = node_allocate_fn;
348
387
  sp->deallocate = deallocate_fn;
349
387
  sp->allocate_data = allocate_data;
350
351
387
  return sp;
352
387
}
353
354
/* Deallocate SP.  */
355
356
void 
357
splay_tree_delete (splay_tree sp)
358
387
{
359
387
  splay_tree_delete_helper (sp, sp->root);
360
387
  (*sp->deallocate) ((char*) sp, sp->allocate_data);
361
387
}
362
363
/* Insert a new node (associating KEY with DATA) into SP.  If a
364
   previous node with the indicated KEY exists, its data is replaced
365
   with the new value.  Returns the new node.  */
366
367
splay_tree_node
368
splay_tree_insert (splay_tree sp, splay_tree_key key, splay_tree_value value)
369
3.53k
{
370
3.53k
  int comparison = 0;
371
372
3.53k
  splay_tree_splay (sp, key);
373
374
3.53k
  if (sp->root)
375
3.14k
    comparison = (*sp->comp)(sp->root->key, key);
376
377
3.53k
  if (sp->root && comparison == 0)
378
0
    {
379
      /* If the root of the tree already has the indicated KEY, delete
380
         the old key and old value, and replace them with KEY and  VALUE.  */
381
0
      if (sp->delete_key)
382
0
  (*sp->delete_key) (sp->root->key);
383
0
      if (sp->delete_value)
384
0
  (*sp->delete_value)(sp->root->value);
385
0
      sp->root->key = key;
386
0
      sp->root->value = value;
387
0
    } 
388
3.53k
  else 
389
3.53k
    {
390
      /* Create a new node, and insert it at the root.  */
391
3.53k
      splay_tree_node node;
392
393
3.53k
      node = ((splay_tree_node)
394
3.53k
        (*sp->allocate) (sizeof (struct splay_tree_node_s),
395
3.53k
             sp->allocate_data));
396
3.53k
      node->key = key;
397
3.53k
      node->value = value;
398
      
399
3.53k
      if (!sp->root)
400
387
  node->left = node->right = 0;
401
3.14k
      else if (comparison < 0)
402
3.14k
  {
403
3.14k
    node->left = sp->root;
404
3.14k
    node->right = node->left->right;
405
3.14k
    node->left->right = 0;
406
3.14k
  }
407
0
      else
408
0
  {
409
0
    node->right = sp->root;
410
0
    node->left = node->right->left;
411
0
    node->right->left = 0;
412
0
  }
413
414
3.53k
      sp->root = node;
415
3.53k
    }
416
417
3.53k
  return sp->root;
418
3.53k
}
419
420
/* Remove KEY from SP.  It is not an error if it did not exist.  */
421
422
void
423
splay_tree_remove (splay_tree sp, splay_tree_key key)
424
0
{
425
0
  splay_tree_splay (sp, key);
426
427
0
  if (sp->root && (*sp->comp) (sp->root->key, key) == 0)
428
0
    {
429
0
      splay_tree_node left, right;
430
431
0
      left = sp->root->left;
432
0
      right = sp->root->right;
433
434
      /* Delete the root node itself.  */
435
0
      if (sp->delete_key)
436
0
  (*sp->delete_key) (sp->root->key);
437
0
      if (sp->delete_value)
438
0
  (*sp->delete_value) (sp->root->value);
439
0
      (*sp->deallocate) (sp->root, sp->allocate_data);
440
441
      /* One of the children is now the root.  Doesn't matter much
442
   which, so long as we preserve the properties of the tree.  */
443
0
      if (left)
444
0
  {
445
0
    sp->root = left;
446
447
    /* If there was a right child as well, hang it off the 
448
       right-most leaf of the left child.  */
449
0
    if (right)
450
0
      {
451
0
        while (left->right)
452
0
    left = left->right;
453
0
        left->right = right;
454
0
      }
455
0
  }
456
0
      else
457
0
  sp->root = right;
458
0
    }
459
0
}
460
461
/* Lookup KEY in SP, returning VALUE if present, and NULL 
462
   otherwise.  */
463
464
splay_tree_node
465
splay_tree_lookup (splay_tree sp, splay_tree_key key)
466
3.53k
{
467
3.53k
  splay_tree_splay (sp, key);
468
469
3.53k
  if (sp->root && (*sp->comp)(sp->root->key, key) == 0)
470
0
    return sp->root;
471
3.53k
  else
472
3.53k
    return 0;
473
3.53k
}
474
475
/* Return the node in SP with the greatest key.  */
476
477
splay_tree_node
478
splay_tree_max (splay_tree sp)
479
0
{
480
0
  splay_tree_node n = sp->root;
481
482
0
  if (!n)
483
0
    return NULL;
484
485
0
  while (n->right)
486
0
    n = n->right;
487
488
0
  return n;
489
0
}
490
491
/* Return the node in SP with the smallest key.  */
492
493
splay_tree_node
494
splay_tree_min (splay_tree sp)
495
0
{
496
0
  splay_tree_node n = sp->root;
497
498
0
  if (!n)
499
0
    return NULL;
500
501
0
  while (n->left)
502
0
    n = n->left;
503
504
0
  return n;
505
0
}
506
507
/* Return the immediate predecessor KEY, or NULL if there is no
508
   predecessor.  KEY need not be present in the tree.  */
509
510
splay_tree_node
511
splay_tree_predecessor (splay_tree sp, splay_tree_key key)
512
0
{
513
0
  int comparison;
514
0
  splay_tree_node node;
515
516
  /* If the tree is empty, there is certainly no predecessor.  */
517
0
  if (!sp->root)
518
0
    return NULL;
519
520
  /* Splay the tree around KEY.  That will leave either the KEY
521
     itself, its predecessor, or its successor at the root.  */
522
0
  splay_tree_splay (sp, key);
523
0
  comparison = (*sp->comp)(sp->root->key, key);
524
525
  /* If the predecessor is at the root, just return it.  */
526
0
  if (comparison < 0)
527
0
    return sp->root;
528
529
  /* Otherwise, find the rightmost element of the left subtree.  */
530
0
  node = sp->root->left;
531
0
  if (node)
532
0
    while (node->right)
533
0
      node = node->right;
534
535
0
  return node;
536
0
}
537
538
/* Return the immediate successor KEY, or NULL if there is no
539
   successor.  KEY need not be present in the tree.  */
540
541
splay_tree_node
542
splay_tree_successor (splay_tree sp, splay_tree_key key)
543
0
{
544
0
  int comparison;
545
0
  splay_tree_node node;
546
547
  /* If the tree is empty, there is certainly no successor.  */
548
0
  if (!sp->root)
549
0
    return NULL;
550
551
  /* Splay the tree around KEY.  That will leave either the KEY
552
     itself, its predecessor, or its successor at the root.  */
553
0
  splay_tree_splay (sp, key);
554
0
  comparison = (*sp->comp)(sp->root->key, key);
555
556
  /* If the successor is at the root, just return it.  */
557
0
  if (comparison > 0)
558
0
    return sp->root;
559
560
  /* Otherwise, find the leftmost element of the right subtree.  */
561
0
  node = sp->root->right;
562
0
  if (node)
563
0
    while (node->left)
564
0
      node = node->left;
565
566
0
  return node;
567
0
}
568
569
/* Call FN, passing it the DATA, for every node in SP, following an
570
   in-order traversal.  If FN every returns a non-zero value, the
571
   iteration ceases immediately, and the value is returned.
572
   Otherwise, this function returns 0.  */
573
574
int
575
splay_tree_foreach (splay_tree sp, splay_tree_foreach_fn fn, void *data)
576
0
{
577
0
  return splay_tree_foreach_helper (sp->root, fn, data);
578
0
}
579
580
/* Splay-tree comparison function, treating the keys as ints.  */
581
582
int
583
splay_tree_compare_ints (splay_tree_key k1, splay_tree_key k2)
584
0
{
585
0
  if ((int) k1 < (int) k2)
586
0
    return -1;
587
0
  else if ((int) k1 > (int) k2)
588
0
    return 1;
589
0
  else 
590
0
    return 0;
591
0
}
592
593
/* Splay-tree comparison function, treating the keys as pointers.  */
594
595
int
596
splay_tree_compare_pointers (splay_tree_key k1, splay_tree_key k2)
597
0
{
598
0
  if ((char*) k1 < (char*) k2)
599
0
    return -1;
600
0
  else if ((char*) k1 > (char*) k2)
601
0
    return 1;
602
0
  else 
603
0
    return 0;
604
0
}
605
606
/* Splay-tree comparison function, treating the keys as strings.  */
607
608
int
609
splay_tree_compare_strings (splay_tree_key k1, splay_tree_key k2)
610
0
{
611
0
  return strcmp ((char *) k1, (char *) k2);
612
0
}
613
614
/* Splay-tree delete function, simply using free.  */
615
616
void
617
splay_tree_delete_pointers (splay_tree_value value)
618
0
{
619
0
  free ((void *) value);
620
0
}