Coverage Report

Created: 2025-06-24 06:45

/src/binutils-gdb/libiberty/splay-tree.c
Line
Count
Source (jump to first uncovered line)
1
/* A splay-tree datatype.  
2
   Copyright (C) 1998-2025 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
1.23k
{
57
1.23k
  splay_tree_node pending = 0;
58
1.23k
  splay_tree_node active = 0;
59
60
1.23k
  if (!node)
61
0
    return;
62
63
9.26k
#define KDEL(x)  if (sp->delete_key) (*sp->delete_key)(x);
64
9.26k
#define VDEL(x)  if (sp->delete_value) (*sp->delete_value)(x);
65
66
1.23k
  KDEL (node->key);
67
1.23k
  VDEL (node->value);
68
69
  /* We use the "key" field to hold the "next" pointer.  */
70
1.23k
  node->key = (splay_tree_key)pending;
71
1.23k
  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
10.4k
  while (pending)
78
9.26k
    {
79
9.26k
      active = pending;
80
9.26k
      pending = 0;
81
18.5k
      while (active)
82
9.26k
  {
83
9.26k
    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
9.26k
    if (active->left)
89
8.03k
      {
90
8.03k
        KDEL (active->left->key);
91
8.03k
        VDEL (active->left->value);
92
8.03k
        active->left->key = (splay_tree_key)pending;
93
8.03k
        pending = (splay_tree_node)(active->left);
94
8.03k
      }
95
9.26k
    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
9.26k
    temp = active;
104
9.26k
    active = (splay_tree_node)(temp->key);
105
9.26k
    (*sp->deallocate) ((char*) temp, sp->allocate_data);
106
9.26k
  }
107
9.26k
    }
108
1.23k
#undef KDEL
109
1.23k
#undef VDEL
110
1.23k
}
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
18.5k
{
143
18.5k
  if (sp->root == 0)
144
2.46k
    return;
145
146
16.0k
  do {
147
16.0k
    int cmp1, cmp2;
148
16.0k
    splay_tree_node n, c;
149
150
16.0k
    n = sp->root;
151
16.0k
    cmp1 = (*sp->comp) (key, n->key);
152
153
    /* Found.  */
154
16.0k
    if (cmp1 == 0)
155
0
      return;
156
157
    /* Left or right?  If no child, then we're done.  */
158
16.0k
    if (cmp1 < 0)
159
0
      c = n->left;
160
16.0k
    else
161
16.0k
      c = n->right;
162
16.0k
    if (!c)
163
16.0k
      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
16.0k
}
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
10.4k
{
259
10.4k
  return (void *) xmalloc (size);
260
10.4k
}
261
262
static void
263
splay_tree_xmalloc_deallocate (void *object, void *data ATTRIBUTE_UNUSED)
264
10.4k
{
265
10.4k
  free (object);
266
10.4k
}
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
1.23k
{
279
1.23k
  return (splay_tree_new_with_allocator
280
1.23k
          (compare_fn, delete_key_fn, delete_value_fn,
281
1.23k
           splay_tree_xmalloc_allocate, splay_tree_xmalloc_deallocate, 0));
282
1.23k
}
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
1.23k
{
297
1.23k
  return
298
1.23k
    splay_tree_new_typed_alloc (compare_fn, delete_key_fn, delete_value_fn,
299
1.23k
        allocate_fn, allocate_fn, deallocate_fn,
300
1.23k
        allocate_data);
301
1.23k
}
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
1.23k
{
340
1.23k
  splay_tree sp = (splay_tree) (*tree_allocate_fn)
341
1.23k
    (sizeof (struct splay_tree_s), allocate_data);
342
343
1.23k
  sp->root = 0;
344
1.23k
  sp->comp = compare_fn;
345
1.23k
  sp->delete_key = delete_key_fn;
346
1.23k
  sp->delete_value = delete_value_fn;
347
1.23k
  sp->allocate = node_allocate_fn;
348
1.23k
  sp->deallocate = deallocate_fn;
349
1.23k
  sp->allocate_data = allocate_data;
350
351
1.23k
  return sp;
352
1.23k
}
353
354
/* Deallocate SP.  */
355
356
void 
357
splay_tree_delete (splay_tree sp)
358
1.23k
{
359
1.23k
  splay_tree_delete_helper (sp, sp->root);
360
1.23k
  (*sp->deallocate) ((char*) sp, sp->allocate_data);
361
1.23k
}
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
9.26k
{
370
9.26k
  int comparison = 0;
371
372
9.26k
  splay_tree_splay (sp, key);
373
374
9.26k
  if (sp->root)
375
8.03k
    comparison = (*sp->comp)(sp->root->key, key);
376
377
9.26k
  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
9.26k
  else 
389
9.26k
    {
390
      /* Create a new node, and insert it at the root.  */
391
9.26k
      splay_tree_node node;
392
393
9.26k
      node = ((splay_tree_node)
394
9.26k
        (*sp->allocate) (sizeof (struct splay_tree_node_s),
395
9.26k
             sp->allocate_data));
396
9.26k
      node->key = key;
397
9.26k
      node->value = value;
398
      
399
9.26k
      if (!sp->root)
400
1.23k
  node->left = node->right = 0;
401
8.03k
      else if (comparison < 0)
402
8.03k
  {
403
8.03k
    node->left = sp->root;
404
8.03k
    node->right = node->left->right;
405
8.03k
    node->left->right = 0;
406
8.03k
  }
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
9.26k
      sp->root = node;
415
9.26k
    }
416
417
9.26k
  return sp->root;
418
9.26k
}
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
9.26k
{
467
9.26k
  splay_tree_splay (sp, key);
468
469
9.26k
  if (sp->root && (*sp->comp)(sp->root->key, key) == 0)
470
0
    return sp->root;
471
9.26k
  else
472
9.26k
    return 0;
473
9.26k
}
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
}