Coverage Report

Created: 2025-08-26 06:31

/src/irssi/subprojects/glib-2.74.3/glib/gtree.c
Line
Count
Source (jump to first uncovered line)
1
/* GLIB - Library of useful routines for C programming
2
 * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
3
 *
4
 * SPDX-License-Identifier: LGPL-2.1-or-later
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Lesser General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2.1 of the License, or (at your option) any later version.
10
 *
11
 * This library is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18
 */
19
20
/*
21
 * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
22
 * file for a list of people on the GLib Team.  See the ChangeLog
23
 * files for a list of changes.  These files are distributed with
24
 * GLib at ftp://ftp.gtk.org/pub/gtk/. 
25
 */
26
27
/* 
28
 * MT safe
29
 */
30
31
#include "config.h"
32
33
#include "gtree.h"
34
35
#include "gatomic.h"
36
#include "gtestutils.h"
37
#include "gslice.h"
38
39
/**
40
 * SECTION:trees-binary
41
 * @title: Balanced Binary Trees
42
 * @short_description: a sorted collection of key/value pairs optimized
43
 *                     for searching and traversing in order
44
 *
45
 * The #GTree structure and its associated functions provide a sorted
46
 * collection of key/value pairs optimized for searching and traversing
47
 * in order. This means that most of the operations  (access, search,
48
 * insertion, deletion, ...) on #GTree are O(log(n)) in average and O(n)
49
 * in worst case for time complexity. But, note that maintaining a
50
 * balanced sorted #GTree of n elements is done in time O(n log(n)).
51
 *
52
 * To create a new #GTree use g_tree_new().
53
 *
54
 * To insert a key/value pair into a #GTree use g_tree_insert()
55
 * (O(n log(n))).
56
 *
57
 * To remove a key/value pair use g_tree_remove() (O(n log(n))).
58
 *
59
 * To look up the value corresponding to a given key, use
60
 * g_tree_lookup() and g_tree_lookup_extended().
61
 *
62
 * To find out the number of nodes in a #GTree, use g_tree_nnodes(). To
63
 * get the height of a #GTree, use g_tree_height().
64
 *
65
 * To traverse a #GTree, calling a function for each node visited in
66
 * the traversal, use g_tree_foreach().
67
 *
68
 * To destroy a #GTree, use g_tree_destroy().
69
 **/
70
71
#define MAX_GTREE_HEIGHT 40
72
73
/**
74
 * GTree:
75
 *
76
 * The GTree struct is an opaque data structure representing a
77
 * [balanced binary tree][glib-Balanced-Binary-Trees]. It should be
78
 * accessed only by using the following functions.
79
 */
80
struct _GTree
81
{
82
  GTreeNode        *root;
83
  GCompareDataFunc  key_compare;
84
  GDestroyNotify    key_destroy_func;
85
  GDestroyNotify    value_destroy_func;
86
  gpointer          key_compare_data;
87
  guint             nnodes;
88
  gint              ref_count;
89
};
90
91
struct _GTreeNode
92
{
93
  gpointer   key;         /* key for this node */
94
  gpointer   value;       /* value stored at this node */
95
  GTreeNode *left;        /* left subtree */
96
  GTreeNode *right;       /* right subtree */
97
  gint8      balance;     /* height (right) - height (left) */
98
  guint8     left_child;
99
  guint8     right_child;
100
};
101
102
103
static GTreeNode* g_tree_node_new                   (gpointer       key,
104
                                                     gpointer       value);
105
static GTreeNode *g_tree_insert_internal (GTree *tree,
106
                                          gpointer key,
107
                                          gpointer value,
108
                                          gboolean replace);
109
static gboolean   g_tree_remove_internal            (GTree         *tree,
110
                                                     gconstpointer  key,
111
                                                     gboolean       steal);
112
static GTreeNode* g_tree_node_balance               (GTreeNode     *node);
113
static GTreeNode *g_tree_find_node                  (GTree         *tree,
114
                                                     gconstpointer  key);
115
static gint       g_tree_node_pre_order             (GTreeNode     *node,
116
                                                     GTraverseFunc  traverse_func,
117
                                                     gpointer       data);
118
static gint       g_tree_node_in_order              (GTreeNode     *node,
119
                                                     GTraverseFunc  traverse_func,
120
                                                     gpointer       data);
121
static gint       g_tree_node_post_order            (GTreeNode     *node,
122
                                                     GTraverseFunc  traverse_func,
123
                                                     gpointer       data);
124
static GTreeNode *g_tree_node_search (GTreeNode *node,
125
                                      GCompareFunc search_func,
126
                                      gconstpointer data);
127
static GTreeNode* g_tree_node_rotate_left           (GTreeNode     *node);
128
static GTreeNode* g_tree_node_rotate_right          (GTreeNode     *node);
129
#ifdef G_TREE_DEBUG
130
static void       g_tree_node_check                 (GTreeNode     *node);
131
#endif
132
133
134
static GTreeNode*
135
g_tree_node_new (gpointer key,
136
                 gpointer value)
137
1.46M
{
138
1.46M
  GTreeNode *node = g_slice_new (GTreeNode);
139
140
1.46M
  node->balance = 0;
141
1.46M
  node->left = NULL;
142
1.46M
  node->right = NULL;
143
1.46M
  node->left_child = FALSE;
144
1.46M
  node->right_child = FALSE;
145
1.46M
  node->key = key;
146
1.46M
  node->value = value;
147
148
1.46M
  return node;
149
1.46M
}
150
151
/**
152
 * g_tree_new:
153
 * @key_compare_func: the function used to order the nodes in the #GTree.
154
 *   It should return values similar to the standard strcmp() function -
155
 *   0 if the two arguments are equal, a negative value if the first argument 
156
 *   comes before the second, or a positive value if the first argument comes 
157
 *   after the second.
158
 * 
159
 * Creates a new #GTree.
160
 * 
161
 * Returns: a newly allocated #GTree
162
 */
163
GTree *
164
g_tree_new (GCompareFunc key_compare_func)
165
8
{
166
8
  g_return_val_if_fail (key_compare_func != NULL, NULL);
167
168
8
  return g_tree_new_full ((GCompareDataFunc) key_compare_func, NULL,
169
8
                          NULL, NULL);
170
8
}
171
172
/**
173
 * g_tree_new_with_data:
174
 * @key_compare_func: qsort()-style comparison function
175
 * @key_compare_data: data to pass to comparison function
176
 * 
177
 * Creates a new #GTree with a comparison function that accepts user data.
178
 * See g_tree_new() for more details.
179
 * 
180
 * Returns: a newly allocated #GTree
181
 */
182
GTree *
183
g_tree_new_with_data (GCompareDataFunc key_compare_func,
184
                      gpointer         key_compare_data)
185
0
{
186
0
  g_return_val_if_fail (key_compare_func != NULL, NULL);
187
  
188
0
  return g_tree_new_full (key_compare_func, key_compare_data, 
189
0
                          NULL, NULL);
190
0
}
191
192
/**
193
 * g_tree_new_full:
194
 * @key_compare_func: qsort()-style comparison function
195
 * @key_compare_data: data to pass to comparison function
196
 * @key_destroy_func: a function to free the memory allocated for the key 
197
 *   used when removing the entry from the #GTree or %NULL if you don't
198
 *   want to supply such a function
199
 * @value_destroy_func: a function to free the memory allocated for the 
200
 *   value used when removing the entry from the #GTree or %NULL if you 
201
 *   don't want to supply such a function
202
 * 
203
 * Creates a new #GTree like g_tree_new() and allows to specify functions 
204
 * to free the memory allocated for the key and value that get called when 
205
 * removing the entry from the #GTree.
206
 * 
207
 * Returns: a newly allocated #GTree
208
 */
209
GTree *
210
g_tree_new_full (GCompareDataFunc key_compare_func,
211
                 gpointer         key_compare_data,
212
                 GDestroyNotify   key_destroy_func,
213
                 GDestroyNotify   value_destroy_func)
214
1.04M
{
215
1.04M
  GTree *tree;
216
  
217
1.04M
  g_return_val_if_fail (key_compare_func != NULL, NULL);
218
  
219
1.04M
  tree = g_slice_new (GTree);
220
1.04M
  tree->root               = NULL;
221
1.04M
  tree->key_compare        = key_compare_func;
222
1.04M
  tree->key_destroy_func   = key_destroy_func;
223
1.04M
  tree->value_destroy_func = value_destroy_func;
224
1.04M
  tree->key_compare_data   = key_compare_data;
225
1.04M
  tree->nnodes             = 0;
226
1.04M
  tree->ref_count          = 1;
227
  
228
1.04M
  return tree;
229
1.04M
}
230
231
/**
232
 * g_tree_node_first:
233
 * @tree: a #GTree
234
 *
235
 * Returns the first in-order node of the tree, or %NULL
236
 * for an empty tree.
237
 *
238
 * Returns: (nullable) (transfer none): the first node in the tree
239
 *
240
 * Since: 2.68
241
 */
242
GTreeNode *
243
g_tree_node_first (GTree *tree)
244
1.04M
{
245
1.04M
  GTreeNode *tmp;
246
247
1.04M
  g_return_val_if_fail (tree != NULL, NULL);
248
249
1.04M
  if (!tree->root)
250
1.04M
    return NULL;
251
252
0
  tmp = tree->root;
253
254
0
  while (tmp->left_child)
255
0
    tmp = tmp->left;
256
257
0
  return tmp;
258
1.04M
}
259
260
/**
261
 * g_tree_node_last:
262
 * @tree: a #GTree
263
 *
264
 * Returns the last in-order node of the tree, or %NULL
265
 * for an empty tree.
266
 *
267
 * Returns: (nullable) (transfer none): the last node in the tree
268
 *
269
 * Since: 2.68
270
 */
271
GTreeNode *
272
g_tree_node_last (GTree *tree)
273
0
{
274
0
  GTreeNode *tmp;
275
276
0
  g_return_val_if_fail (tree != NULL, NULL);
277
278
0
  if (!tree->root)
279
0
    return NULL;
280
281
0
  tmp = tree->root;
282
283
0
  while (tmp->right_child)
284
0
    tmp = tmp->right;
285
286
0
  return tmp;
287
0
}
288
289
/**
290
 * g_tree_node_previous
291
 * @node: a #GTree node
292
 *
293
 * Returns the previous in-order node of the tree, or %NULL
294
 * if the passed node was already the first one.
295
 *
296
 * Returns: (nullable) (transfer none): the previous node in the tree
297
 *
298
 * Since: 2.68
299
 */
300
GTreeNode *
301
g_tree_node_previous (GTreeNode *node)
302
13.7k
{
303
13.7k
  GTreeNode *tmp;
304
305
13.7k
  g_return_val_if_fail (node != NULL, NULL);
306
307
13.7k
  tmp = node->left;
308
309
13.7k
  if (node->left_child)
310
13.7k
    while (tmp->right_child)
311
0
      tmp = tmp->right;
312
313
13.7k
  return tmp;
314
13.7k
}
315
316
/**
317
 * g_tree_node_next
318
 * @node: a #GTree node
319
 *
320
 * Returns the next in-order node of the tree, or %NULL
321
 * if the passed node was already the last one.
322
 *
323
 * Returns: (nullable) (transfer none): the next node in the tree
324
 *
325
 * Since: 2.68
326
 */
327
GTreeNode *
328
g_tree_node_next (GTreeNode *node)
329
38.6k
{
330
38.6k
  GTreeNode *tmp;
331
332
38.6k
  g_return_val_if_fail (node != NULL, NULL);
333
334
38.6k
  tmp = node->right;
335
336
38.6k
  if (node->right_child)
337
38.6k
    while (tmp->left_child)
338
0
      tmp = tmp->left;
339
340
38.6k
  return tmp;
341
38.6k
}
342
343
/**
344
 * g_tree_remove_all:
345
 * @tree: a #GTree
346
 *
347
 * Removes all nodes from a #GTree and destroys their keys and values,
348
 * then resets the #GTree’s root to %NULL.
349
 *
350
 * Since: 2.70
351
 */
352
void
353
g_tree_remove_all (GTree *tree)
354
1.04M
{
355
1.04M
  GTreeNode *node;
356
1.04M
  GTreeNode *next;
357
358
1.04M
  g_return_if_fail (tree != NULL);
359
360
1.04M
  node = g_tree_node_first (tree);
361
362
1.04M
  while (node)
363
0
    {
364
0
      next = g_tree_node_next (node);
365
366
0
      if (tree->key_destroy_func)
367
0
        tree->key_destroy_func (node->key);
368
0
      if (tree->value_destroy_func)
369
0
        tree->value_destroy_func (node->value);
370
0
      g_slice_free (GTreeNode, node);
371
372
#ifdef G_TREE_DEBUG
373
      g_assert (tree->nnodes > 0);
374
      tree->nnodes--;
375
#endif
376
377
0
      node = next;
378
0
    }
379
380
#ifdef G_TREE_DEBUG
381
  g_assert (tree->nnodes == 0);
382
#endif
383
384
1.04M
  tree->root = NULL;
385
1.04M
#ifndef G_TREE_DEBUG
386
1.04M
  tree->nnodes = 0;
387
1.04M
#endif
388
1.04M
}
389
390
/**
391
 * g_tree_ref:
392
 * @tree: a #GTree
393
 *
394
 * Increments the reference count of @tree by one.
395
 *
396
 * It is safe to call this function from any thread.
397
 *
398
 * Returns: the passed in #GTree
399
 *
400
 * Since: 2.22
401
 */
402
GTree *
403
g_tree_ref (GTree *tree)
404
1.16M
{
405
1.16M
  g_return_val_if_fail (tree != NULL, NULL);
406
407
1.16M
  g_atomic_int_inc (&tree->ref_count);
408
409
1.16M
  return tree;
410
1.16M
}
411
412
/**
413
 * g_tree_unref:
414
 * @tree: a #GTree
415
 *
416
 * Decrements the reference count of @tree by one.
417
 * If the reference count drops to 0, all keys and values will
418
 * be destroyed (if destroy functions were specified) and all
419
 * memory allocated by @tree will be released.
420
 *
421
 * It is safe to call this function from any thread.
422
 *
423
 * Since: 2.22
424
 */
425
void
426
g_tree_unref (GTree *tree)
427
2.21M
{
428
2.21M
  g_return_if_fail (tree != NULL);
429
430
2.21M
  if (g_atomic_int_dec_and_test (&tree->ref_count))
431
1.04M
    {
432
1.04M
      g_tree_remove_all (tree);
433
1.04M
      g_slice_free (GTree, tree);
434
1.04M
    }
435
2.21M
}
436
437
/**
438
 * g_tree_destroy:
439
 * @tree: a #GTree
440
 * 
441
 * Removes all keys and values from the #GTree and decreases its
442
 * reference count by one. If keys and/or values are dynamically
443
 * allocated, you should either free them first or create the #GTree
444
 * using g_tree_new_full(). In the latter case the destroy functions
445
 * you supplied will be called on all keys and values before destroying
446
 * the #GTree.
447
 */
448
void
449
g_tree_destroy (GTree *tree)
450
0
{
451
0
  g_return_if_fail (tree != NULL);
452
453
0
  g_tree_remove_all (tree);
454
0
  g_tree_unref (tree);
455
0
}
456
457
/**
458
 * g_tree_insert_node:
459
 * @tree: a #GTree
460
 * @key: the key to insert
461
 * @value: the value corresponding to the key
462
 * 
463
 * Inserts a key/value pair into a #GTree.
464
 *
465
 * If the given key already exists in the #GTree its corresponding value
466
 * is set to the new value. If you supplied a @value_destroy_func when
467
 * creating the #GTree, the old value is freed using that function. If
468
 * you supplied a @key_destroy_func when creating the #GTree, the passed
469
 * key is freed using that function.
470
 *
471
 * The tree is automatically 'balanced' as new key/value pairs are added,
472
 * so that the distance from the root to every leaf is as small as possible.
473
 * The cost of maintaining a balanced tree while inserting new key/value
474
 * result in a O(n log(n)) operation where most of the other operations
475
 * are O(log(n)).
476
 *
477
 * Returns: (transfer none): the inserted (or set) node.
478
 *
479
 * Since: 2.68
480
 */
481
GTreeNode *
482
g_tree_insert_node (GTree    *tree,
483
                    gpointer  key,
484
                    gpointer  value)
485
1.46M
{
486
1.46M
  GTreeNode *node;
487
488
1.46M
  g_return_val_if_fail (tree != NULL, NULL);
489
490
1.46M
  node = g_tree_insert_internal (tree, key, value, FALSE);
491
492
#ifdef G_TREE_DEBUG
493
  g_tree_node_check (tree->root);
494
#endif
495
496
1.46M
  return node;
497
1.46M
}
498
499
/**
500
 * g_tree_insert:
501
 * @tree: a #GTree
502
 * @key: the key to insert
503
 * @value: the value corresponding to the key
504
 * 
505
 * Inserts a key/value pair into a #GTree.
506
 *
507
 * Inserts a new key and value into a #GTree as g_tree_insert_node() does,
508
 * only this function does not return the inserted or set node.
509
 */
510
void
511
g_tree_insert (GTree    *tree,
512
               gpointer  key,
513
               gpointer  value)
514
1.46M
{
515
1.46M
  g_tree_insert_node (tree, key, value);
516
1.46M
}
517
518
/**
519
 * g_tree_replace_node:
520
 * @tree: a #GTree
521
 * @key: the key to insert
522
 * @value: the value corresponding to the key
523
 *
524
 * Inserts a new key and value into a #GTree similar to g_tree_insert_node().
525
 * The difference is that if the key already exists in the #GTree, it gets 
526
 * replaced by the new key. If you supplied a @value_destroy_func when 
527
 * creating the #GTree, the old value is freed using that function. If you 
528
 * supplied a @key_destroy_func when creating the #GTree, the old key is 
529
 * freed using that function. 
530
 *
531
 * The tree is automatically 'balanced' as new key/value pairs are added,
532
 * so that the distance from the root to every leaf is as small as possible.
533
 *
534
 * Returns: (transfer none): the inserted (or set) node.
535
 *
536
 * Since: 2.68
537
 */
538
GTreeNode *
539
g_tree_replace_node (GTree    *tree,
540
                     gpointer  key,
541
                     gpointer  value)
542
0
{
543
0
  GTreeNode *node;
544
545
0
  g_return_val_if_fail (tree != NULL, NULL);
546
547
0
  node = g_tree_insert_internal (tree, key, value, TRUE);
548
549
#ifdef G_TREE_DEBUG
550
  g_tree_node_check (tree->root);
551
#endif
552
553
0
  return node;
554
0
}
555
556
/**
557
 * g_tree_replace:
558
 * @tree: a #GTree
559
 * @key: the key to insert
560
 * @value: the value corresponding to the key
561
 *
562
 * Inserts a new key and value into a #GTree as g_tree_replace_node() does,
563
 * only this function does not return the inserted or set node.
564
 */
565
void
566
g_tree_replace (GTree    *tree,
567
                gpointer  key,
568
                gpointer  value)
569
0
{
570
0
  g_tree_replace_node (tree, key, value);
571
0
}
572
573
/* internal insert routine */
574
static GTreeNode *
575
g_tree_insert_internal (GTree    *tree,
576
                        gpointer  key,
577
                        gpointer  value,
578
                        gboolean  replace)
579
1.46M
{
580
1.46M
  GTreeNode *node, *retnode;
581
1.46M
  GTreeNode *path[MAX_GTREE_HEIGHT];
582
1.46M
  int idx;
583
584
1.46M
  g_return_val_if_fail (tree != NULL, NULL);
585
586
1.46M
  if (!tree->root)
587
868k
    {
588
868k
      tree->root = g_tree_node_new (key, value);
589
868k
      tree->nnodes++;
590
868k
      return tree->root;
591
868k
    }
592
593
599k
  idx = 0;
594
599k
  path[idx++] = NULL;
595
599k
  node = tree->root;
596
597
983k
  while (1)
598
983k
    {
599
983k
      int cmp = tree->key_compare (key, node->key, tree->key_compare_data);
600
      
601
983k
      if (cmp == 0)
602
0
        {
603
0
          if (tree->value_destroy_func)
604
0
            tree->value_destroy_func (node->value);
605
606
0
          node->value = value;
607
608
0
          if (replace)
609
0
            {
610
0
              if (tree->key_destroy_func)
611
0
                tree->key_destroy_func (node->key);
612
613
0
              node->key = key;
614
0
            }
615
0
          else
616
0
            {
617
              /* free the passed key */
618
0
              if (tree->key_destroy_func)
619
0
                tree->key_destroy_func (key);
620
0
            }
621
622
0
          return node;
623
0
        }
624
983k
      else if (cmp < 0)
625
570k
        {
626
570k
          if (node->left_child)
627
237k
            {
628
237k
              path[idx++] = node;
629
237k
              node = node->left;
630
237k
            }
631
332k
          else
632
332k
            {
633
332k
              GTreeNode *child = g_tree_node_new (key, value);
634
635
332k
              child->left = node->left;
636
332k
              child->right = node;
637
332k
              node->left = child;
638
332k
              node->left_child = TRUE;
639
332k
              node->balance -= 1;
640
641
332k
              tree->nnodes++;
642
643
332k
              retnode = child;
644
332k
              break;
645
332k
            }
646
570k
        }
647
413k
      else
648
413k
        {
649
413k
          if (node->right_child)
650
147k
            {
651
147k
              path[idx++] = node;
652
147k
              node = node->right;
653
147k
            }
654
266k
          else
655
266k
            {
656
266k
              GTreeNode *child = g_tree_node_new (key, value);
657
658
266k
              child->right = node->right;
659
266k
              child->left = node;
660
266k
              node->right = child;
661
266k
              node->right_child = TRUE;
662
266k
              node->balance += 1;
663
664
266k
              tree->nnodes++;
665
666
266k
              retnode = child;
667
266k
              break;
668
266k
            }
669
413k
        }
670
983k
    }
671
672
  /* Restore balance. This is the goodness of a non-recursive
673
   * implementation, when we are done with balancing we 'break'
674
   * the loop and we are done.
675
   */
676
908k
  while (1)
677
908k
    {
678
908k
      GTreeNode *bparent = path[--idx];
679
908k
      gboolean left_node = (bparent && node == bparent->left);
680
908k
      g_assert (!bparent || bparent->left == node || bparent->right == node);
681
682
908k
      if (node->balance < -1 || node->balance > 1)
683
163k
        {
684
163k
          node = g_tree_node_balance (node);
685
163k
          if (bparent == NULL)
686
104k
            tree->root = node;
687
58.4k
          else if (left_node)
688
35.5k
            bparent->left = node;
689
22.9k
          else
690
22.9k
            bparent->right = node;
691
163k
        }
692
693
908k
      if (node->balance == 0 || bparent == NULL)
694
599k
        break;
695
      
696
309k
      if (left_node)
697
192k
        bparent->balance -= 1;
698
116k
      else
699
116k
        bparent->balance += 1;
700
701
309k
      node = bparent;
702
309k
    }
703
704
599k
  return retnode;
705
599k
}
706
707
/**
708
 * g_tree_remove:
709
 * @tree: a #GTree
710
 * @key: the key to remove
711
 * 
712
 * Removes a key/value pair from a #GTree.
713
 *
714
 * If the #GTree was created using g_tree_new_full(), the key and value 
715
 * are freed using the supplied destroy functions, otherwise you have to 
716
 * make sure that any dynamically allocated values are freed yourself.
717
 * If the key does not exist in the #GTree, the function does nothing.
718
 *
719
 * The cost of maintaining a balanced tree while removing a key/value
720
 * result in a O(n log(n)) operation where most of the other operations
721
 * are O(log(n)).
722
 *
723
 * Returns: %TRUE if the key was found (prior to 2.8, this function
724
 *     returned nothing)
725
 */
726
gboolean
727
g_tree_remove (GTree         *tree,
728
               gconstpointer  key)
729
1.46M
{
730
1.46M
  gboolean removed;
731
732
1.46M
  g_return_val_if_fail (tree != NULL, FALSE);
733
734
1.46M
  removed = g_tree_remove_internal (tree, key, FALSE);
735
736
#ifdef G_TREE_DEBUG
737
  g_tree_node_check (tree->root);
738
#endif
739
740
1.46M
  return removed;
741
1.46M
}
742
743
/**
744
 * g_tree_steal:
745
 * @tree: a #GTree
746
 * @key: the key to remove
747
 * 
748
 * Removes a key and its associated value from a #GTree without calling 
749
 * the key and value destroy functions.
750
 *
751
 * If the key does not exist in the #GTree, the function does nothing.
752
 *
753
 * Returns: %TRUE if the key was found (prior to 2.8, this function
754
 *     returned nothing)
755
 */
756
gboolean
757
g_tree_steal (GTree         *tree,
758
              gconstpointer  key)
759
0
{
760
0
  gboolean removed;
761
762
0
  g_return_val_if_fail (tree != NULL, FALSE);
763
764
0
  removed = g_tree_remove_internal (tree, key, TRUE);
765
766
#ifdef G_TREE_DEBUG
767
  g_tree_node_check (tree->root);
768
#endif
769
770
0
  return removed;
771
0
}
772
773
/* internal remove routine */
774
static gboolean
775
g_tree_remove_internal (GTree         *tree,
776
                        gconstpointer  key,
777
                        gboolean       steal)
778
1.46M
{
779
1.46M
  GTreeNode *node, *parent, *balance;
780
1.46M
  GTreeNode *path[MAX_GTREE_HEIGHT];
781
1.46M
  int idx;
782
1.46M
  gboolean left_node;
783
784
1.46M
  g_return_val_if_fail (tree != NULL, FALSE);
785
786
1.46M
  if (!tree->root)
787
0
    return FALSE;
788
789
1.46M
  idx = 0;
790
1.46M
  path[idx++] = NULL;
791
1.46M
  node = tree->root;
792
793
2.09M
  while (1)
794
2.09M
    {
795
2.09M
      int cmp = tree->key_compare (key, node->key, tree->key_compare_data);
796
797
2.09M
      if (cmp == 0)
798
1.46M
        break;
799
631k
      else if (cmp < 0)
800
346k
        {
801
346k
          if (!node->left_child)
802
0
            return FALSE;
803
804
346k
          path[idx++] = node;
805
346k
          node = node->left;
806
346k
        }
807
284k
      else
808
284k
        {
809
284k
          if (!node->right_child)
810
0
            return FALSE;
811
812
284k
          path[idx++] = node;
813
284k
          node = node->right;
814
284k
        }
815
2.09M
    }
816
817
  /* The following code is almost equal to g_tree_remove_node,
818
   * except that we do not have to call g_tree_node_parent.
819
   */
820
1.46M
  balance = parent = path[--idx];
821
1.46M
  g_assert (!parent || parent->left == node || parent->right == node);
822
1.46M
  left_node = (parent && node == parent->left);
823
824
1.46M
  if (!node->left_child)
825
1.37M
    {
826
1.37M
      if (!node->right_child)
827
1.33M
        {
828
1.33M
          if (!parent)
829
868k
            tree->root = NULL;
830
467k
          else if (left_node)
831
252k
            {
832
252k
              parent->left_child = FALSE;
833
252k
              parent->left = node->left;
834
252k
              parent->balance += 1;
835
252k
            }
836
214k
          else
837
214k
            {
838
214k
              parent->right_child = FALSE;
839
214k
              parent->right = node->right;
840
214k
              parent->balance -= 1;
841
214k
            }
842
1.33M
        }
843
38.6k
      else /* node has a right child */
844
38.6k
        {
845
38.6k
          GTreeNode *tmp = g_tree_node_next (node);
846
38.6k
          tmp->left = node->left;
847
848
38.6k
          if (!parent)
849
24.7k
            tree->root = node->right;
850
13.9k
          else if (left_node)
851
4.82k
            {
852
4.82k
              parent->left = node->right;
853
4.82k
              parent->balance += 1;
854
4.82k
            }
855
9.14k
          else
856
9.14k
            {
857
9.14k
              parent->right = node->right;
858
9.14k
              parent->balance -= 1;
859
9.14k
            }
860
38.6k
        }
861
1.37M
    }
862
93.1k
  else /* node has a left child */
863
93.1k
    {
864
93.1k
      if (!node->right_child)
865
13.7k
        {
866
13.7k
          GTreeNode *tmp = g_tree_node_previous (node);
867
13.7k
          tmp->right = node->right;
868
869
13.7k
          if (parent == NULL)
870
2.89k
            tree->root = node->left;
871
10.8k
          else if (left_node)
872
10.2k
            {
873
10.2k
              parent->left = node->left;
874
10.2k
              parent->balance += 1;
875
10.2k
            }
876
536
          else
877
536
            {
878
536
              parent->right = node->left;
879
536
              parent->balance -= 1;
880
536
            }
881
13.7k
        }
882
79.4k
      else /* node has a both children (pant, pant!) */
883
79.4k
        {
884
79.4k
          GTreeNode *prev = node->left;
885
79.4k
          GTreeNode *next = node->right;
886
79.4k
          GTreeNode *nextp = node;
887
79.4k
          int old_idx = idx + 1;
888
79.4k
          idx++;
889
890
          /* path[idx] == parent */
891
          /* find the immediately next node (and its parent) */
892
99.2k
          while (next->left_child)
893
19.8k
            {
894
19.8k
              path[++idx] = nextp = next;
895
19.8k
              next = next->left;
896
19.8k
            }
897
898
79.4k
          path[old_idx] = next;
899
79.4k
          balance = path[idx];
900
901
          /* remove 'next' from the tree */
902
79.4k
          if (nextp != node)
903
16.4k
            {
904
16.4k
              if (next->right_child)
905
1.78k
                nextp->left = next->right;
906
14.6k
              else
907
14.6k
                nextp->left_child = FALSE;
908
16.4k
              nextp->balance += 1;
909
910
16.4k
              next->right_child = TRUE;
911
16.4k
              next->right = node->right;
912
16.4k
            }
913
63.0k
          else
914
63.0k
            node->balance -= 1;
915
916
          /* set the prev to point to the right place */
917
82.0k
          while (prev->right_child)
918
2.63k
            prev = prev->right;
919
79.4k
          prev->right = next;
920
921
          /* prepare 'next' to replace 'node' */
922
79.4k
          next->left_child = TRUE;
923
79.4k
          next->left = node->left;
924
79.4k
          next->balance = node->balance;
925
926
79.4k
          if (!parent)
927
65.7k
            tree->root = next;
928
13.6k
          else if (left_node)
929
12.8k
            parent->left = next;
930
876
          else
931
876
            parent->right = next;
932
79.4k
        }
933
93.1k
    }
934
935
  /* restore balance */
936
1.46M
  if (balance)
937
662k
    while (1)
938
662k
      {
939
662k
        GTreeNode *bparent = path[--idx];
940
662k
        g_assert (!bparent || bparent->left == balance || bparent->right == balance);
941
662k
        left_node = (bparent && balance == bparent->left);
942
943
662k
        if(balance->balance < -1 || balance->balance > 1)
944
14.8k
          {
945
14.8k
            balance = g_tree_node_balance (balance);
946
14.8k
            if (!bparent)
947
5.52k
              tree->root = balance;
948
9.30k
            else if (left_node)
949
3.20k
              bparent->left = balance;
950
6.10k
            else
951
6.10k
              bparent->right = balance;
952
14.8k
          }
953
954
662k
        if (balance->balance != 0 || !bparent)
955
571k
          break;
956
957
90.7k
        if (left_node)
958
44.5k
          bparent->balance += 1;
959
46.1k
        else
960
46.1k
          bparent->balance -= 1;
961
962
90.7k
        balance = bparent;
963
90.7k
      }
964
965
1.46M
  if (!steal)
966
1.46M
    {
967
1.46M
      if (tree->key_destroy_func)
968
1.46M
        tree->key_destroy_func (node->key);
969
1.46M
      if (tree->value_destroy_func)
970
0
        tree->value_destroy_func (node->value);
971
1.46M
    }
972
973
1.46M
  g_slice_free (GTreeNode, node);
974
975
1.46M
  tree->nnodes--;
976
977
1.46M
  return TRUE;
978
1.46M
}
979
980
/**
981
 * g_tree_node_key:
982
 * @node: a #GTree node
983
 *
984
 * Gets the key stored at a particular tree node.
985
 *
986
 * Returns: (nullable) (transfer none): the key at the node.
987
 *
988
 * Since: 2.68
989
 */
990
gpointer
991
g_tree_node_key (GTreeNode *node)
992
0
{
993
0
  g_return_val_if_fail (node != NULL, NULL);
994
995
0
  return node->key;
996
0
}
997
998
/**
999
 * g_tree_node_value:
1000
 * @node: a #GTree node
1001
 *
1002
 * Gets the value stored at a particular tree node.
1003
 *
1004
 * Returns: (nullable) (transfer none): the value at the node.
1005
 *
1006
 * Since: 2.68
1007
 */
1008
gpointer
1009
g_tree_node_value (GTreeNode *node)
1010
0
{
1011
0
  g_return_val_if_fail (node != NULL, NULL);
1012
1013
0
  return node->value;
1014
0
}
1015
1016
/**
1017
 * g_tree_lookup_node:
1018
 * @tree: a #GTree
1019
 * @key: the key to look up
1020
 *
1021
 * Gets the tree node corresponding to the given key. Since a #GTree is
1022
 * automatically balanced as key/value pairs are added, key lookup
1023
 * is O(log n) (where n is the number of key/value pairs in the tree).
1024
 *
1025
 * Returns: (nullable) (transfer none): the tree node corresponding to
1026
 *          the key, or %NULL if the key was not found
1027
 *
1028
 * Since: 2.68
1029
 */
1030
GTreeNode *
1031
g_tree_lookup_node (GTree         *tree,
1032
                    gconstpointer  key)
1033
1.50M
{
1034
1.50M
  g_return_val_if_fail (tree != NULL, NULL);
1035
1036
1.50M
  return g_tree_find_node (tree, key);
1037
1.50M
}
1038
1039
/**
1040
 * g_tree_lookup:
1041
 * @tree: a #GTree
1042
 * @key: the key to look up
1043
 * 
1044
 * Gets the value corresponding to the given key. Since a #GTree is 
1045
 * automatically balanced as key/value pairs are added, key lookup
1046
 * is O(log n) (where n is the number of key/value pairs in the tree).
1047
 *
1048
 * Returns: the value corresponding to the key, or %NULL
1049
 *     if the key was not found
1050
 */
1051
gpointer
1052
g_tree_lookup (GTree         *tree,
1053
               gconstpointer  key)
1054
1.50M
{
1055
1.50M
  GTreeNode *node;
1056
1057
1.50M
  node = g_tree_lookup_node (tree, key);
1058
1059
1.50M
  return node ? node->value : NULL;
1060
1.50M
}
1061
1062
/**
1063
 * g_tree_lookup_extended:
1064
 * @tree: a #GTree
1065
 * @lookup_key: the key to look up
1066
 * @orig_key: (out) (optional) (nullable): returns the original key
1067
 * @value: (out) (optional) (nullable): returns the value associated with the key
1068
 * 
1069
 * Looks up a key in the #GTree, returning the original key and the
1070
 * associated value. This is useful if you need to free the memory
1071
 * allocated for the original key, for example before calling
1072
 * g_tree_remove().
1073
 * 
1074
 * Returns: %TRUE if the key was found in the #GTree
1075
 */
1076
gboolean
1077
g_tree_lookup_extended (GTree         *tree,
1078
                        gconstpointer  lookup_key,
1079
                        gpointer      *orig_key,
1080
                        gpointer      *value)
1081
0
{
1082
0
  GTreeNode *node;
1083
  
1084
0
  g_return_val_if_fail (tree != NULL, FALSE);
1085
  
1086
0
  node = g_tree_find_node (tree, lookup_key);
1087
  
1088
0
  if (node)
1089
0
    {
1090
0
      if (orig_key)
1091
0
        *orig_key = node->key;
1092
0
      if (value)
1093
0
        *value = node->value;
1094
0
      return TRUE;
1095
0
    }
1096
0
  else
1097
0
    return FALSE;
1098
0
}
1099
1100
/**
1101
 * g_tree_foreach:
1102
 * @tree: a #GTree
1103
 * @func: the function to call for each node visited.
1104
 *     If this function returns %TRUE, the traversal is stopped.
1105
 * @user_data: user data to pass to the function
1106
 *
1107
 * Calls the given function for each of the key/value pairs in the #GTree.
1108
 * The function is passed the key and value of each pair, and the given
1109
 * @data parameter. The tree is traversed in sorted order.
1110
 *
1111
 * The tree may not be modified while iterating over it (you can't 
1112
 * add/remove items). To remove all items matching a predicate, you need 
1113
 * to add each item to a list in your #GTraverseFunc as you walk over 
1114
 * the tree, then walk the list and remove each item.
1115
 */
1116
void
1117
g_tree_foreach (GTree         *tree,
1118
                GTraverseFunc  func,
1119
                gpointer       user_data)
1120
0
{
1121
0
  GTreeNode *node;
1122
1123
0
  g_return_if_fail (tree != NULL);
1124
  
1125
0
  if (!tree->root)
1126
0
    return;
1127
1128
0
  node = g_tree_node_first (tree);
1129
1130
0
  while (node)
1131
0
    {
1132
0
      if ((*func) (node->key, node->value, user_data))
1133
0
        break;
1134
      
1135
0
      node = g_tree_node_next (node);
1136
0
    }
1137
0
}
1138
1139
/**
1140
 * g_tree_foreach_node:
1141
 * @tree: a #GTree
1142
 * @func: the function to call for each node visited.
1143
 *     If this function returns %TRUE, the traversal is stopped.
1144
 * @user_data: user data to pass to the function
1145
 *
1146
 * Calls the given function for each of the nodes in the #GTree.
1147
 * The function is passed the pointer to the particular node, and the given
1148
 * @data parameter. The tree traversal happens in-order.
1149
 *
1150
 * The tree may not be modified while iterating over it (you can't
1151
 * add/remove items). To remove all items matching a predicate, you need
1152
 * to add each item to a list in your #GTraverseFunc as you walk over
1153
 * the tree, then walk the list and remove each item.
1154
 *
1155
 * Since: 2.68
1156
 */
1157
void
1158
g_tree_foreach_node (GTree             *tree,
1159
                     GTraverseNodeFunc  func,
1160
                     gpointer           user_data)
1161
0
{
1162
0
  GTreeNode *node;
1163
1164
0
  g_return_if_fail (tree != NULL);
1165
1166
0
  if (!tree->root)
1167
0
    return;
1168
1169
0
  node = g_tree_node_first (tree);
1170
1171
0
  while (node)
1172
0
    {
1173
0
      if ((*func) (node, user_data))
1174
0
        break;
1175
1176
0
      node = g_tree_node_next (node);
1177
0
    }
1178
0
}
1179
1180
/**
1181
 * g_tree_traverse:
1182
 * @tree: a #GTree
1183
 * @traverse_func: the function to call for each node visited. If this 
1184
 *   function returns %TRUE, the traversal is stopped.
1185
 * @traverse_type: the order in which nodes are visited, one of %G_IN_ORDER,
1186
 *   %G_PRE_ORDER and %G_POST_ORDER
1187
 * @user_data: user data to pass to the function
1188
 * 
1189
 * Calls the given function for each node in the #GTree. 
1190
 *
1191
 * Deprecated:2.2: The order of a balanced tree is somewhat arbitrary.
1192
 *     If you just want to visit all nodes in sorted order, use
1193
 *     g_tree_foreach() instead. If you really need to visit nodes in
1194
 *     a different order, consider using an [n-ary tree][glib-N-ary-Trees].
1195
 */
1196
/**
1197
 * GTraverseFunc:
1198
 * @key: a key of a #GTree node
1199
 * @value: the value corresponding to the key
1200
 * @user_data: user data passed to g_tree_traverse()
1201
 *
1202
 * Specifies the type of function passed to g_tree_traverse(). It is
1203
 * passed the key and value of each node, together with the @user_data
1204
 * parameter passed to g_tree_traverse(). If the function returns
1205
 * %TRUE, the traversal is stopped.
1206
 *
1207
 * Returns: %TRUE to stop the traversal
1208
 */
1209
void
1210
g_tree_traverse (GTree         *tree,
1211
                 GTraverseFunc  traverse_func,
1212
                 GTraverseType  traverse_type,
1213
                 gpointer       user_data)
1214
0
{
1215
0
  g_return_if_fail (tree != NULL);
1216
1217
0
  if (!tree->root)
1218
0
    return;
1219
1220
0
  switch (traverse_type)
1221
0
    {
1222
0
    case G_PRE_ORDER:
1223
0
      g_tree_node_pre_order (tree->root, traverse_func, user_data);
1224
0
      break;
1225
1226
0
    case G_IN_ORDER:
1227
0
      g_tree_node_in_order (tree->root, traverse_func, user_data);
1228
0
      break;
1229
1230
0
    case G_POST_ORDER:
1231
0
      g_tree_node_post_order (tree->root, traverse_func, user_data);
1232
0
      break;
1233
    
1234
0
    case G_LEVEL_ORDER:
1235
0
      g_warning ("g_tree_traverse(): traverse type G_LEVEL_ORDER isn't implemented.");
1236
0
      break;
1237
0
    }
1238
0
}
1239
1240
/**
1241
 * g_tree_search_node:
1242
 * @tree: a #GTree
1243
 * @search_func: a function used to search the #GTree
1244
 * @user_data: the data passed as the second argument to @search_func
1245
 *
1246
 * Searches a #GTree using @search_func.
1247
 *
1248
 * The @search_func is called with a pointer to the key of a key/value
1249
 * pair in the tree, and the passed in @user_data. If @search_func returns
1250
 * 0 for a key/value pair, then the corresponding node is returned as
1251
 * the result of g_tree_search(). If @search_func returns -1, searching
1252
 * will proceed among the key/value pairs that have a smaller key; if
1253
 * @search_func returns 1, searching will proceed among the key/value
1254
 * pairs that have a larger key.
1255
 *
1256
 * Returns: (nullable) (transfer none): the node corresponding to the
1257
 *          found key, or %NULL if the key was not found
1258
 *
1259
 * Since: 2.68
1260
 */
1261
GTreeNode *
1262
g_tree_search_node (GTree         *tree,
1263
                    GCompareFunc   search_func,
1264
                    gconstpointer  user_data)
1265
0
{
1266
0
  g_return_val_if_fail (tree != NULL, NULL);
1267
1268
0
  if (!tree->root)
1269
0
    return NULL;
1270
1271
0
  return g_tree_node_search (tree->root, search_func, user_data);
1272
0
}
1273
1274
/**
1275
 * g_tree_search:
1276
 * @tree: a #GTree
1277
 * @search_func: a function used to search the #GTree
1278
 * @user_data: the data passed as the second argument to @search_func
1279
 *
1280
 * Searches a #GTree using @search_func.
1281
 *
1282
 * The @search_func is called with a pointer to the key of a key/value
1283
 * pair in the tree, and the passed in @user_data. If @search_func returns
1284
 * 0 for a key/value pair, then the corresponding value is returned as
1285
 * the result of g_tree_search(). If @search_func returns -1, searching
1286
 * will proceed among the key/value pairs that have a smaller key; if
1287
 * @search_func returns 1, searching will proceed among the key/value
1288
 * pairs that have a larger key.
1289
 *
1290
 * Returns: the value corresponding to the found key, or %NULL
1291
 *     if the key was not found
1292
 */
1293
gpointer
1294
g_tree_search (GTree         *tree,
1295
               GCompareFunc   search_func,
1296
               gconstpointer  user_data)
1297
0
{
1298
0
  GTreeNode *node;
1299
1300
0
  node = g_tree_search_node (tree, search_func, user_data);
1301
1302
0
  return node ? node->value : NULL;
1303
0
}
1304
1305
/**
1306
 * g_tree_lower_bound:
1307
 * @tree: a #GTree
1308
 * @key: the key to calculate the lower bound for
1309
 *
1310
 * Gets the lower bound node corresponding to the given key,
1311
 * or %NULL if the tree is empty or all the nodes in the tree
1312
 * have keys that are strictly lower than the searched key.
1313
 *
1314
 * The lower bound is the first node that has its key greater
1315
 * than or equal to the searched key.
1316
 *
1317
 * Returns: (nullable) (transfer none): the tree node corresponding to
1318
 *          the lower bound, or %NULL if the tree is empty or has only
1319
 *          keys strictly lower than the searched key.
1320
 *
1321
 * Since: 2.68
1322
 */
1323
GTreeNode *
1324
g_tree_lower_bound (GTree         *tree,
1325
                    gconstpointer  key)
1326
0
{
1327
0
  GTreeNode *node, *result;
1328
0
  gint cmp;
1329
1330
0
  g_return_val_if_fail (tree != NULL, NULL);
1331
1332
0
  node = tree->root;
1333
0
  if (!node)
1334
0
    return NULL;
1335
1336
0
  result = NULL;
1337
0
  while (1)
1338
0
    {
1339
0
      cmp = tree->key_compare (key, node->key, tree->key_compare_data);
1340
0
      if (cmp <= 0)
1341
0
        {
1342
0
          result = node;
1343
1344
0
          if (!node->left_child)
1345
0
            return result;
1346
1347
0
          node = node->left;
1348
0
        }
1349
0
      else
1350
0
        {
1351
0
          if (!node->right_child)
1352
0
            return result;
1353
1354
0
          node = node->right;
1355
0
        }
1356
0
    }
1357
0
}
1358
1359
/**
1360
 * g_tree_upper_bound:
1361
 * @tree: a #GTree
1362
 * @key: the key to calculate the upper bound for
1363
 *
1364
 * Gets the upper bound node corresponding to the given key,
1365
 * or %NULL if the tree is empty or all the nodes in the tree
1366
 * have keys that are lower than or equal to the searched key.
1367
 *
1368
 * The upper bound is the first node that has its key strictly greater
1369
 * than the searched key.
1370
 *
1371
 * Returns: (nullable) (transfer none): the tree node corresponding to the
1372
 *          upper bound, or %NULL if the tree is empty or has only keys
1373
 *          lower than or equal to the searched key.
1374
 *
1375
 * Since: 2.68
1376
 */
1377
GTreeNode *
1378
g_tree_upper_bound (GTree         *tree,
1379
                    gconstpointer  key)
1380
0
{
1381
0
  GTreeNode *node, *result;
1382
0
  gint cmp;
1383
1384
0
  g_return_val_if_fail (tree != NULL, NULL);
1385
1386
0
  node = tree->root;
1387
0
  if (!node)
1388
0
    return NULL;
1389
1390
0
  result = NULL;
1391
0
  while (1)
1392
0
    {
1393
0
      cmp = tree->key_compare (key, node->key, tree->key_compare_data);
1394
0
      if (cmp < 0)
1395
0
        {
1396
0
          result = node;
1397
1398
0
          if (!node->left_child)
1399
0
            return result;
1400
1401
0
          node = node->left;
1402
0
        }
1403
0
      else
1404
0
        {
1405
0
          if (!node->right_child)
1406
0
            return result;
1407
1408
0
          node = node->right;
1409
0
        }
1410
0
    }
1411
0
}
1412
1413
/**
1414
 * g_tree_height:
1415
 * @tree: a #GTree
1416
 * 
1417
 * Gets the height of a #GTree.
1418
 *
1419
 * If the #GTree contains no nodes, the height is 0.
1420
 * If the #GTree contains only one root node the height is 1.
1421
 * If the root node has children the height is 2, etc.
1422
 * 
1423
 * Returns: the height of @tree
1424
 */
1425
gint
1426
g_tree_height (GTree *tree)
1427
0
{
1428
0
  GTreeNode *node;
1429
0
  gint height;
1430
1431
0
  g_return_val_if_fail (tree != NULL, 0);
1432
1433
0
  if (!tree->root)
1434
0
    return 0;
1435
1436
0
  height = 0;
1437
0
  node = tree->root;
1438
1439
0
  while (1)
1440
0
    {
1441
0
      height += 1 + MAX(node->balance, 0);
1442
1443
0
      if (!node->left_child)
1444
0
        return height;
1445
      
1446
0
      node = node->left;
1447
0
    }
1448
0
}
1449
1450
/**
1451
 * g_tree_nnodes:
1452
 * @tree: a #GTree
1453
 * 
1454
 * Gets the number of nodes in a #GTree.
1455
 * 
1456
 * Returns: the number of nodes in @tree
1457
 */
1458
gint
1459
g_tree_nnodes (GTree *tree)
1460
0
{
1461
0
  g_return_val_if_fail (tree != NULL, 0);
1462
1463
0
  return tree->nnodes;
1464
0
}
1465
1466
static GTreeNode *
1467
g_tree_node_balance (GTreeNode *node)
1468
177k
{
1469
177k
  if (node->balance < -1)
1470
125k
    {
1471
125k
      if (node->left->balance > 0)
1472
49.3k
        node->left = g_tree_node_rotate_left (node->left);
1473
125k
      node = g_tree_node_rotate_right (node);
1474
125k
    }
1475
52.0k
  else if (node->balance > 1)
1476
52.0k
    {
1477
52.0k
      if (node->right->balance < 0)
1478
17.7k
        node->right = g_tree_node_rotate_right (node->right);
1479
52.0k
      node = g_tree_node_rotate_left (node);
1480
52.0k
    }
1481
1482
177k
  return node;
1483
177k
}
1484
1485
static GTreeNode *
1486
g_tree_find_node (GTree        *tree,
1487
                  gconstpointer key)
1488
1.50M
{
1489
1.50M
  GTreeNode *node;
1490
1.50M
  gint cmp;
1491
1492
1.50M
  node = tree->root;
1493
1.50M
  if (!node)
1494
868k
    return NULL;
1495
1496
1.04M
  while (1)
1497
1.04M
    {
1498
1.04M
      cmp = tree->key_compare (key, node->key, tree->key_compare_data);
1499
1.04M
      if (cmp == 0)
1500
37.0k
        return node;
1501
1.00M
      else if (cmp < 0)
1502
592k
        {
1503
592k
          if (!node->left_child)
1504
332k
            return NULL;
1505
1506
259k
          node = node->left;
1507
259k
        }
1508
417k
      else
1509
417k
        {
1510
417k
          if (!node->right_child)
1511
266k
            return NULL;
1512
1513
151k
          node = node->right;
1514
151k
        }
1515
1.04M
    }
1516
636k
}
1517
1518
static gint
1519
g_tree_node_pre_order (GTreeNode     *node,
1520
                       GTraverseFunc  traverse_func,
1521
                       gpointer       data)
1522
0
{
1523
0
  if ((*traverse_func) (node->key, node->value, data))
1524
0
    return TRUE;
1525
1526
0
  if (node->left_child)
1527
0
    {
1528
0
      if (g_tree_node_pre_order (node->left, traverse_func, data))
1529
0
        return TRUE;
1530
0
    }
1531
1532
0
  if (node->right_child)
1533
0
    {
1534
0
      if (g_tree_node_pre_order (node->right, traverse_func, data))
1535
0
        return TRUE;
1536
0
    }
1537
1538
0
  return FALSE;
1539
0
}
1540
1541
static gint
1542
g_tree_node_in_order (GTreeNode     *node,
1543
                      GTraverseFunc  traverse_func,
1544
                      gpointer       data)
1545
0
{
1546
0
  if (node->left_child)
1547
0
    {
1548
0
      if (g_tree_node_in_order (node->left, traverse_func, data))
1549
0
        return TRUE;
1550
0
    }
1551
1552
0
  if ((*traverse_func) (node->key, node->value, data))
1553
0
    return TRUE;
1554
1555
0
  if (node->right_child)
1556
0
    {
1557
0
      if (g_tree_node_in_order (node->right, traverse_func, data))
1558
0
        return TRUE;
1559
0
    }
1560
  
1561
0
  return FALSE;
1562
0
}
1563
1564
static gint
1565
g_tree_node_post_order (GTreeNode     *node,
1566
                        GTraverseFunc  traverse_func,
1567
                        gpointer       data)
1568
0
{
1569
0
  if (node->left_child)
1570
0
    {
1571
0
      if (g_tree_node_post_order (node->left, traverse_func, data))
1572
0
        return TRUE;
1573
0
    }
1574
1575
0
  if (node->right_child)
1576
0
    {
1577
0
      if (g_tree_node_post_order (node->right, traverse_func, data))
1578
0
        return TRUE;
1579
0
    }
1580
1581
0
  if ((*traverse_func) (node->key, node->value, data))
1582
0
    return TRUE;
1583
1584
0
  return FALSE;
1585
0
}
1586
1587
static GTreeNode *
1588
g_tree_node_search (GTreeNode     *node,
1589
                    GCompareFunc   search_func,
1590
                    gconstpointer  data)
1591
0
{
1592
0
  gint dir;
1593
1594
0
  if (!node)
1595
0
    return NULL;
1596
1597
0
  while (1) 
1598
0
    {
1599
0
      dir = (* search_func) (node->key, data);
1600
0
      if (dir == 0)
1601
0
        return node;
1602
0
      else if (dir < 0) 
1603
0
        {
1604
0
          if (!node->left_child)
1605
0
            return NULL;
1606
1607
0
          node = node->left;
1608
0
        }
1609
0
      else
1610
0
        {
1611
0
          if (!node->right_child)
1612
0
            return NULL;
1613
1614
0
          node = node->right;
1615
0
        }
1616
0
    }
1617
0
}
1618
1619
static GTreeNode *
1620
g_tree_node_rotate_left (GTreeNode *node)
1621
101k
{
1622
101k
  GTreeNode *right;
1623
101k
  gint a_bal;
1624
101k
  gint b_bal;
1625
1626
101k
  right = node->right;
1627
1628
101k
  if (right->left_child)
1629
20.6k
    node->right = right->left;
1630
80.6k
  else
1631
80.6k
    {
1632
80.6k
      node->right_child = FALSE;
1633
80.6k
      right->left_child = TRUE;
1634
80.6k
    }
1635
101k
  right->left = node;
1636
1637
101k
  a_bal = node->balance;
1638
101k
  b_bal = right->balance;
1639
1640
101k
  if (b_bal <= 0)
1641
49.5k
    {
1642
49.5k
      if (a_bal >= 1)
1643
49.5k
        right->balance = b_bal - 1;
1644
0
      else
1645
0
        right->balance = a_bal + b_bal - 2;
1646
49.5k
      node->balance = a_bal - 1;
1647
49.5k
    }
1648
51.8k
  else
1649
51.8k
    {
1650
51.8k
      if (a_bal <= b_bal)
1651
3.58k
        right->balance = a_bal - 2;
1652
48.2k
      else
1653
48.2k
        right->balance = b_bal - 1;
1654
51.8k
      node->balance = a_bal - b_bal - 1;
1655
51.8k
    }
1656
1657
101k
  return right;
1658
101k
}
1659
1660
static GTreeNode *
1661
g_tree_node_rotate_right (GTreeNode *node)
1662
143k
{
1663
143k
  GTreeNode *left;
1664
143k
  gint a_bal;
1665
143k
  gint b_bal;
1666
1667
143k
  left = node->left;
1668
1669
143k
  if (left->right_child)
1670
11.2k
    node->left = left->right;
1671
132k
  else
1672
132k
    {
1673
132k
      node->left_child = FALSE;
1674
132k
      left->right_child = TRUE;
1675
132k
    }
1676
143k
  left->right = node;
1677
1678
143k
  a_bal = node->balance;
1679
143k
  b_bal = left->balance;
1680
1681
143k
  if (b_bal <= 0)
1682
140k
    {
1683
140k
      if (b_bal > a_bal)
1684
121k
        left->balance = b_bal + 1;
1685
18.8k
      else
1686
18.8k
        left->balance = a_bal + 2;
1687
140k
      node->balance = a_bal - b_bal + 1;
1688
140k
    }
1689
2.80k
  else
1690
2.80k
    {
1691
2.80k
      if (a_bal <= -1)
1692
2.80k
        left->balance = b_bal + 1;
1693
0
      else
1694
0
        left->balance = a_bal + b_bal + 2;
1695
2.80k
      node->balance = a_bal + 1;
1696
2.80k
    }
1697
1698
143k
  return left;
1699
143k
}
1700
1701
#ifdef G_TREE_DEBUG
1702
static gint
1703
g_tree_node_height (GTreeNode *node)
1704
{
1705
  gint left_height;
1706
  gint right_height;
1707
1708
  if (node)
1709
    {
1710
      left_height = 0;
1711
      right_height = 0;
1712
1713
      if (node->left_child)
1714
        left_height = g_tree_node_height (node->left);
1715
1716
      if (node->right_child)
1717
        right_height = g_tree_node_height (node->right);
1718
1719
      return MAX (left_height, right_height) + 1;
1720
    }
1721
1722
  return 0;
1723
}
1724
1725
static void
1726
g_tree_node_check (GTreeNode *node)
1727
{
1728
  gint left_height;
1729
  gint right_height;
1730
  gint balance;
1731
  GTreeNode *tmp;
1732
1733
  if (node)
1734
    {
1735
      if (node->left_child)
1736
        {
1737
          tmp = g_tree_node_previous (node);
1738
          g_assert (tmp->right == node);
1739
        }
1740
1741
      if (node->right_child)
1742
        {
1743
          tmp = g_tree_node_next (node);
1744
          g_assert (tmp->left == node);
1745
        }
1746
1747
      left_height = 0;
1748
      right_height = 0;
1749
      
1750
      if (node->left_child)
1751
        left_height = g_tree_node_height (node->left);
1752
      if (node->right_child)
1753
        right_height = g_tree_node_height (node->right);
1754
      
1755
      balance = right_height - left_height;
1756
      g_assert (balance == node->balance);
1757
      
1758
      if (node->left_child)
1759
        g_tree_node_check (node->left);
1760
      if (node->right_child)
1761
        g_tree_node_check (node->right);
1762
    }
1763
}
1764
1765
static void
1766
g_tree_node_dump (GTreeNode *node, 
1767
                  gint       indent)
1768
{
1769
  g_print ("%*s%c\n", indent, "", *(char *)node->key);
1770
1771
  if (node->left_child)
1772
    {
1773
      g_print ("%*sLEFT\n", indent, "");
1774
      g_tree_node_dump (node->left, indent + 2);
1775
    }
1776
  else if (node->left)
1777
    g_print ("%*s<%c\n", indent + 2, "", *(char *)node->left->key);
1778
1779
  if (node->right_child)
1780
    {
1781
      g_print ("%*sRIGHT\n", indent, "");
1782
      g_tree_node_dump (node->right, indent + 2);
1783
    }
1784
  else if (node->right)
1785
    g_print ("%*s>%c\n", indent + 2, "", *(char *)node->right->key);
1786
}
1787
1788
void
1789
g_tree_dump (GTree *tree)
1790
{
1791
  if (tree->root)
1792
    g_tree_node_dump (tree->root, 0);
1793
}
1794
#endif