Coverage Report

Created: 2026-03-31 07:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gnutls/gl/gl_anyrbtree_list2.h
Line
Count
Source
1
/* Sequential list data type implemented by a binary tree.
2
   Copyright (C) 2006-2007, 2009-2026 Free Software Foundation, Inc.
3
   Written by Bruno Haible <bruno@clisp.org>, 2006.
4
5
   This file is free software: you can redistribute it and/or modify
6
   it under the terms of the GNU Lesser General Public License as
7
   published by the Free Software Foundation; either version 2.1 of the
8
   License, or (at your option) any later version.
9
10
   This file is distributed in the hope that it will be useful,
11
   but WITHOUT ANY WARRANTY; without even the implied warranty of
12
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
   GNU Lesser General Public License for more details.
14
15
   You should have received a copy of the GNU Lesser General Public License
16
   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
17
18
/* Common code of gl_rbtree_list.c and gl_rbtreehash_list.c.  */
19
20
/* -------------------------- gl_list_t Data Type -------------------------- */
21
22
/* Creates a subtree for count >= 1 elements.
23
   Its black-height bh is passed as argument, with
24
   2^bh - 1 <= count <= 2^(bh+1) - 1.  bh == 0 implies count == 1.
25
   Its height is h where 2^(h-1) <= count <= 2^h - 1.
26
   Return NULL upon out-of-memory.  */
27
static gl_list_node_t
28
create_subtree_with_contents (unsigned int bh,
29
                              size_t count, const void **contents)
30
0
{
31
0
  size_t half1 = (count - 1) / 2;
32
0
  size_t half2 = count / 2;
33
  /* Note: half1 + half2 = count - 1.  */
34
0
  gl_list_node_t node =
35
0
    (struct gl_list_node_impl *) malloc (sizeof (struct gl_list_node_impl));
36
0
  if (node == NULL)
37
0
    return NULL;
38
39
0
  if (half1 > 0)
40
0
    {
41
      /* half1 > 0 implies count > 1, implies bh >= 1, implies
42
           2^(bh-1) - 1 <= half1 <= 2^bh - 1.  */
43
0
      node->left =
44
0
        create_subtree_with_contents (bh - 1, half1, contents);
45
0
      if (node->left == NULL)
46
0
        goto fail1;
47
0
      node->left->parent = node;
48
0
    }
49
0
  else
50
0
    node->left = NULL;
51
52
0
  node->value = contents[half1];
53
54
0
  if (half2 > 0)
55
0
    {
56
      /* half2 > 0 implies count > 1, implies bh >= 1, implies
57
           2^(bh-1) - 1 <= half2 <= 2^bh - 1.  */
58
0
      node->right =
59
0
       create_subtree_with_contents (bh - 1, half2, contents + half1 + 1);
60
0
      if (node->right == NULL)
61
0
        goto fail2;
62
0
      node->right->parent = node;
63
0
    }
64
0
  else
65
0
    node->right = NULL;
66
67
0
  node->color = (bh == 0 ? RED : BLACK);
68
69
0
  node->branch_size = count;
70
71
0
  return node;
72
73
0
 fail2:
74
0
  if (node->left != NULL)
75
0
    free_subtree (node->left);
76
0
 fail1:
77
0
  free (node);
78
0
  return NULL;
79
0
}
80
81
static gl_list_t
82
gl_tree_nx_create (gl_list_implementation_t implementation,
83
                   gl_listelement_equals_fn equals_fn,
84
                   gl_listelement_hashcode_fn hashcode_fn,
85
                   gl_listelement_dispose_fn dispose_fn,
86
                   bool allow_duplicates,
87
                   size_t count, const void **contents)
88
0
{
89
0
  struct gl_list_impl *list =
90
0
    (struct gl_list_impl *) malloc (sizeof (struct gl_list_impl));
91
92
0
  if (list == NULL)
93
0
    return NULL;
94
95
0
  list->base.vtable = implementation;
96
0
  list->base.equals_fn = equals_fn;
97
0
  list->base.hashcode_fn = hashcode_fn;
98
0
  list->base.dispose_fn = dispose_fn;
99
0
  list->base.allow_duplicates = allow_duplicates;
100
#if WITH_HASHTABLE
101
  {
102
    size_t estimate = xsum (count, count / 2); /* 1.5 * count */
103
    if (estimate < 10)
104
      estimate = 10;
105
    list->table_size = next_prime (estimate);
106
    if (size_overflow_p (xtimes (list->table_size, sizeof (gl_hash_entry_t))))
107
      goto fail1;
108
    list->table =
109
      (gl_hash_entry_t *) calloc (list->table_size, sizeof (gl_hash_entry_t));
110
    if (list->table == NULL)
111
      goto fail1;
112
  }
113
#endif
114
0
  if (count > 0)
115
0
    {
116
      /* Assuming 2^bh - 1 <= count <= 2^(bh+1) - 2, we create a tree whose
117
         upper bh levels are black, and only the partially present lowest
118
         level is red.  */
119
0
      unsigned int bh;
120
0
      {
121
0
        size_t n;
122
0
        for (n = count + 1, bh = 0; n > 1; n = n >> 1)
123
0
          bh++;
124
0
      }
125
126
0
      list->root = create_subtree_with_contents (bh, count, contents);
127
0
      if (list->root == NULL)
128
0
        goto fail2;
129
0
      list->root->parent = NULL;
130
131
#if WITH_HASHTABLE
132
      /* Now that the tree is built, node_position() works.  Now we can
133
         add the nodes to the hash table.  */
134
      if (add_nodes_to_buckets (list) < 0)
135
        goto fail3;
136
#endif
137
0
    }
138
0
  else
139
0
    list->root = NULL;
140
141
0
  return list;
142
143
#if WITH_HASHTABLE
144
 fail3:
145
  free_subtree (list->root);
146
#endif
147
0
 fail2:
148
#if WITH_HASHTABLE
149
  free (list->table);
150
 fail1:
151
#endif
152
0
  free (list);
153
0
  return NULL;
154
0
}
155
156
/* Rotates left a subtree.
157
158
                         B                         D
159
                       /   \                     /   \
160
                     A       D       -->       B       E
161
                            / \               / \
162
                           C   E             A   C
163
164
   Changes the tree structure, updates the branch sizes.
165
   The caller must update the colors and register D as child of its parent.  */
166
static gl_list_node_t
167
rotate_left (gl_list_node_t b_node, gl_list_node_t d_node)
168
0
{
169
0
  gl_list_node_t a_node = b_node->left;
170
0
  gl_list_node_t c_node = d_node->left;
171
0
  gl_list_node_t e_node = d_node->right;
172
173
0
  b_node->right = c_node;
174
0
  d_node->left = b_node;
175
176
0
  d_node->parent = b_node->parent;
177
0
  b_node->parent = d_node;
178
0
  if (c_node != NULL)
179
0
    c_node->parent = b_node;
180
181
0
  b_node->branch_size =
182
0
    (a_node != NULL ? a_node->branch_size : 0)
183
0
    + 1 + (c_node != NULL ? c_node->branch_size : 0);
184
0
  d_node->branch_size =
185
0
    b_node->branch_size + 1 + (e_node != NULL ? e_node->branch_size : 0);
186
187
0
  return d_node;
188
0
}
189
190
/* Rotates right a subtree.
191
192
                           D                     B
193
                         /   \                 /   \
194
                       B       E     -->     A       D
195
                      / \                           / \
196
                     A   C                         C   E
197
198
   Changes the tree structure, updates the branch sizes.
199
   The caller must update the colors and register B as child of its parent.  */
200
static gl_list_node_t
201
rotate_right (gl_list_node_t b_node, gl_list_node_t d_node)
202
0
{
203
0
  gl_list_node_t a_node = b_node->left;
204
0
  gl_list_node_t c_node = b_node->right;
205
0
  gl_list_node_t e_node = d_node->right;
206
207
0
  d_node->left = c_node;
208
0
  b_node->right = d_node;
209
210
0
  b_node->parent = d_node->parent;
211
0
  d_node->parent = b_node;
212
0
  if (c_node != NULL)
213
0
    c_node->parent = d_node;
214
215
0
  d_node->branch_size =
216
0
    (c_node != NULL ? c_node->branch_size : 0)
217
0
    + 1 + (e_node != NULL ? e_node->branch_size : 0);
218
0
  b_node->branch_size =
219
0
    (a_node != NULL ? a_node->branch_size : 0) + 1 + d_node->branch_size;
220
221
0
  return b_node;
222
0
}
223
224
/* Ensures the tree is balanced, after an insertion operation.
225
   Also assigns node->color.
226
   parent is the given node's parent, known to be non-NULL.  */
227
static void
228
rebalance_after_add (gl_list_t list, gl_list_node_t node, gl_list_node_t parent)
229
0
{
230
0
  for (;;)
231
0
    {
232
      /* At this point, parent = node->parent != NULL.
233
         Think of node->color being RED (although node->color is not yet
234
         assigned.)  */
235
236
0
      if (parent->color == BLACK)
237
0
        {
238
          /* A RED color for node is acceptable.  */
239
0
          node->color = RED;
240
0
          return;
241
0
        }
242
243
0
      gl_list_node_t grandparent = parent->parent;
244
      /* Since parent is RED, we know that
245
         grandparent is != NULL and colored BLACK.  */
246
247
0
      gl_list_node_t uncle;
248
0
      if (grandparent->left == parent)
249
0
        uncle = grandparent->right;
250
0
      else if (grandparent->right == parent)
251
0
        uncle = grandparent->left;
252
0
      else
253
0
        abort ();
254
255
0
      if (uncle != NULL && uncle->color == RED)
256
0
        {
257
          /* Change grandparent from BLACK to RED, and
258
             change parent and uncle from RED to BLACK.
259
             This makes it acceptable for node to be RED.  */
260
0
          node->color = RED;
261
0
          parent->color = uncle->color = BLACK;
262
0
          node = grandparent;
263
0
        }
264
0
      else
265
0
        {
266
          /* grandparent and uncle are BLACK.  parent is RED.  node wants
267
             to be RED too.
268
             In this case, recoloring is not sufficient.  Need to perform
269
             one or two rotations.  */
270
0
          gl_list_node_t *grandparentp;
271
272
0
          if (grandparent->parent == NULL)
273
0
            grandparentp = &list->root;
274
0
          else if (grandparent->parent->left == grandparent)
275
0
            grandparentp = &grandparent->parent->left;
276
0
          else if (grandparent->parent->right == grandparent)
277
0
            grandparentp = &grandparent->parent->right;
278
0
          else
279
0
            abort ();
280
281
0
          if (grandparent->left == parent)
282
0
            {
283
0
              if (parent->right == node)
284
0
                {
285
                  /* Rotation between node and parent.  */
286
0
                  grandparent->left = rotate_left (parent, node);
287
0
                  node = parent;
288
0
                  parent = grandparent->left;
289
0
                }
290
              /* grandparent and uncle are BLACK.  parent and node want to be
291
                 RED.  parent = grandparent->left.  node = parent->left.
292
293
                      grandparent              parent
294
                         bh+1                   bh+1
295
                         /   \                 /   \
296
                     parent  uncle    -->   node  grandparent
297
                      bh      bh             bh      bh
298
                      / \                           / \
299
                   node  C                         C  uncle
300
                    bh   bh                       bh    bh
301
               */
302
0
              *grandparentp = rotate_right (parent, grandparent);
303
0
              parent->color = BLACK;
304
0
              node->color = grandparent->color = RED;
305
0
            }
306
0
          else /* grandparent->right == parent */
307
0
            {
308
0
              if (parent->left == node)
309
0
                {
310
                  /* Rotation between node and parent.  */
311
0
                  grandparent->right = rotate_right (node, parent);
312
0
                  node = parent;
313
0
                  parent = grandparent->right;
314
0
                }
315
              /* grandparent and uncle are BLACK.  parent and node want to be
316
                 RED.  parent = grandparent->right.  node = parent->right.
317
318
                    grandparent                    parent
319
                       bh+1                         bh+1
320
                       /   \                       /   \
321
                   uncle  parent     -->   grandparent  node
322
                     bh     bh                  bh       bh
323
                            / \                 / \
324
                           C  node          uncle  C
325
                          bh   bh            bh    bh
326
               */
327
0
              *grandparentp = rotate_left (grandparent, parent);
328
0
              parent->color = BLACK;
329
0
              node->color = grandparent->color = RED;
330
0
            }
331
0
          return;
332
0
        }
333
334
      /* Start again with a new (node, parent) pair.  */
335
0
      parent = node->parent;
336
337
0
      if (parent == NULL)
338
0
        {
339
          /* Change node's color from RED to BLACK.  This increases the
340
             tree's black-height.  */
341
0
          node->color = BLACK;
342
0
          return;
343
0
        }
344
0
    }
345
0
}
346
347
/* Ensures the tree is balanced, after a deletion operation.
348
   CHILD was a grandchild of PARENT and is now its child.  Between them,
349
   a black node was removed.  CHILD is also black, or NULL.
350
   (CHILD can also be NULL.  But PARENT is non-NULL.)  */
351
static void
352
rebalance_after_remove (gl_list_t list, gl_list_node_t child, gl_list_node_t parent)
353
0
{
354
0
  for (;;)
355
0
    {
356
      /* At this point, we reduced the black-height of the CHILD subtree by 1.
357
         To make up, either look for a possibility to turn a RED to a BLACK
358
         node, or try to reduce the black-height tree of CHILD's sibling
359
         subtree as well.  */
360
0
      gl_list_node_t *parentp;
361
362
0
      if (parent->parent == NULL)
363
0
        parentp = &list->root;
364
0
      else if (parent->parent->left == parent)
365
0
        parentp = &parent->parent->left;
366
0
      else if (parent->parent->right == parent)
367
0
        parentp = &parent->parent->right;
368
0
      else
369
0
        abort ();
370
371
0
      if (parent->left == child)
372
0
        {
373
0
          gl_list_node_t sibling = parent->right;
374
          /* sibling's black-height is >= 1.  In particular,
375
             sibling != NULL.
376
377
                      parent
378
                       /   \
379
                   child  sibling
380
                     bh    bh+1
381
           */
382
383
0
          if (sibling->color == RED)
384
0
            {
385
              /* sibling is RED, hence parent is BLACK and sibling's children
386
                 are non-NULL and BLACK.
387
388
                      parent                       sibling
389
                       bh+2                         bh+2
390
                       /   \                        /   \
391
                   child  sibling     -->       parent    SR
392
                     bh    bh+1                  bh+1    bh+1
393
                            / \                  / \
394
                          SL   SR            child  SL
395
                         bh+1 bh+1             bh  bh+1
396
               */
397
0
              *parentp = rotate_left (parent, sibling);
398
0
              parent->color = RED;
399
0
              sibling->color = BLACK;
400
401
              /* Concentrate on the subtree of parent.  The new sibling is
402
                 one of the old sibling's children, and known to be BLACK.  */
403
0
              parentp = &sibling->left;
404
0
              sibling = parent->right;
405
0
            }
406
          /* Now we know that sibling is BLACK.
407
408
                      parent
409
                       /   \
410
                   child  sibling
411
                     bh    bh+1
412
           */
413
0
          if (sibling->right != NULL && sibling->right->color == RED)
414
0
            {
415
              /*
416
                      parent                     sibling
417
                     bh+1|bh+2                  bh+1|bh+2
418
                       /   \                      /   \
419
                   child  sibling    -->      parent    SR
420
                     bh    bh+1                bh+1    bh+1
421
                            / \                / \
422
                          SL   SR           child  SL
423
                          bh   bh             bh   bh
424
               */
425
0
              *parentp = rotate_left (parent, sibling);
426
0
              sibling->color = parent->color;
427
0
              parent->color = BLACK;
428
0
              sibling->right->color = BLACK;
429
0
              return;
430
0
            }
431
0
          else if (sibling->left != NULL && sibling->left->color == RED)
432
0
            {
433
              /*
434
                      parent                   parent
435
                     bh+1|bh+2                bh+1|bh+2
436
                       /   \                    /   \
437
                   child  sibling    -->    child    SL
438
                     bh    bh+1               bh    bh+1
439
                            / \                     /  \
440
                          SL   SR                 SLL  sibling
441
                          bh   bh                 bh     bh
442
                         /  \                           /   \
443
                       SLL  SLR                       SLR    SR
444
                       bh    bh                       bh     bh
445
446
                 where SLL, SLR, SR are all black.
447
               */
448
0
              parent->right = rotate_right (sibling->left, sibling);
449
              /* Change sibling from BLACK to RED and SL from RED to BLACK.  */
450
0
              sibling->color = RED;
451
0
              sibling = parent->right;
452
0
              sibling->color = BLACK;
453
454
              /* Now do as in the previous case.  */
455
0
              *parentp = rotate_left (parent, sibling);
456
0
              sibling->color = parent->color;
457
0
              parent->color = BLACK;
458
0
              sibling->right->color = BLACK;
459
0
              return;
460
0
            }
461
0
          else
462
0
            {
463
0
              if (parent->color == BLACK)
464
0
                {
465
                  /* Change sibling from BLACK to RED.  Then the entire
466
                     subtree at parent has decreased its black-height.
467
                              parent                   parent
468
                               bh+2                     bh+1
469
                               /   \                    /   \
470
                           child  sibling    -->    child  sibling
471
                             bh    bh+1               bh     bh
472
                   */
473
0
                  sibling->color = RED;
474
475
0
                  child = parent;
476
0
                }
477
0
              else
478
0
                {
479
                  /* Change parent from RED to BLACK, but compensate by
480
                     changing sibling from BLACK to RED.
481
                              parent                   parent
482
                               bh+1                     bh+1
483
                               /   \                    /   \
484
                           child  sibling    -->    child  sibling
485
                             bh    bh+1               bh     bh
486
                   */
487
0
                  parent->color = BLACK;
488
0
                  sibling->color = RED;
489
0
                  return;
490
0
                }
491
0
            }
492
0
        }
493
0
      else if (parent->right == child)
494
0
        {
495
0
          gl_list_node_t sibling = parent->left;
496
          /* sibling's black-height is >= 1.  In particular,
497
             sibling != NULL.
498
499
                      parent
500
                       /   \
501
                  sibling  child
502
                    bh+1     bh
503
           */
504
505
0
          if (sibling->color == RED)
506
0
            {
507
              /* sibling is RED, hence parent is BLACK and sibling's children
508
                 are non-NULL and BLACK.
509
510
                      parent                 sibling
511
                       bh+2                    bh+2
512
                       /   \                  /   \
513
                  sibling  child    -->     SR    parent
514
                    bh+1     ch            bh+1    bh+1
515
                    / \                            / \
516
                  SL   SR                        SL  child
517
                 bh+1 bh+1                      bh+1   bh
518
               */
519
0
              *parentp = rotate_right (sibling, parent);
520
0
              parent->color = RED;
521
0
              sibling->color = BLACK;
522
523
              /* Concentrate on the subtree of parent.  The new sibling is
524
                 one of the old sibling's children, and known to be BLACK.  */
525
0
              parentp = &sibling->right;
526
0
              sibling = parent->left;
527
0
            }
528
          /* Now we know that sibling is BLACK.
529
530
                      parent
531
                       /   \
532
                  sibling  child
533
                    bh+1     bh
534
           */
535
0
          if (sibling->left != NULL && sibling->left->color == RED)
536
0
            {
537
              /*
538
                       parent                 sibling
539
                      bh+1|bh+2              bh+1|bh+2
540
                        /   \                  /   \
541
                   sibling  child    -->     SL   parent
542
                     bh+1     bh            bh+1   bh+1
543
                     / \                           / \
544
                   SL   SR                       SR  child
545
                   bh   bh                       bh    bh
546
               */
547
0
              *parentp = rotate_right (sibling, parent);
548
0
              sibling->color = parent->color;
549
0
              parent->color = BLACK;
550
0
              sibling->left->color = BLACK;
551
0
              return;
552
0
            }
553
0
          else if (sibling->right != NULL && sibling->right->color == RED)
554
0
            {
555
              /*
556
                      parent                       parent
557
                     bh+1|bh+2                    bh+1|bh+2
558
                       /   \                        /   \
559
                   sibling  child    -->          SR    child
560
                    bh+1      bh                 bh+1     bh
561
                     / \                         /  \
562
                   SL   SR                  sibling  SRR
563
                   bh   bh                    bh      bh
564
                       /  \                  /   \
565
                     SRL  SRR               SL   SRL
566
                     bh    bh               bh    bh
567
568
                 where SL, SRL, SRR are all black.
569
               */
570
0
              parent->left = rotate_left (sibling, sibling->right);
571
              /* Change sibling from BLACK to RED and SL from RED to BLACK.  */
572
0
              sibling->color = RED;
573
0
              sibling = parent->left;
574
0
              sibling->color = BLACK;
575
576
              /* Now do as in the previous case.  */
577
0
              *parentp = rotate_right (sibling, parent);
578
0
              sibling->color = parent->color;
579
0
              parent->color = BLACK;
580
0
              sibling->left->color = BLACK;
581
0
              return;
582
0
            }
583
0
          else
584
0
            {
585
0
              if (parent->color == BLACK)
586
0
                {
587
                  /* Change sibling from BLACK to RED.  Then the entire
588
                     subtree at parent has decreased its black-height.
589
                              parent                   parent
590
                               bh+2                     bh+1
591
                               /   \                    /   \
592
                           sibling  child    -->    sibling  child
593
                            bh+1      bh              bh       bh
594
                   */
595
0
                  sibling->color = RED;
596
597
0
                  child = parent;
598
0
                }
599
0
              else
600
0
                {
601
                  /* Change parent from RED to BLACK, but compensate by
602
                     changing sibling from BLACK to RED.
603
                              parent                   parent
604
                               bh+1                     bh+1
605
                               /   \                    /   \
606
                           sibling  child    -->    sibling  child
607
                            bh+1      bh              bh       bh
608
                   */
609
0
                  parent->color = BLACK;
610
0
                  sibling->color = RED;
611
0
                  return;
612
0
                }
613
0
            }
614
0
        }
615
0
      else
616
0
        abort ();
617
618
      /* Start again with a new (child, parent) pair.  */
619
0
      parent = child->parent;
620
621
#if 0 /* Already handled.  */
622
      if (child != NULL && child->color == RED)
623
        {
624
          child->color = BLACK;
625
          return;
626
        }
627
#endif
628
629
0
      if (parent == NULL)
630
0
        return;
631
0
    }
632
0
}
633
634
static void
635
gl_tree_remove_node_from_tree (gl_list_t list, gl_list_node_t node)
636
0
{
637
0
  gl_list_node_t parent = node->parent;
638
639
0
  if (node->left == NULL)
640
0
    {
641
      /* Replace node with node->right.  */
642
0
      gl_list_node_t child = node->right;
643
644
0
      if (child != NULL)
645
0
        {
646
0
          child->parent = parent;
647
          /* Since node->left == NULL, child must be RED and of height 1,
648
             hence node must have been BLACK.  Recolor the child.  */
649
0
          child->color = BLACK;
650
0
        }
651
0
      if (parent == NULL)
652
0
        list->root = child;
653
0
      else
654
0
        {
655
0
          if (parent->left == node)
656
0
            parent->left = child;
657
0
          else /* parent->right == node */
658
0
            parent->right = child;
659
660
          /* Update branch_size fields of the parent nodes.  */
661
0
          for (gl_list_node_t p = parent; p != NULL; p = p->parent)
662
0
            p->branch_size--;
663
664
0
          if (child == NULL && node->color == BLACK)
665
0
            rebalance_after_remove (list, child, parent);
666
0
        }
667
0
    }
668
0
  else if (node->right == NULL)
669
0
    {
670
      /* It is not absolutely necessary to treat this case.  But the more
671
         general case below is more complicated, hence slower.  */
672
      /* Replace node with node->left.  */
673
0
      gl_list_node_t child = node->left;
674
675
0
      child->parent = parent;
676
      /* Since node->right == NULL, child must be RED and of height 1,
677
         hence node must have been BLACK.  Recolor the child.  */
678
0
      child->color = BLACK;
679
0
      if (parent == NULL)
680
0
        list->root = child;
681
0
      else
682
0
        {
683
0
          if (parent->left == node)
684
0
            parent->left = child;
685
0
          else /* parent->right == node */
686
0
            parent->right = child;
687
688
          /* Update branch_size fields of the parent nodes.  */
689
0
          for (gl_list_node_t p = parent; p != NULL; p = p->parent)
690
0
            p->branch_size--;
691
0
        }
692
0
    }
693
0
  else
694
0
    {
695
      /* Replace node with the rightmost element of the node->left subtree.  */
696
697
0
      gl_list_node_t subst;
698
0
      for (subst = node->left; subst->right != NULL; )
699
0
        subst = subst->right;
700
701
0
      gl_list_node_t subst_parent = subst->parent;
702
703
0
      gl_list_node_t child = subst->left;
704
705
0
      color_t removed_color = subst->color;
706
707
      /* The case subst_parent == node is special:  If we do nothing special,
708
         we get confusion about node->left, subst->left and child->parent.
709
           subst_parent == node
710
           <==> The 'for' loop above terminated immediately.
711
           <==> subst == subst_parent->left
712
                [otherwise subst == subst_parent->right]
713
         In this case, we would need to first set
714
           child->parent = node; node->left = child;
715
         and later - when we copy subst into node's position - again
716
           child->parent = subst; subst->left = child;
717
         Altogether a no-op.  */
718
0
      if (subst_parent != node)
719
0
        {
720
0
          if (child != NULL)
721
0
            child->parent = subst_parent;
722
0
          subst_parent->right = child;
723
0
        }
724
725
      /* Update branch_size fields of the parent nodes.  */
726
0
      for (gl_list_node_t p = subst_parent; p != NULL; p = p->parent)
727
0
        p->branch_size--;
728
729
      /* Copy subst into node's position.
730
         (This is safer than to copy subst's value into node, keep node in
731
         place, and free subst.)  */
732
0
      if (subst_parent != node)
733
0
        {
734
0
          subst->left = node->left;
735
0
          subst->left->parent = subst;
736
0
        }
737
0
      subst->right = node->right;
738
0
      subst->right->parent = subst;
739
0
      subst->color = node->color;
740
0
      subst->branch_size = node->branch_size;
741
0
      subst->parent = parent;
742
0
      if (parent == NULL)
743
0
        list->root = subst;
744
0
      else if (parent->left == node)
745
0
        parent->left = subst;
746
0
      else /* parent->right == node */
747
0
        parent->right = subst;
748
749
0
      if (removed_color == BLACK)
750
0
        {
751
0
          if (child != NULL && child->color == RED)
752
            /* Recolor the child.  */
753
0
            child->color = BLACK;
754
0
          else
755
            /* Rebalancing starts at child's parent, that is subst_parent -
756
               except when subst_parent == node.  In this case, we need to use
757
               its replacement, subst.  */
758
0
            rebalance_after_remove (list, child,
759
0
                                    subst_parent != node ? subst_parent : subst);
760
0
        }
761
0
    }
762
0
}
763
764
static gl_list_node_t
765
gl_tree_nx_add_first (gl_list_t list, const void *elt)
766
0
{
767
  /* Create new node.  */
768
0
  gl_list_node_t new_node =
769
0
    (struct gl_list_node_impl *) malloc (sizeof (struct gl_list_node_impl));
770
771
0
  if (new_node == NULL)
772
0
    return NULL;
773
774
0
  new_node->left = NULL;
775
0
  new_node->right = NULL;
776
0
  new_node->branch_size = 1;
777
0
  new_node->value = elt;
778
#if WITH_HASHTABLE
779
  new_node->h.hashcode =
780
    (list->base.hashcode_fn != NULL
781
     ? list->base.hashcode_fn (new_node->value)
782
     : (size_t)(uintptr_t) new_node->value);
783
#endif
784
785
  /* Add it to the tree.  */
786
0
  if (list->root == NULL)
787
0
    {
788
0
      new_node->color = BLACK;
789
0
      list->root = new_node;
790
0
      new_node->parent = NULL;
791
0
    }
792
0
  else
793
0
    {
794
0
      gl_list_node_t node;
795
0
      for (node = list->root; node->left != NULL; )
796
0
        node = node->left;
797
798
0
      node->left = new_node;
799
0
      new_node->parent = node;
800
801
      /* Update branch_size fields of the parent nodes.  */
802
0
      for (gl_list_node_t p = node; p != NULL; p = p->parent)
803
0
        p->branch_size++;
804
805
      /* Color and rebalance.  */
806
0
      rebalance_after_add (list, new_node, node);
807
0
    }
808
809
#if WITH_HASHTABLE
810
  /* Add node to the hash table.
811
     Note that this is only possible _after_ the node has been added to the
812
     tree structure, because add_to_bucket() uses node_position().  */
813
  if (add_to_bucket (list, new_node) < 0)
814
    {
815
      gl_tree_remove_node_from_tree (list, new_node);
816
      free (new_node);
817
      return NULL;
818
    }
819
  hash_resize_after_add (list);
820
#endif
821
822
0
  return new_node;
823
0
}
824
825
static gl_list_node_t
826
gl_tree_nx_add_last (gl_list_t list, const void *elt)
827
0
{
828
  /* Create new node.  */
829
0
  gl_list_node_t new_node =
830
0
    (struct gl_list_node_impl *) malloc (sizeof (struct gl_list_node_impl));
831
832
0
  if (new_node == NULL)
833
0
    return NULL;
834
835
0
  new_node->left = NULL;
836
0
  new_node->right = NULL;
837
0
  new_node->branch_size = 1;
838
0
  new_node->value = elt;
839
#if WITH_HASHTABLE
840
  new_node->h.hashcode =
841
    (list->base.hashcode_fn != NULL
842
     ? list->base.hashcode_fn (new_node->value)
843
     : (size_t)(uintptr_t) new_node->value);
844
#endif
845
846
  /* Add it to the tree.  */
847
0
  if (list->root == NULL)
848
0
    {
849
0
      new_node->color = BLACK;
850
0
      list->root = new_node;
851
0
      new_node->parent = NULL;
852
0
    }
853
0
  else
854
0
    {
855
0
      gl_list_node_t node;
856
0
      for (node = list->root; node->right != NULL; )
857
0
        node = node->right;
858
859
0
      node->right = new_node;
860
0
      new_node->parent = node;
861
862
      /* Update branch_size fields of the parent nodes.  */
863
0
      for (gl_list_node_t p = node; p != NULL; p = p->parent)
864
0
        p->branch_size++;
865
866
      /* Color and rebalance.  */
867
0
      rebalance_after_add (list, new_node, node);
868
0
    }
869
870
#if WITH_HASHTABLE
871
  /* Add node to the hash table.
872
     Note that this is only possible _after_ the node has been added to the
873
     tree structure, because add_to_bucket() uses node_position().  */
874
  if (add_to_bucket (list, new_node) < 0)
875
    {
876
      gl_tree_remove_node_from_tree (list, new_node);
877
      free (new_node);
878
      return NULL;
879
    }
880
  hash_resize_after_add (list);
881
#endif
882
883
0
  return new_node;
884
0
}
885
886
static gl_list_node_t
887
gl_tree_nx_add_before (gl_list_t list, gl_list_node_t node, const void *elt)
888
0
{
889
  /* Create new node.  */
890
0
  gl_list_node_t new_node =
891
0
    (struct gl_list_node_impl *) malloc (sizeof (struct gl_list_node_impl));
892
893
0
  if (new_node == NULL)
894
0
    return NULL;
895
896
0
  new_node->left = NULL;
897
0
  new_node->right = NULL;
898
0
  new_node->branch_size = 1;
899
0
  new_node->value = elt;
900
#if WITH_HASHTABLE
901
  new_node->h.hashcode =
902
    (list->base.hashcode_fn != NULL
903
     ? list->base.hashcode_fn (new_node->value)
904
     : (size_t)(uintptr_t) new_node->value);
905
#endif
906
907
  /* Add it to the tree.  */
908
0
  if (node->left == NULL)
909
0
    node->left = new_node;
910
0
  else
911
0
    {
912
0
      for (node = node->left; node->right != NULL; )
913
0
        node = node->right;
914
0
      node->right = new_node;
915
0
    }
916
0
  new_node->parent = node;
917
918
  /* Update branch_size fields of the parent nodes.  */
919
0
  for (gl_list_node_t p = node; p != NULL; p = p->parent)
920
0
    p->branch_size++;
921
922
  /* Color and rebalance.  */
923
0
  rebalance_after_add (list, new_node, node);
924
925
#if WITH_HASHTABLE
926
  /* Add node to the hash table.
927
     Note that this is only possible _after_ the node has been added to the
928
     tree structure, because add_to_bucket() uses node_position().  */
929
  if (add_to_bucket (list, new_node) < 0)
930
    {
931
      gl_tree_remove_node_from_tree (list, new_node);
932
      free (new_node);
933
      return NULL;
934
    }
935
  hash_resize_after_add (list);
936
#endif
937
938
0
  return new_node;
939
0
}
940
941
static gl_list_node_t
942
gl_tree_nx_add_after (gl_list_t list, gl_list_node_t node, const void *elt)
943
0
{
944
  /* Create new node.  */
945
0
  gl_list_node_t new_node =
946
0
    (struct gl_list_node_impl *) malloc (sizeof (struct gl_list_node_impl));
947
948
0
  if (new_node == NULL)
949
0
    return NULL;
950
951
0
  new_node->left = NULL;
952
0
  new_node->right = NULL;
953
0
  new_node->branch_size = 1;
954
0
  new_node->value = elt;
955
#if WITH_HASHTABLE
956
  new_node->h.hashcode =
957
    (list->base.hashcode_fn != NULL
958
     ? list->base.hashcode_fn (new_node->value)
959
     : (size_t)(uintptr_t) new_node->value);
960
#endif
961
962
  /* Add it to the tree.  */
963
0
  if (node->right == NULL)
964
0
    node->right = new_node;
965
0
  else
966
0
    {
967
0
      for (node = node->right; node->left != NULL; )
968
0
        node = node->left;
969
0
      node->left = new_node;
970
0
    }
971
0
  new_node->parent = node;
972
973
  /* Update branch_size fields of the parent nodes.  */
974
0
  for (gl_list_node_t p = node; p != NULL; p = p->parent)
975
0
    p->branch_size++;
976
977
  /* Color and rebalance.  */
978
0
  rebalance_after_add (list, new_node, node);
979
980
#if WITH_HASHTABLE
981
  /* Add node to the hash table.
982
     Note that this is only possible _after_ the node has been added to the
983
     tree structure, because add_to_bucket() uses node_position().  */
984
  if (add_to_bucket (list, new_node) < 0)
985
    {
986
      gl_tree_remove_node_from_tree (list, new_node);
987
      free (new_node);
988
      return NULL;
989
    }
990
  hash_resize_after_add (list);
991
#endif
992
993
0
  return new_node;
994
0
}