xref: /openbmc/qemu/util/qtree.c (revision e3feb2cc224f61149a27f021042f5a4230bb1008)
1*e3feb2ccSEmilio Cota /*
2*e3feb2ccSEmilio Cota  * GLIB - Library of useful routines for C programming
3*e3feb2ccSEmilio Cota  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
4*e3feb2ccSEmilio Cota  *
5*e3feb2ccSEmilio Cota  * SPDX-License-Identifier: LGPL-2.1-or-later
6*e3feb2ccSEmilio Cota  *
7*e3feb2ccSEmilio Cota  * This library is free software; you can redistribute it and/or
8*e3feb2ccSEmilio Cota  * modify it under the terms of the GNU Lesser General Public
9*e3feb2ccSEmilio Cota  * License as published by the Free Software Foundation; either
10*e3feb2ccSEmilio Cota  * version 2.1 of the License, or (at your option) any later version.
11*e3feb2ccSEmilio Cota  *
12*e3feb2ccSEmilio Cota  * This library is distributed in the hope that it will be useful,
13*e3feb2ccSEmilio Cota  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14*e3feb2ccSEmilio Cota  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15*e3feb2ccSEmilio Cota  * Lesser General Public License for more details.
16*e3feb2ccSEmilio Cota  *
17*e3feb2ccSEmilio Cota  * You should have received a copy of the GNU Lesser General Public
18*e3feb2ccSEmilio Cota  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19*e3feb2ccSEmilio Cota  */
20*e3feb2ccSEmilio Cota 
21*e3feb2ccSEmilio Cota /*
22*e3feb2ccSEmilio Cota  * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
23*e3feb2ccSEmilio Cota  * file for a list of people on the GLib Team.  See the ChangeLog
24*e3feb2ccSEmilio Cota  * files for a list of changes.  These files are distributed with
25*e3feb2ccSEmilio Cota  * GLib at ftp://ftp.gtk.org/pub/gtk/.
26*e3feb2ccSEmilio Cota  */
27*e3feb2ccSEmilio Cota 
28*e3feb2ccSEmilio Cota /*
29*e3feb2ccSEmilio Cota  * MT safe
30*e3feb2ccSEmilio Cota  */
31*e3feb2ccSEmilio Cota 
32*e3feb2ccSEmilio Cota #include "qemu/osdep.h"
33*e3feb2ccSEmilio Cota #include "qemu/qtree.h"
34*e3feb2ccSEmilio Cota 
35*e3feb2ccSEmilio Cota /**
36*e3feb2ccSEmilio Cota  * SECTION:trees-binary
37*e3feb2ccSEmilio Cota  * @title: Balanced Binary Trees
38*e3feb2ccSEmilio Cota  * @short_description: a sorted collection of key/value pairs optimized
39*e3feb2ccSEmilio Cota  *                     for searching and traversing in order
40*e3feb2ccSEmilio Cota  *
41*e3feb2ccSEmilio Cota  * The #QTree structure and its associated functions provide a sorted
42*e3feb2ccSEmilio Cota  * collection of key/value pairs optimized for searching and traversing
43*e3feb2ccSEmilio Cota  * in order. This means that most of the operations  (access, search,
44*e3feb2ccSEmilio Cota  * insertion, deletion, ...) on #QTree are O(log(n)) in average and O(n)
45*e3feb2ccSEmilio Cota  * in worst case for time complexity. But, note that maintaining a
46*e3feb2ccSEmilio Cota  * balanced sorted #QTree of n elements is done in time O(n log(n)).
47*e3feb2ccSEmilio Cota  *
48*e3feb2ccSEmilio Cota  * To create a new #QTree use q_tree_new().
49*e3feb2ccSEmilio Cota  *
50*e3feb2ccSEmilio Cota  * To insert a key/value pair into a #QTree use q_tree_insert()
51*e3feb2ccSEmilio Cota  * (O(n log(n))).
52*e3feb2ccSEmilio Cota  *
53*e3feb2ccSEmilio Cota  * To remove a key/value pair use q_tree_remove() (O(n log(n))).
54*e3feb2ccSEmilio Cota  *
55*e3feb2ccSEmilio Cota  * To look up the value corresponding to a given key, use
56*e3feb2ccSEmilio Cota  * q_tree_lookup() and q_tree_lookup_extended().
57*e3feb2ccSEmilio Cota  *
58*e3feb2ccSEmilio Cota  * To find out the number of nodes in a #QTree, use q_tree_nnodes(). To
59*e3feb2ccSEmilio Cota  * get the height of a #QTree, use q_tree_height().
60*e3feb2ccSEmilio Cota  *
61*e3feb2ccSEmilio Cota  * To traverse a #QTree, calling a function for each node visited in
62*e3feb2ccSEmilio Cota  * the traversal, use q_tree_foreach().
63*e3feb2ccSEmilio Cota  *
64*e3feb2ccSEmilio Cota  * To destroy a #QTree, use q_tree_destroy().
65*e3feb2ccSEmilio Cota  **/
66*e3feb2ccSEmilio Cota 
67*e3feb2ccSEmilio Cota #define MAX_GTREE_HEIGHT 40
68*e3feb2ccSEmilio Cota 
69*e3feb2ccSEmilio Cota /**
70*e3feb2ccSEmilio Cota  * QTree:
71*e3feb2ccSEmilio Cota  *
72*e3feb2ccSEmilio Cota  * The QTree struct is an opaque data structure representing a
73*e3feb2ccSEmilio Cota  * [balanced binary tree][glib-Balanced-Binary-Trees]. It should be
74*e3feb2ccSEmilio Cota  * accessed only by using the following functions.
75*e3feb2ccSEmilio Cota  */
76*e3feb2ccSEmilio Cota struct _QTree {
77*e3feb2ccSEmilio Cota     QTreeNode        *root;
78*e3feb2ccSEmilio Cota     GCompareDataFunc  key_compare;
79*e3feb2ccSEmilio Cota     GDestroyNotify    key_destroy_func;
80*e3feb2ccSEmilio Cota     GDestroyNotify    value_destroy_func;
81*e3feb2ccSEmilio Cota     gpointer          key_compare_data;
82*e3feb2ccSEmilio Cota     guint             nnodes;
83*e3feb2ccSEmilio Cota     gint              ref_count;
84*e3feb2ccSEmilio Cota };
85*e3feb2ccSEmilio Cota 
86*e3feb2ccSEmilio Cota struct _QTreeNode {
87*e3feb2ccSEmilio Cota     gpointer   key;         /* key for this node */
88*e3feb2ccSEmilio Cota     gpointer   value;       /* value stored at this node */
89*e3feb2ccSEmilio Cota     QTreeNode *left;        /* left subtree */
90*e3feb2ccSEmilio Cota     QTreeNode *right;       /* right subtree */
91*e3feb2ccSEmilio Cota     gint8      balance;     /* height (right) - height (left) */
92*e3feb2ccSEmilio Cota     guint8     left_child;
93*e3feb2ccSEmilio Cota     guint8     right_child;
94*e3feb2ccSEmilio Cota };
95*e3feb2ccSEmilio Cota 
96*e3feb2ccSEmilio Cota 
97*e3feb2ccSEmilio Cota static QTreeNode *q_tree_node_new(gpointer       key,
98*e3feb2ccSEmilio Cota                                   gpointer       value);
99*e3feb2ccSEmilio Cota static QTreeNode *q_tree_insert_internal(QTree *tree,
100*e3feb2ccSEmilio Cota                                          gpointer key,
101*e3feb2ccSEmilio Cota                                          gpointer value,
102*e3feb2ccSEmilio Cota                                          gboolean replace);
103*e3feb2ccSEmilio Cota static gboolean   q_tree_remove_internal(QTree         *tree,
104*e3feb2ccSEmilio Cota                                          gconstpointer  key,
105*e3feb2ccSEmilio Cota                                          gboolean       steal);
106*e3feb2ccSEmilio Cota static QTreeNode *q_tree_node_balance(QTreeNode     *node);
107*e3feb2ccSEmilio Cota static QTreeNode *q_tree_find_node(QTree         *tree,
108*e3feb2ccSEmilio Cota                                    gconstpointer  key);
109*e3feb2ccSEmilio Cota static QTreeNode *q_tree_node_search(QTreeNode *node,
110*e3feb2ccSEmilio Cota                                      GCompareFunc search_func,
111*e3feb2ccSEmilio Cota                                      gconstpointer data);
112*e3feb2ccSEmilio Cota static QTreeNode *q_tree_node_rotate_left(QTreeNode     *node);
113*e3feb2ccSEmilio Cota static QTreeNode *q_tree_node_rotate_right(QTreeNode     *node);
114*e3feb2ccSEmilio Cota #ifdef Q_TREE_DEBUG
115*e3feb2ccSEmilio Cota static void       q_tree_node_check(QTreeNode     *node);
116*e3feb2ccSEmilio Cota #endif
117*e3feb2ccSEmilio Cota 
118*e3feb2ccSEmilio Cota static QTreeNode*
119*e3feb2ccSEmilio Cota q_tree_node_new(gpointer key,
120*e3feb2ccSEmilio Cota                 gpointer value)
121*e3feb2ccSEmilio Cota {
122*e3feb2ccSEmilio Cota     QTreeNode *node = g_new(QTreeNode, 1);
123*e3feb2ccSEmilio Cota 
124*e3feb2ccSEmilio Cota     node->balance = 0;
125*e3feb2ccSEmilio Cota     node->left = NULL;
126*e3feb2ccSEmilio Cota     node->right = NULL;
127*e3feb2ccSEmilio Cota     node->left_child = FALSE;
128*e3feb2ccSEmilio Cota     node->right_child = FALSE;
129*e3feb2ccSEmilio Cota     node->key = key;
130*e3feb2ccSEmilio Cota     node->value = value;
131*e3feb2ccSEmilio Cota 
132*e3feb2ccSEmilio Cota     return node;
133*e3feb2ccSEmilio Cota }
134*e3feb2ccSEmilio Cota 
135*e3feb2ccSEmilio Cota /**
136*e3feb2ccSEmilio Cota  * q_tree_new:
137*e3feb2ccSEmilio Cota  * @key_compare_func: the function used to order the nodes in the #QTree.
138*e3feb2ccSEmilio Cota  *   It should return values similar to the standard strcmp() function -
139*e3feb2ccSEmilio Cota  *   0 if the two arguments are equal, a negative value if the first argument
140*e3feb2ccSEmilio Cota  *   comes before the second, or a positive value if the first argument comes
141*e3feb2ccSEmilio Cota  *   after the second.
142*e3feb2ccSEmilio Cota  *
143*e3feb2ccSEmilio Cota  * Creates a new #QTree.
144*e3feb2ccSEmilio Cota  *
145*e3feb2ccSEmilio Cota  * Returns: a newly allocated #QTree
146*e3feb2ccSEmilio Cota  */
147*e3feb2ccSEmilio Cota QTree *
148*e3feb2ccSEmilio Cota q_tree_new(GCompareFunc key_compare_func)
149*e3feb2ccSEmilio Cota {
150*e3feb2ccSEmilio Cota     g_return_val_if_fail(key_compare_func != NULL, NULL);
151*e3feb2ccSEmilio Cota 
152*e3feb2ccSEmilio Cota     return q_tree_new_full((GCompareDataFunc) key_compare_func, NULL,
153*e3feb2ccSEmilio Cota                            NULL, NULL);
154*e3feb2ccSEmilio Cota }
155*e3feb2ccSEmilio Cota 
156*e3feb2ccSEmilio Cota /**
157*e3feb2ccSEmilio Cota  * q_tree_new_with_data:
158*e3feb2ccSEmilio Cota  * @key_compare_func: qsort()-style comparison function
159*e3feb2ccSEmilio Cota  * @key_compare_data: data to pass to comparison function
160*e3feb2ccSEmilio Cota  *
161*e3feb2ccSEmilio Cota  * Creates a new #QTree with a comparison function that accepts user data.
162*e3feb2ccSEmilio Cota  * See q_tree_new() for more details.
163*e3feb2ccSEmilio Cota  *
164*e3feb2ccSEmilio Cota  * Returns: a newly allocated #QTree
165*e3feb2ccSEmilio Cota  */
166*e3feb2ccSEmilio Cota QTree *
167*e3feb2ccSEmilio Cota q_tree_new_with_data(GCompareDataFunc key_compare_func,
168*e3feb2ccSEmilio Cota                      gpointer         key_compare_data)
169*e3feb2ccSEmilio Cota {
170*e3feb2ccSEmilio Cota     g_return_val_if_fail(key_compare_func != NULL, NULL);
171*e3feb2ccSEmilio Cota 
172*e3feb2ccSEmilio Cota     return q_tree_new_full(key_compare_func, key_compare_data,
173*e3feb2ccSEmilio Cota                            NULL, NULL);
174*e3feb2ccSEmilio Cota }
175*e3feb2ccSEmilio Cota 
176*e3feb2ccSEmilio Cota /**
177*e3feb2ccSEmilio Cota  * q_tree_new_full:
178*e3feb2ccSEmilio Cota  * @key_compare_func: qsort()-style comparison function
179*e3feb2ccSEmilio Cota  * @key_compare_data: data to pass to comparison function
180*e3feb2ccSEmilio Cota  * @key_destroy_func: a function to free the memory allocated for the key
181*e3feb2ccSEmilio Cota  *   used when removing the entry from the #QTree or %NULL if you don't
182*e3feb2ccSEmilio Cota  *   want to supply such a function
183*e3feb2ccSEmilio Cota  * @value_destroy_func: a function to free the memory allocated for the
184*e3feb2ccSEmilio Cota  *   value used when removing the entry from the #QTree or %NULL if you
185*e3feb2ccSEmilio Cota  *   don't want to supply such a function
186*e3feb2ccSEmilio Cota  *
187*e3feb2ccSEmilio Cota  * Creates a new #QTree like q_tree_new() and allows to specify functions
188*e3feb2ccSEmilio Cota  * to free the memory allocated for the key and value that get called when
189*e3feb2ccSEmilio Cota  * removing the entry from the #QTree.
190*e3feb2ccSEmilio Cota  *
191*e3feb2ccSEmilio Cota  * Returns: a newly allocated #QTree
192*e3feb2ccSEmilio Cota  */
193*e3feb2ccSEmilio Cota QTree *
194*e3feb2ccSEmilio Cota q_tree_new_full(GCompareDataFunc key_compare_func,
195*e3feb2ccSEmilio Cota                 gpointer         key_compare_data,
196*e3feb2ccSEmilio Cota                 GDestroyNotify   key_destroy_func,
197*e3feb2ccSEmilio Cota                 GDestroyNotify   value_destroy_func)
198*e3feb2ccSEmilio Cota {
199*e3feb2ccSEmilio Cota     QTree *tree;
200*e3feb2ccSEmilio Cota 
201*e3feb2ccSEmilio Cota     g_return_val_if_fail(key_compare_func != NULL, NULL);
202*e3feb2ccSEmilio Cota 
203*e3feb2ccSEmilio Cota     tree = g_new(QTree, 1);
204*e3feb2ccSEmilio Cota     tree->root               = NULL;
205*e3feb2ccSEmilio Cota     tree->key_compare        = key_compare_func;
206*e3feb2ccSEmilio Cota     tree->key_destroy_func   = key_destroy_func;
207*e3feb2ccSEmilio Cota     tree->value_destroy_func = value_destroy_func;
208*e3feb2ccSEmilio Cota     tree->key_compare_data   = key_compare_data;
209*e3feb2ccSEmilio Cota     tree->nnodes             = 0;
210*e3feb2ccSEmilio Cota     tree->ref_count          = 1;
211*e3feb2ccSEmilio Cota 
212*e3feb2ccSEmilio Cota     return tree;
213*e3feb2ccSEmilio Cota }
214*e3feb2ccSEmilio Cota 
215*e3feb2ccSEmilio Cota /**
216*e3feb2ccSEmilio Cota  * q_tree_node_first:
217*e3feb2ccSEmilio Cota  * @tree: a #QTree
218*e3feb2ccSEmilio Cota  *
219*e3feb2ccSEmilio Cota  * Returns the first in-order node of the tree, or %NULL
220*e3feb2ccSEmilio Cota  * for an empty tree.
221*e3feb2ccSEmilio Cota  *
222*e3feb2ccSEmilio Cota  * Returns: (nullable) (transfer none): the first node in the tree
223*e3feb2ccSEmilio Cota  *
224*e3feb2ccSEmilio Cota  * Since: 2.68 in GLib. Internal in Qtree, i.e. not in the public API.
225*e3feb2ccSEmilio Cota  */
226*e3feb2ccSEmilio Cota static QTreeNode *
227*e3feb2ccSEmilio Cota q_tree_node_first(QTree *tree)
228*e3feb2ccSEmilio Cota {
229*e3feb2ccSEmilio Cota     QTreeNode *tmp;
230*e3feb2ccSEmilio Cota 
231*e3feb2ccSEmilio Cota     g_return_val_if_fail(tree != NULL, NULL);
232*e3feb2ccSEmilio Cota 
233*e3feb2ccSEmilio Cota     if (!tree->root) {
234*e3feb2ccSEmilio Cota         return NULL;
235*e3feb2ccSEmilio Cota     }
236*e3feb2ccSEmilio Cota 
237*e3feb2ccSEmilio Cota     tmp = tree->root;
238*e3feb2ccSEmilio Cota 
239*e3feb2ccSEmilio Cota     while (tmp->left_child) {
240*e3feb2ccSEmilio Cota         tmp = tmp->left;
241*e3feb2ccSEmilio Cota     }
242*e3feb2ccSEmilio Cota 
243*e3feb2ccSEmilio Cota     return tmp;
244*e3feb2ccSEmilio Cota }
245*e3feb2ccSEmilio Cota 
246*e3feb2ccSEmilio Cota /**
247*e3feb2ccSEmilio Cota  * q_tree_node_previous
248*e3feb2ccSEmilio Cota  * @node: a #QTree node
249*e3feb2ccSEmilio Cota  *
250*e3feb2ccSEmilio Cota  * Returns the previous in-order node of the tree, or %NULL
251*e3feb2ccSEmilio Cota  * if the passed node was already the first one.
252*e3feb2ccSEmilio Cota  *
253*e3feb2ccSEmilio Cota  * Returns: (nullable) (transfer none): the previous node in the tree
254*e3feb2ccSEmilio Cota  *
255*e3feb2ccSEmilio Cota  * Since: 2.68 in GLib. Internal in Qtree, i.e. not in the public API.
256*e3feb2ccSEmilio Cota  */
257*e3feb2ccSEmilio Cota static QTreeNode *
258*e3feb2ccSEmilio Cota q_tree_node_previous(QTreeNode *node)
259*e3feb2ccSEmilio Cota {
260*e3feb2ccSEmilio Cota     QTreeNode *tmp;
261*e3feb2ccSEmilio Cota 
262*e3feb2ccSEmilio Cota     g_return_val_if_fail(node != NULL, NULL);
263*e3feb2ccSEmilio Cota 
264*e3feb2ccSEmilio Cota     tmp = node->left;
265*e3feb2ccSEmilio Cota 
266*e3feb2ccSEmilio Cota     if (node->left_child) {
267*e3feb2ccSEmilio Cota         while (tmp->right_child) {
268*e3feb2ccSEmilio Cota             tmp = tmp->right;
269*e3feb2ccSEmilio Cota         }
270*e3feb2ccSEmilio Cota     }
271*e3feb2ccSEmilio Cota 
272*e3feb2ccSEmilio Cota     return tmp;
273*e3feb2ccSEmilio Cota }
274*e3feb2ccSEmilio Cota 
275*e3feb2ccSEmilio Cota /**
276*e3feb2ccSEmilio Cota  * q_tree_node_next
277*e3feb2ccSEmilio Cota  * @node: a #QTree node
278*e3feb2ccSEmilio Cota  *
279*e3feb2ccSEmilio Cota  * Returns the next in-order node of the tree, or %NULL
280*e3feb2ccSEmilio Cota  * if the passed node was already the last one.
281*e3feb2ccSEmilio Cota  *
282*e3feb2ccSEmilio Cota  * Returns: (nullable) (transfer none): the next node in the tree
283*e3feb2ccSEmilio Cota  *
284*e3feb2ccSEmilio Cota  * Since: 2.68 in GLib. Internal in Qtree, i.e. not in the public API.
285*e3feb2ccSEmilio Cota  */
286*e3feb2ccSEmilio Cota static QTreeNode *
287*e3feb2ccSEmilio Cota q_tree_node_next(QTreeNode *node)
288*e3feb2ccSEmilio Cota {
289*e3feb2ccSEmilio Cota     QTreeNode *tmp;
290*e3feb2ccSEmilio Cota 
291*e3feb2ccSEmilio Cota     g_return_val_if_fail(node != NULL, NULL);
292*e3feb2ccSEmilio Cota 
293*e3feb2ccSEmilio Cota     tmp = node->right;
294*e3feb2ccSEmilio Cota 
295*e3feb2ccSEmilio Cota     if (node->right_child) {
296*e3feb2ccSEmilio Cota         while (tmp->left_child) {
297*e3feb2ccSEmilio Cota             tmp = tmp->left;
298*e3feb2ccSEmilio Cota         }
299*e3feb2ccSEmilio Cota     }
300*e3feb2ccSEmilio Cota 
301*e3feb2ccSEmilio Cota     return tmp;
302*e3feb2ccSEmilio Cota }
303*e3feb2ccSEmilio Cota 
304*e3feb2ccSEmilio Cota /**
305*e3feb2ccSEmilio Cota  * q_tree_remove_all:
306*e3feb2ccSEmilio Cota  * @tree: a #QTree
307*e3feb2ccSEmilio Cota  *
308*e3feb2ccSEmilio Cota  * Removes all nodes from a #QTree and destroys their keys and values,
309*e3feb2ccSEmilio Cota  * then resets the #QTree’s root to %NULL.
310*e3feb2ccSEmilio Cota  *
311*e3feb2ccSEmilio Cota  * Since: 2.70 in GLib. Internal in Qtree, i.e. not in the public API.
312*e3feb2ccSEmilio Cota  */
313*e3feb2ccSEmilio Cota static void
314*e3feb2ccSEmilio Cota q_tree_remove_all(QTree *tree)
315*e3feb2ccSEmilio Cota {
316*e3feb2ccSEmilio Cota     QTreeNode *node;
317*e3feb2ccSEmilio Cota     QTreeNode *next;
318*e3feb2ccSEmilio Cota 
319*e3feb2ccSEmilio Cota     g_return_if_fail(tree != NULL);
320*e3feb2ccSEmilio Cota 
321*e3feb2ccSEmilio Cota     node = q_tree_node_first(tree);
322*e3feb2ccSEmilio Cota 
323*e3feb2ccSEmilio Cota     while (node) {
324*e3feb2ccSEmilio Cota         next = q_tree_node_next(node);
325*e3feb2ccSEmilio Cota 
326*e3feb2ccSEmilio Cota         if (tree->key_destroy_func) {
327*e3feb2ccSEmilio Cota             tree->key_destroy_func(node->key);
328*e3feb2ccSEmilio Cota         }
329*e3feb2ccSEmilio Cota         if (tree->value_destroy_func) {
330*e3feb2ccSEmilio Cota             tree->value_destroy_func(node->value);
331*e3feb2ccSEmilio Cota         }
332*e3feb2ccSEmilio Cota         g_free(node);
333*e3feb2ccSEmilio Cota 
334*e3feb2ccSEmilio Cota #ifdef Q_TREE_DEBUG
335*e3feb2ccSEmilio Cota         g_assert(tree->nnodes > 0);
336*e3feb2ccSEmilio Cota         tree->nnodes--;
337*e3feb2ccSEmilio Cota #endif
338*e3feb2ccSEmilio Cota 
339*e3feb2ccSEmilio Cota         node = next;
340*e3feb2ccSEmilio Cota     }
341*e3feb2ccSEmilio Cota 
342*e3feb2ccSEmilio Cota #ifdef Q_TREE_DEBUG
343*e3feb2ccSEmilio Cota     g_assert(tree->nnodes == 0);
344*e3feb2ccSEmilio Cota #endif
345*e3feb2ccSEmilio Cota 
346*e3feb2ccSEmilio Cota     tree->root = NULL;
347*e3feb2ccSEmilio Cota #ifndef Q_TREE_DEBUG
348*e3feb2ccSEmilio Cota     tree->nnodes = 0;
349*e3feb2ccSEmilio Cota #endif
350*e3feb2ccSEmilio Cota }
351*e3feb2ccSEmilio Cota 
352*e3feb2ccSEmilio Cota /**
353*e3feb2ccSEmilio Cota  * q_tree_ref:
354*e3feb2ccSEmilio Cota  * @tree: a #QTree
355*e3feb2ccSEmilio Cota  *
356*e3feb2ccSEmilio Cota  * Increments the reference count of @tree by one.
357*e3feb2ccSEmilio Cota  *
358*e3feb2ccSEmilio Cota  * It is safe to call this function from any thread.
359*e3feb2ccSEmilio Cota  *
360*e3feb2ccSEmilio Cota  * Returns: the passed in #QTree
361*e3feb2ccSEmilio Cota  *
362*e3feb2ccSEmilio Cota  * Since: 2.22
363*e3feb2ccSEmilio Cota  */
364*e3feb2ccSEmilio Cota QTree *
365*e3feb2ccSEmilio Cota q_tree_ref(QTree *tree)
366*e3feb2ccSEmilio Cota {
367*e3feb2ccSEmilio Cota     g_return_val_if_fail(tree != NULL, NULL);
368*e3feb2ccSEmilio Cota 
369*e3feb2ccSEmilio Cota     g_atomic_int_inc(&tree->ref_count);
370*e3feb2ccSEmilio Cota 
371*e3feb2ccSEmilio Cota     return tree;
372*e3feb2ccSEmilio Cota }
373*e3feb2ccSEmilio Cota 
374*e3feb2ccSEmilio Cota /**
375*e3feb2ccSEmilio Cota  * q_tree_unref:
376*e3feb2ccSEmilio Cota  * @tree: a #QTree
377*e3feb2ccSEmilio Cota  *
378*e3feb2ccSEmilio Cota  * Decrements the reference count of @tree by one.
379*e3feb2ccSEmilio Cota  * If the reference count drops to 0, all keys and values will
380*e3feb2ccSEmilio Cota  * be destroyed (if destroy functions were specified) and all
381*e3feb2ccSEmilio Cota  * memory allocated by @tree will be released.
382*e3feb2ccSEmilio Cota  *
383*e3feb2ccSEmilio Cota  * It is safe to call this function from any thread.
384*e3feb2ccSEmilio Cota  *
385*e3feb2ccSEmilio Cota  * Since: 2.22
386*e3feb2ccSEmilio Cota  */
387*e3feb2ccSEmilio Cota void
388*e3feb2ccSEmilio Cota q_tree_unref(QTree *tree)
389*e3feb2ccSEmilio Cota {
390*e3feb2ccSEmilio Cota     g_return_if_fail(tree != NULL);
391*e3feb2ccSEmilio Cota 
392*e3feb2ccSEmilio Cota     if (g_atomic_int_dec_and_test(&tree->ref_count)) {
393*e3feb2ccSEmilio Cota         q_tree_remove_all(tree);
394*e3feb2ccSEmilio Cota         g_free(tree);
395*e3feb2ccSEmilio Cota     }
396*e3feb2ccSEmilio Cota }
397*e3feb2ccSEmilio Cota 
398*e3feb2ccSEmilio Cota /**
399*e3feb2ccSEmilio Cota  * q_tree_destroy:
400*e3feb2ccSEmilio Cota  * @tree: a #QTree
401*e3feb2ccSEmilio Cota  *
402*e3feb2ccSEmilio Cota  * Removes all keys and values from the #QTree and decreases its
403*e3feb2ccSEmilio Cota  * reference count by one. If keys and/or values are dynamically
404*e3feb2ccSEmilio Cota  * allocated, you should either free them first or create the #QTree
405*e3feb2ccSEmilio Cota  * using q_tree_new_full(). In the latter case the destroy functions
406*e3feb2ccSEmilio Cota  * you supplied will be called on all keys and values before destroying
407*e3feb2ccSEmilio Cota  * the #QTree.
408*e3feb2ccSEmilio Cota  */
409*e3feb2ccSEmilio Cota void
410*e3feb2ccSEmilio Cota q_tree_destroy(QTree *tree)
411*e3feb2ccSEmilio Cota {
412*e3feb2ccSEmilio Cota     g_return_if_fail(tree != NULL);
413*e3feb2ccSEmilio Cota 
414*e3feb2ccSEmilio Cota     q_tree_remove_all(tree);
415*e3feb2ccSEmilio Cota     q_tree_unref(tree);
416*e3feb2ccSEmilio Cota }
417*e3feb2ccSEmilio Cota 
418*e3feb2ccSEmilio Cota /**
419*e3feb2ccSEmilio Cota  * q_tree_insert_node:
420*e3feb2ccSEmilio Cota  * @tree: a #QTree
421*e3feb2ccSEmilio Cota  * @key: the key to insert
422*e3feb2ccSEmilio Cota  * @value: the value corresponding to the key
423*e3feb2ccSEmilio Cota  *
424*e3feb2ccSEmilio Cota  * Inserts a key/value pair into a #QTree.
425*e3feb2ccSEmilio Cota  *
426*e3feb2ccSEmilio Cota  * If the given key already exists in the #QTree its corresponding value
427*e3feb2ccSEmilio Cota  * is set to the new value. If you supplied a @value_destroy_func when
428*e3feb2ccSEmilio Cota  * creating the #QTree, the old value is freed using that function. If
429*e3feb2ccSEmilio Cota  * you supplied a @key_destroy_func when creating the #QTree, the passed
430*e3feb2ccSEmilio Cota  * key is freed using that function.
431*e3feb2ccSEmilio Cota  *
432*e3feb2ccSEmilio Cota  * The tree is automatically 'balanced' as new key/value pairs are added,
433*e3feb2ccSEmilio Cota  * so that the distance from the root to every leaf is as small as possible.
434*e3feb2ccSEmilio Cota  * The cost of maintaining a balanced tree while inserting new key/value
435*e3feb2ccSEmilio Cota  * result in a O(n log(n)) operation where most of the other operations
436*e3feb2ccSEmilio Cota  * are O(log(n)).
437*e3feb2ccSEmilio Cota  *
438*e3feb2ccSEmilio Cota  * Returns: (transfer none): the inserted (or set) node.
439*e3feb2ccSEmilio Cota  *
440*e3feb2ccSEmilio Cota  * Since: 2.68 in GLib. Internal in Qtree, i.e. not in the public API.
441*e3feb2ccSEmilio Cota  */
442*e3feb2ccSEmilio Cota static QTreeNode *
443*e3feb2ccSEmilio Cota q_tree_insert_node(QTree    *tree,
444*e3feb2ccSEmilio Cota                    gpointer  key,
445*e3feb2ccSEmilio Cota                    gpointer  value)
446*e3feb2ccSEmilio Cota {
447*e3feb2ccSEmilio Cota     QTreeNode *node;
448*e3feb2ccSEmilio Cota 
449*e3feb2ccSEmilio Cota     g_return_val_if_fail(tree != NULL, NULL);
450*e3feb2ccSEmilio Cota 
451*e3feb2ccSEmilio Cota     node = q_tree_insert_internal(tree, key, value, FALSE);
452*e3feb2ccSEmilio Cota 
453*e3feb2ccSEmilio Cota #ifdef Q_TREE_DEBUG
454*e3feb2ccSEmilio Cota     q_tree_node_check(tree->root);
455*e3feb2ccSEmilio Cota #endif
456*e3feb2ccSEmilio Cota 
457*e3feb2ccSEmilio Cota     return node;
458*e3feb2ccSEmilio Cota }
459*e3feb2ccSEmilio Cota 
460*e3feb2ccSEmilio Cota /**
461*e3feb2ccSEmilio Cota  * q_tree_insert:
462*e3feb2ccSEmilio Cota  * @tree: a #QTree
463*e3feb2ccSEmilio Cota  * @key: the key to insert
464*e3feb2ccSEmilio Cota  * @value: the value corresponding to the key
465*e3feb2ccSEmilio Cota  *
466*e3feb2ccSEmilio Cota  * Inserts a key/value pair into a #QTree.
467*e3feb2ccSEmilio Cota  *
468*e3feb2ccSEmilio Cota  * Inserts a new key and value into a #QTree as q_tree_insert_node() does,
469*e3feb2ccSEmilio Cota  * only this function does not return the inserted or set node.
470*e3feb2ccSEmilio Cota  */
471*e3feb2ccSEmilio Cota void
472*e3feb2ccSEmilio Cota q_tree_insert(QTree    *tree,
473*e3feb2ccSEmilio Cota               gpointer  key,
474*e3feb2ccSEmilio Cota               gpointer  value)
475*e3feb2ccSEmilio Cota {
476*e3feb2ccSEmilio Cota     q_tree_insert_node(tree, key, value);
477*e3feb2ccSEmilio Cota }
478*e3feb2ccSEmilio Cota 
479*e3feb2ccSEmilio Cota /**
480*e3feb2ccSEmilio Cota  * q_tree_replace_node:
481*e3feb2ccSEmilio Cota  * @tree: a #QTree
482*e3feb2ccSEmilio Cota  * @key: the key to insert
483*e3feb2ccSEmilio Cota  * @value: the value corresponding to the key
484*e3feb2ccSEmilio Cota  *
485*e3feb2ccSEmilio Cota  * Inserts a new key and value into a #QTree similar to q_tree_insert_node().
486*e3feb2ccSEmilio Cota  * The difference is that if the key already exists in the #QTree, it gets
487*e3feb2ccSEmilio Cota  * replaced by the new key. If you supplied a @value_destroy_func when
488*e3feb2ccSEmilio Cota  * creating the #QTree, the old value is freed using that function. If you
489*e3feb2ccSEmilio Cota  * supplied a @key_destroy_func when creating the #QTree, the old key is
490*e3feb2ccSEmilio Cota  * freed using that function.
491*e3feb2ccSEmilio Cota  *
492*e3feb2ccSEmilio Cota  * The tree is automatically 'balanced' as new key/value pairs are added,
493*e3feb2ccSEmilio Cota  * so that the distance from the root to every leaf is as small as possible.
494*e3feb2ccSEmilio Cota  *
495*e3feb2ccSEmilio Cota  * Returns: (transfer none): the inserted (or set) node.
496*e3feb2ccSEmilio Cota  *
497*e3feb2ccSEmilio Cota  * Since: 2.68 in GLib. Internal in Qtree, i.e. not in the public API.
498*e3feb2ccSEmilio Cota  */
499*e3feb2ccSEmilio Cota static QTreeNode *
500*e3feb2ccSEmilio Cota q_tree_replace_node(QTree    *tree,
501*e3feb2ccSEmilio Cota                     gpointer  key,
502*e3feb2ccSEmilio Cota                     gpointer  value)
503*e3feb2ccSEmilio Cota {
504*e3feb2ccSEmilio Cota     QTreeNode *node;
505*e3feb2ccSEmilio Cota 
506*e3feb2ccSEmilio Cota     g_return_val_if_fail(tree != NULL, NULL);
507*e3feb2ccSEmilio Cota 
508*e3feb2ccSEmilio Cota     node = q_tree_insert_internal(tree, key, value, TRUE);
509*e3feb2ccSEmilio Cota 
510*e3feb2ccSEmilio Cota #ifdef Q_TREE_DEBUG
511*e3feb2ccSEmilio Cota     q_tree_node_check(tree->root);
512*e3feb2ccSEmilio Cota #endif
513*e3feb2ccSEmilio Cota 
514*e3feb2ccSEmilio Cota     return node;
515*e3feb2ccSEmilio Cota }
516*e3feb2ccSEmilio Cota 
517*e3feb2ccSEmilio Cota /**
518*e3feb2ccSEmilio Cota  * q_tree_replace:
519*e3feb2ccSEmilio Cota  * @tree: a #QTree
520*e3feb2ccSEmilio Cota  * @key: the key to insert
521*e3feb2ccSEmilio Cota  * @value: the value corresponding to the key
522*e3feb2ccSEmilio Cota  *
523*e3feb2ccSEmilio Cota  * Inserts a new key and value into a #QTree as q_tree_replace_node() does,
524*e3feb2ccSEmilio Cota  * only this function does not return the inserted or set node.
525*e3feb2ccSEmilio Cota  */
526*e3feb2ccSEmilio Cota void
527*e3feb2ccSEmilio Cota q_tree_replace(QTree    *tree,
528*e3feb2ccSEmilio Cota                gpointer  key,
529*e3feb2ccSEmilio Cota                gpointer  value)
530*e3feb2ccSEmilio Cota {
531*e3feb2ccSEmilio Cota     q_tree_replace_node(tree, key, value);
532*e3feb2ccSEmilio Cota }
533*e3feb2ccSEmilio Cota 
534*e3feb2ccSEmilio Cota /* internal insert routine */
535*e3feb2ccSEmilio Cota static QTreeNode *
536*e3feb2ccSEmilio Cota q_tree_insert_internal(QTree    *tree,
537*e3feb2ccSEmilio Cota                        gpointer  key,
538*e3feb2ccSEmilio Cota                        gpointer  value,
539*e3feb2ccSEmilio Cota                        gboolean  replace)
540*e3feb2ccSEmilio Cota {
541*e3feb2ccSEmilio Cota     QTreeNode *node, *retnode;
542*e3feb2ccSEmilio Cota     QTreeNode *path[MAX_GTREE_HEIGHT];
543*e3feb2ccSEmilio Cota     int idx;
544*e3feb2ccSEmilio Cota 
545*e3feb2ccSEmilio Cota     g_return_val_if_fail(tree != NULL, NULL);
546*e3feb2ccSEmilio Cota 
547*e3feb2ccSEmilio Cota     if (!tree->root) {
548*e3feb2ccSEmilio Cota         tree->root = q_tree_node_new(key, value);
549*e3feb2ccSEmilio Cota         tree->nnodes++;
550*e3feb2ccSEmilio Cota         return tree->root;
551*e3feb2ccSEmilio Cota     }
552*e3feb2ccSEmilio Cota 
553*e3feb2ccSEmilio Cota     idx = 0;
554*e3feb2ccSEmilio Cota     path[idx++] = NULL;
555*e3feb2ccSEmilio Cota     node = tree->root;
556*e3feb2ccSEmilio Cota 
557*e3feb2ccSEmilio Cota     while (1) {
558*e3feb2ccSEmilio Cota         int cmp = tree->key_compare(key, node->key, tree->key_compare_data);
559*e3feb2ccSEmilio Cota 
560*e3feb2ccSEmilio Cota         if (cmp == 0) {
561*e3feb2ccSEmilio Cota             if (tree->value_destroy_func) {
562*e3feb2ccSEmilio Cota                 tree->value_destroy_func(node->value);
563*e3feb2ccSEmilio Cota             }
564*e3feb2ccSEmilio Cota 
565*e3feb2ccSEmilio Cota             node->value = value;
566*e3feb2ccSEmilio Cota 
567*e3feb2ccSEmilio Cota             if (replace) {
568*e3feb2ccSEmilio Cota                 if (tree->key_destroy_func) {
569*e3feb2ccSEmilio Cota                     tree->key_destroy_func(node->key);
570*e3feb2ccSEmilio Cota                 }
571*e3feb2ccSEmilio Cota 
572*e3feb2ccSEmilio Cota                 node->key = key;
573*e3feb2ccSEmilio Cota             } else {
574*e3feb2ccSEmilio Cota                 /* free the passed key */
575*e3feb2ccSEmilio Cota                 if (tree->key_destroy_func) {
576*e3feb2ccSEmilio Cota                     tree->key_destroy_func(key);
577*e3feb2ccSEmilio Cota                 }
578*e3feb2ccSEmilio Cota             }
579*e3feb2ccSEmilio Cota 
580*e3feb2ccSEmilio Cota             return node;
581*e3feb2ccSEmilio Cota         } else if (cmp < 0) {
582*e3feb2ccSEmilio Cota             if (node->left_child) {
583*e3feb2ccSEmilio Cota                 path[idx++] = node;
584*e3feb2ccSEmilio Cota                 node = node->left;
585*e3feb2ccSEmilio Cota             } else {
586*e3feb2ccSEmilio Cota                 QTreeNode *child = q_tree_node_new(key, value);
587*e3feb2ccSEmilio Cota 
588*e3feb2ccSEmilio Cota                 child->left = node->left;
589*e3feb2ccSEmilio Cota                 child->right = node;
590*e3feb2ccSEmilio Cota                 node->left = child;
591*e3feb2ccSEmilio Cota                 node->left_child = TRUE;
592*e3feb2ccSEmilio Cota                 node->balance -= 1;
593*e3feb2ccSEmilio Cota 
594*e3feb2ccSEmilio Cota                 tree->nnodes++;
595*e3feb2ccSEmilio Cota 
596*e3feb2ccSEmilio Cota                 retnode = child;
597*e3feb2ccSEmilio Cota                 break;
598*e3feb2ccSEmilio Cota             }
599*e3feb2ccSEmilio Cota         } else {
600*e3feb2ccSEmilio Cota             if (node->right_child) {
601*e3feb2ccSEmilio Cota                 path[idx++] = node;
602*e3feb2ccSEmilio Cota                 node = node->right;
603*e3feb2ccSEmilio Cota             } else {
604*e3feb2ccSEmilio Cota                 QTreeNode *child = q_tree_node_new(key, value);
605*e3feb2ccSEmilio Cota 
606*e3feb2ccSEmilio Cota                 child->right = node->right;
607*e3feb2ccSEmilio Cota                 child->left = node;
608*e3feb2ccSEmilio Cota                 node->right = child;
609*e3feb2ccSEmilio Cota                 node->right_child = TRUE;
610*e3feb2ccSEmilio Cota                 node->balance += 1;
611*e3feb2ccSEmilio Cota 
612*e3feb2ccSEmilio Cota                 tree->nnodes++;
613*e3feb2ccSEmilio Cota 
614*e3feb2ccSEmilio Cota                 retnode = child;
615*e3feb2ccSEmilio Cota                 break;
616*e3feb2ccSEmilio Cota             }
617*e3feb2ccSEmilio Cota         }
618*e3feb2ccSEmilio Cota     }
619*e3feb2ccSEmilio Cota 
620*e3feb2ccSEmilio Cota     /*
621*e3feb2ccSEmilio Cota      * Restore balance. This is the goodness of a non-recursive
622*e3feb2ccSEmilio Cota      * implementation, when we are done with balancing we 'break'
623*e3feb2ccSEmilio Cota      * the loop and we are done.
624*e3feb2ccSEmilio Cota      */
625*e3feb2ccSEmilio Cota     while (1) {
626*e3feb2ccSEmilio Cota         QTreeNode *bparent = path[--idx];
627*e3feb2ccSEmilio Cota         gboolean left_node = (bparent && node == bparent->left);
628*e3feb2ccSEmilio Cota         g_assert(!bparent || bparent->left == node || bparent->right == node);
629*e3feb2ccSEmilio Cota 
630*e3feb2ccSEmilio Cota         if (node->balance < -1 || node->balance > 1) {
631*e3feb2ccSEmilio Cota             node = q_tree_node_balance(node);
632*e3feb2ccSEmilio Cota             if (bparent == NULL) {
633*e3feb2ccSEmilio Cota                 tree->root = node;
634*e3feb2ccSEmilio Cota             } else if (left_node) {
635*e3feb2ccSEmilio Cota                 bparent->left = node;
636*e3feb2ccSEmilio Cota             } else {
637*e3feb2ccSEmilio Cota                 bparent->right = node;
638*e3feb2ccSEmilio Cota             }
639*e3feb2ccSEmilio Cota         }
640*e3feb2ccSEmilio Cota 
641*e3feb2ccSEmilio Cota         if (node->balance == 0 || bparent == NULL) {
642*e3feb2ccSEmilio Cota             break;
643*e3feb2ccSEmilio Cota         }
644*e3feb2ccSEmilio Cota 
645*e3feb2ccSEmilio Cota         if (left_node) {
646*e3feb2ccSEmilio Cota             bparent->balance -= 1;
647*e3feb2ccSEmilio Cota         } else {
648*e3feb2ccSEmilio Cota             bparent->balance += 1;
649*e3feb2ccSEmilio Cota         }
650*e3feb2ccSEmilio Cota 
651*e3feb2ccSEmilio Cota         node = bparent;
652*e3feb2ccSEmilio Cota     }
653*e3feb2ccSEmilio Cota 
654*e3feb2ccSEmilio Cota     return retnode;
655*e3feb2ccSEmilio Cota }
656*e3feb2ccSEmilio Cota 
657*e3feb2ccSEmilio Cota /**
658*e3feb2ccSEmilio Cota  * q_tree_remove:
659*e3feb2ccSEmilio Cota  * @tree: a #QTree
660*e3feb2ccSEmilio Cota  * @key: the key to remove
661*e3feb2ccSEmilio Cota  *
662*e3feb2ccSEmilio Cota  * Removes a key/value pair from a #QTree.
663*e3feb2ccSEmilio Cota  *
664*e3feb2ccSEmilio Cota  * If the #QTree was created using q_tree_new_full(), the key and value
665*e3feb2ccSEmilio Cota  * are freed using the supplied destroy functions, otherwise you have to
666*e3feb2ccSEmilio Cota  * make sure that any dynamically allocated values are freed yourself.
667*e3feb2ccSEmilio Cota  * If the key does not exist in the #QTree, the function does nothing.
668*e3feb2ccSEmilio Cota  *
669*e3feb2ccSEmilio Cota  * The cost of maintaining a balanced tree while removing a key/value
670*e3feb2ccSEmilio Cota  * result in a O(n log(n)) operation where most of the other operations
671*e3feb2ccSEmilio Cota  * are O(log(n)).
672*e3feb2ccSEmilio Cota  *
673*e3feb2ccSEmilio Cota  * Returns: %TRUE if the key was found (prior to 2.8, this function
674*e3feb2ccSEmilio Cota  *     returned nothing)
675*e3feb2ccSEmilio Cota  */
676*e3feb2ccSEmilio Cota gboolean
677*e3feb2ccSEmilio Cota q_tree_remove(QTree         *tree,
678*e3feb2ccSEmilio Cota               gconstpointer  key)
679*e3feb2ccSEmilio Cota {
680*e3feb2ccSEmilio Cota     gboolean removed;
681*e3feb2ccSEmilio Cota 
682*e3feb2ccSEmilio Cota     g_return_val_if_fail(tree != NULL, FALSE);
683*e3feb2ccSEmilio Cota 
684*e3feb2ccSEmilio Cota     removed = q_tree_remove_internal(tree, key, FALSE);
685*e3feb2ccSEmilio Cota 
686*e3feb2ccSEmilio Cota #ifdef Q_TREE_DEBUG
687*e3feb2ccSEmilio Cota     q_tree_node_check(tree->root);
688*e3feb2ccSEmilio Cota #endif
689*e3feb2ccSEmilio Cota 
690*e3feb2ccSEmilio Cota     return removed;
691*e3feb2ccSEmilio Cota }
692*e3feb2ccSEmilio Cota 
693*e3feb2ccSEmilio Cota /**
694*e3feb2ccSEmilio Cota  * q_tree_steal:
695*e3feb2ccSEmilio Cota  * @tree: a #QTree
696*e3feb2ccSEmilio Cota  * @key: the key to remove
697*e3feb2ccSEmilio Cota  *
698*e3feb2ccSEmilio Cota  * Removes a key and its associated value from a #QTree without calling
699*e3feb2ccSEmilio Cota  * the key and value destroy functions.
700*e3feb2ccSEmilio Cota  *
701*e3feb2ccSEmilio Cota  * If the key does not exist in the #QTree, the function does nothing.
702*e3feb2ccSEmilio Cota  *
703*e3feb2ccSEmilio Cota  * Returns: %TRUE if the key was found (prior to 2.8, this function
704*e3feb2ccSEmilio Cota  *     returned nothing)
705*e3feb2ccSEmilio Cota  */
706*e3feb2ccSEmilio Cota gboolean
707*e3feb2ccSEmilio Cota q_tree_steal(QTree         *tree,
708*e3feb2ccSEmilio Cota              gconstpointer  key)
709*e3feb2ccSEmilio Cota {
710*e3feb2ccSEmilio Cota     gboolean removed;
711*e3feb2ccSEmilio Cota 
712*e3feb2ccSEmilio Cota     g_return_val_if_fail(tree != NULL, FALSE);
713*e3feb2ccSEmilio Cota 
714*e3feb2ccSEmilio Cota     removed = q_tree_remove_internal(tree, key, TRUE);
715*e3feb2ccSEmilio Cota 
716*e3feb2ccSEmilio Cota #ifdef Q_TREE_DEBUG
717*e3feb2ccSEmilio Cota     q_tree_node_check(tree->root);
718*e3feb2ccSEmilio Cota #endif
719*e3feb2ccSEmilio Cota 
720*e3feb2ccSEmilio Cota     return removed;
721*e3feb2ccSEmilio Cota }
722*e3feb2ccSEmilio Cota 
723*e3feb2ccSEmilio Cota /* internal remove routine */
724*e3feb2ccSEmilio Cota static gboolean
725*e3feb2ccSEmilio Cota q_tree_remove_internal(QTree         *tree,
726*e3feb2ccSEmilio Cota                        gconstpointer  key,
727*e3feb2ccSEmilio Cota                        gboolean       steal)
728*e3feb2ccSEmilio Cota {
729*e3feb2ccSEmilio Cota     QTreeNode *node, *parent, *balance;
730*e3feb2ccSEmilio Cota     QTreeNode *path[MAX_GTREE_HEIGHT];
731*e3feb2ccSEmilio Cota     int idx;
732*e3feb2ccSEmilio Cota     gboolean left_node;
733*e3feb2ccSEmilio Cota 
734*e3feb2ccSEmilio Cota     g_return_val_if_fail(tree != NULL, FALSE);
735*e3feb2ccSEmilio Cota 
736*e3feb2ccSEmilio Cota     if (!tree->root) {
737*e3feb2ccSEmilio Cota         return FALSE;
738*e3feb2ccSEmilio Cota     }
739*e3feb2ccSEmilio Cota 
740*e3feb2ccSEmilio Cota     idx = 0;
741*e3feb2ccSEmilio Cota     path[idx++] = NULL;
742*e3feb2ccSEmilio Cota     node = tree->root;
743*e3feb2ccSEmilio Cota 
744*e3feb2ccSEmilio Cota     while (1) {
745*e3feb2ccSEmilio Cota         int cmp = tree->key_compare(key, node->key, tree->key_compare_data);
746*e3feb2ccSEmilio Cota 
747*e3feb2ccSEmilio Cota         if (cmp == 0) {
748*e3feb2ccSEmilio Cota             break;
749*e3feb2ccSEmilio Cota         } else if (cmp < 0) {
750*e3feb2ccSEmilio Cota             if (!node->left_child) {
751*e3feb2ccSEmilio Cota                 return FALSE;
752*e3feb2ccSEmilio Cota             }
753*e3feb2ccSEmilio Cota 
754*e3feb2ccSEmilio Cota             path[idx++] = node;
755*e3feb2ccSEmilio Cota             node = node->left;
756*e3feb2ccSEmilio Cota         } else {
757*e3feb2ccSEmilio Cota             if (!node->right_child) {
758*e3feb2ccSEmilio Cota                 return FALSE;
759*e3feb2ccSEmilio Cota             }
760*e3feb2ccSEmilio Cota 
761*e3feb2ccSEmilio Cota             path[idx++] = node;
762*e3feb2ccSEmilio Cota             node = node->right;
763*e3feb2ccSEmilio Cota         }
764*e3feb2ccSEmilio Cota     }
765*e3feb2ccSEmilio Cota 
766*e3feb2ccSEmilio Cota     /*
767*e3feb2ccSEmilio Cota      * The following code is almost equal to q_tree_remove_node,
768*e3feb2ccSEmilio Cota      * except that we do not have to call q_tree_node_parent.
769*e3feb2ccSEmilio Cota      */
770*e3feb2ccSEmilio Cota     balance = parent = path[--idx];
771*e3feb2ccSEmilio Cota     g_assert(!parent || parent->left == node || parent->right == node);
772*e3feb2ccSEmilio Cota     left_node = (parent && node == parent->left);
773*e3feb2ccSEmilio Cota 
774*e3feb2ccSEmilio Cota     if (!node->left_child) {
775*e3feb2ccSEmilio Cota         if (!node->right_child) {
776*e3feb2ccSEmilio Cota             if (!parent) {
777*e3feb2ccSEmilio Cota                 tree->root = NULL;
778*e3feb2ccSEmilio Cota             } else if (left_node) {
779*e3feb2ccSEmilio Cota                 parent->left_child = FALSE;
780*e3feb2ccSEmilio Cota                 parent->left = node->left;
781*e3feb2ccSEmilio Cota                 parent->balance += 1;
782*e3feb2ccSEmilio Cota             } else {
783*e3feb2ccSEmilio Cota                 parent->right_child = FALSE;
784*e3feb2ccSEmilio Cota                 parent->right = node->right;
785*e3feb2ccSEmilio Cota                 parent->balance -= 1;
786*e3feb2ccSEmilio Cota             }
787*e3feb2ccSEmilio Cota         } else {
788*e3feb2ccSEmilio Cota             /* node has a right child */
789*e3feb2ccSEmilio Cota             QTreeNode *tmp = q_tree_node_next(node);
790*e3feb2ccSEmilio Cota             tmp->left = node->left;
791*e3feb2ccSEmilio Cota 
792*e3feb2ccSEmilio Cota             if (!parent) {
793*e3feb2ccSEmilio Cota                 tree->root = node->right;
794*e3feb2ccSEmilio Cota             } else if (left_node) {
795*e3feb2ccSEmilio Cota                 parent->left = node->right;
796*e3feb2ccSEmilio Cota                 parent->balance += 1;
797*e3feb2ccSEmilio Cota             } else {
798*e3feb2ccSEmilio Cota                 parent->right = node->right;
799*e3feb2ccSEmilio Cota                 parent->balance -= 1;
800*e3feb2ccSEmilio Cota             }
801*e3feb2ccSEmilio Cota         }
802*e3feb2ccSEmilio Cota     } else {
803*e3feb2ccSEmilio Cota         /* node has a left child */
804*e3feb2ccSEmilio Cota         if (!node->right_child) {
805*e3feb2ccSEmilio Cota             QTreeNode *tmp = q_tree_node_previous(node);
806*e3feb2ccSEmilio Cota             tmp->right = node->right;
807*e3feb2ccSEmilio Cota 
808*e3feb2ccSEmilio Cota             if (parent == NULL) {
809*e3feb2ccSEmilio Cota                 tree->root = node->left;
810*e3feb2ccSEmilio Cota             } else if (left_node) {
811*e3feb2ccSEmilio Cota                 parent->left = node->left;
812*e3feb2ccSEmilio Cota                 parent->balance += 1;
813*e3feb2ccSEmilio Cota             } else {
814*e3feb2ccSEmilio Cota                 parent->right = node->left;
815*e3feb2ccSEmilio Cota                 parent->balance -= 1;
816*e3feb2ccSEmilio Cota             }
817*e3feb2ccSEmilio Cota         } else {
818*e3feb2ccSEmilio Cota             /* node has a both children (pant, pant!) */
819*e3feb2ccSEmilio Cota             QTreeNode *prev = node->left;
820*e3feb2ccSEmilio Cota             QTreeNode *next = node->right;
821*e3feb2ccSEmilio Cota             QTreeNode *nextp = node;
822*e3feb2ccSEmilio Cota             int old_idx = idx + 1;
823*e3feb2ccSEmilio Cota             idx++;
824*e3feb2ccSEmilio Cota 
825*e3feb2ccSEmilio Cota             /* path[idx] == parent */
826*e3feb2ccSEmilio Cota             /* find the immediately next node (and its parent) */
827*e3feb2ccSEmilio Cota             while (next->left_child) {
828*e3feb2ccSEmilio Cota                 path[++idx] = nextp = next;
829*e3feb2ccSEmilio Cota                 next = next->left;
830*e3feb2ccSEmilio Cota             }
831*e3feb2ccSEmilio Cota 
832*e3feb2ccSEmilio Cota             path[old_idx] = next;
833*e3feb2ccSEmilio Cota             balance = path[idx];
834*e3feb2ccSEmilio Cota 
835*e3feb2ccSEmilio Cota             /* remove 'next' from the tree */
836*e3feb2ccSEmilio Cota             if (nextp != node) {
837*e3feb2ccSEmilio Cota                 if (next->right_child) {
838*e3feb2ccSEmilio Cota                     nextp->left = next->right;
839*e3feb2ccSEmilio Cota                 } else {
840*e3feb2ccSEmilio Cota                     nextp->left_child = FALSE;
841*e3feb2ccSEmilio Cota                 }
842*e3feb2ccSEmilio Cota                 nextp->balance += 1;
843*e3feb2ccSEmilio Cota 
844*e3feb2ccSEmilio Cota                 next->right_child = TRUE;
845*e3feb2ccSEmilio Cota                 next->right = node->right;
846*e3feb2ccSEmilio Cota             } else {
847*e3feb2ccSEmilio Cota                 node->balance -= 1;
848*e3feb2ccSEmilio Cota             }
849*e3feb2ccSEmilio Cota 
850*e3feb2ccSEmilio Cota             /* set the prev to point to the right place */
851*e3feb2ccSEmilio Cota             while (prev->right_child) {
852*e3feb2ccSEmilio Cota                 prev = prev->right;
853*e3feb2ccSEmilio Cota             }
854*e3feb2ccSEmilio Cota             prev->right = next;
855*e3feb2ccSEmilio Cota 
856*e3feb2ccSEmilio Cota             /* prepare 'next' to replace 'node' */
857*e3feb2ccSEmilio Cota             next->left_child = TRUE;
858*e3feb2ccSEmilio Cota             next->left = node->left;
859*e3feb2ccSEmilio Cota             next->balance = node->balance;
860*e3feb2ccSEmilio Cota 
861*e3feb2ccSEmilio Cota             if (!parent) {
862*e3feb2ccSEmilio Cota                 tree->root = next;
863*e3feb2ccSEmilio Cota             } else if (left_node) {
864*e3feb2ccSEmilio Cota                 parent->left = next;
865*e3feb2ccSEmilio Cota             } else {
866*e3feb2ccSEmilio Cota                 parent->right = next;
867*e3feb2ccSEmilio Cota             }
868*e3feb2ccSEmilio Cota         }
869*e3feb2ccSEmilio Cota     }
870*e3feb2ccSEmilio Cota 
871*e3feb2ccSEmilio Cota     /* restore balance */
872*e3feb2ccSEmilio Cota     if (balance) {
873*e3feb2ccSEmilio Cota         while (1) {
874*e3feb2ccSEmilio Cota             QTreeNode *bparent = path[--idx];
875*e3feb2ccSEmilio Cota             g_assert(!bparent ||
876*e3feb2ccSEmilio Cota                      bparent->left == balance ||
877*e3feb2ccSEmilio Cota                      bparent->right == balance);
878*e3feb2ccSEmilio Cota             left_node = (bparent && balance == bparent->left);
879*e3feb2ccSEmilio Cota 
880*e3feb2ccSEmilio Cota             if (balance->balance < -1 || balance->balance > 1) {
881*e3feb2ccSEmilio Cota                 balance = q_tree_node_balance(balance);
882*e3feb2ccSEmilio Cota                 if (!bparent) {
883*e3feb2ccSEmilio Cota                     tree->root = balance;
884*e3feb2ccSEmilio Cota                 } else if (left_node) {
885*e3feb2ccSEmilio Cota                     bparent->left = balance;
886*e3feb2ccSEmilio Cota                 } else {
887*e3feb2ccSEmilio Cota                     bparent->right = balance;
888*e3feb2ccSEmilio Cota                 }
889*e3feb2ccSEmilio Cota             }
890*e3feb2ccSEmilio Cota 
891*e3feb2ccSEmilio Cota             if (balance->balance != 0 || !bparent) {
892*e3feb2ccSEmilio Cota                 break;
893*e3feb2ccSEmilio Cota             }
894*e3feb2ccSEmilio Cota 
895*e3feb2ccSEmilio Cota             if (left_node) {
896*e3feb2ccSEmilio Cota                 bparent->balance += 1;
897*e3feb2ccSEmilio Cota             } else {
898*e3feb2ccSEmilio Cota                 bparent->balance -= 1;
899*e3feb2ccSEmilio Cota             }
900*e3feb2ccSEmilio Cota 
901*e3feb2ccSEmilio Cota             balance = bparent;
902*e3feb2ccSEmilio Cota         }
903*e3feb2ccSEmilio Cota     }
904*e3feb2ccSEmilio Cota 
905*e3feb2ccSEmilio Cota     if (!steal) {
906*e3feb2ccSEmilio Cota         if (tree->key_destroy_func) {
907*e3feb2ccSEmilio Cota             tree->key_destroy_func(node->key);
908*e3feb2ccSEmilio Cota         }
909*e3feb2ccSEmilio Cota         if (tree->value_destroy_func) {
910*e3feb2ccSEmilio Cota             tree->value_destroy_func(node->value);
911*e3feb2ccSEmilio Cota         }
912*e3feb2ccSEmilio Cota     }
913*e3feb2ccSEmilio Cota 
914*e3feb2ccSEmilio Cota     g_free(node);
915*e3feb2ccSEmilio Cota 
916*e3feb2ccSEmilio Cota     tree->nnodes--;
917*e3feb2ccSEmilio Cota 
918*e3feb2ccSEmilio Cota     return TRUE;
919*e3feb2ccSEmilio Cota }
920*e3feb2ccSEmilio Cota 
921*e3feb2ccSEmilio Cota /**
922*e3feb2ccSEmilio Cota  * q_tree_lookup_node:
923*e3feb2ccSEmilio Cota  * @tree: a #QTree
924*e3feb2ccSEmilio Cota  * @key: the key to look up
925*e3feb2ccSEmilio Cota  *
926*e3feb2ccSEmilio Cota  * Gets the tree node corresponding to the given key. Since a #QTree is
927*e3feb2ccSEmilio Cota  * automatically balanced as key/value pairs are added, key lookup
928*e3feb2ccSEmilio Cota  * is O(log n) (where n is the number of key/value pairs in the tree).
929*e3feb2ccSEmilio Cota  *
930*e3feb2ccSEmilio Cota  * Returns: (nullable) (transfer none): the tree node corresponding to
931*e3feb2ccSEmilio Cota  *          the key, or %NULL if the key was not found
932*e3feb2ccSEmilio Cota  *
933*e3feb2ccSEmilio Cota  * Since: 2.68 in GLib. Internal in Qtree, i.e. not in the public API.
934*e3feb2ccSEmilio Cota  */
935*e3feb2ccSEmilio Cota static QTreeNode *
936*e3feb2ccSEmilio Cota q_tree_lookup_node(QTree         *tree,
937*e3feb2ccSEmilio Cota                    gconstpointer  key)
938*e3feb2ccSEmilio Cota {
939*e3feb2ccSEmilio Cota     g_return_val_if_fail(tree != NULL, NULL);
940*e3feb2ccSEmilio Cota 
941*e3feb2ccSEmilio Cota     return q_tree_find_node(tree, key);
942*e3feb2ccSEmilio Cota }
943*e3feb2ccSEmilio Cota 
944*e3feb2ccSEmilio Cota /**
945*e3feb2ccSEmilio Cota  * q_tree_lookup:
946*e3feb2ccSEmilio Cota  * @tree: a #QTree
947*e3feb2ccSEmilio Cota  * @key: the key to look up
948*e3feb2ccSEmilio Cota  *
949*e3feb2ccSEmilio Cota  * Gets the value corresponding to the given key. Since a #QTree is
950*e3feb2ccSEmilio Cota  * automatically balanced as key/value pairs are added, key lookup
951*e3feb2ccSEmilio Cota  * is O(log n) (where n is the number of key/value pairs in the tree).
952*e3feb2ccSEmilio Cota  *
953*e3feb2ccSEmilio Cota  * Returns: the value corresponding to the key, or %NULL
954*e3feb2ccSEmilio Cota  *     if the key was not found
955*e3feb2ccSEmilio Cota  */
956*e3feb2ccSEmilio Cota gpointer
957*e3feb2ccSEmilio Cota q_tree_lookup(QTree         *tree,
958*e3feb2ccSEmilio Cota               gconstpointer  key)
959*e3feb2ccSEmilio Cota {
960*e3feb2ccSEmilio Cota     QTreeNode *node;
961*e3feb2ccSEmilio Cota 
962*e3feb2ccSEmilio Cota     node = q_tree_lookup_node(tree, key);
963*e3feb2ccSEmilio Cota 
964*e3feb2ccSEmilio Cota     return node ? node->value : NULL;
965*e3feb2ccSEmilio Cota }
966*e3feb2ccSEmilio Cota 
967*e3feb2ccSEmilio Cota /**
968*e3feb2ccSEmilio Cota  * q_tree_lookup_extended:
969*e3feb2ccSEmilio Cota  * @tree: a #QTree
970*e3feb2ccSEmilio Cota  * @lookup_key: the key to look up
971*e3feb2ccSEmilio Cota  * @orig_key: (out) (optional) (nullable): returns the original key
972*e3feb2ccSEmilio Cota  * @value: (out) (optional) (nullable): returns the value associated with
973*e3feb2ccSEmilio Cota  *         the key
974*e3feb2ccSEmilio Cota  *
975*e3feb2ccSEmilio Cota  * Looks up a key in the #QTree, returning the original key and the
976*e3feb2ccSEmilio Cota  * associated value. This is useful if you need to free the memory
977*e3feb2ccSEmilio Cota  * allocated for the original key, for example before calling
978*e3feb2ccSEmilio Cota  * q_tree_remove().
979*e3feb2ccSEmilio Cota  *
980*e3feb2ccSEmilio Cota  * Returns: %TRUE if the key was found in the #QTree
981*e3feb2ccSEmilio Cota  */
982*e3feb2ccSEmilio Cota gboolean
983*e3feb2ccSEmilio Cota q_tree_lookup_extended(QTree         *tree,
984*e3feb2ccSEmilio Cota                        gconstpointer  lookup_key,
985*e3feb2ccSEmilio Cota                        gpointer      *orig_key,
986*e3feb2ccSEmilio Cota                        gpointer      *value)
987*e3feb2ccSEmilio Cota {
988*e3feb2ccSEmilio Cota     QTreeNode *node;
989*e3feb2ccSEmilio Cota 
990*e3feb2ccSEmilio Cota     g_return_val_if_fail(tree != NULL, FALSE);
991*e3feb2ccSEmilio Cota 
992*e3feb2ccSEmilio Cota     node = q_tree_find_node(tree, lookup_key);
993*e3feb2ccSEmilio Cota 
994*e3feb2ccSEmilio Cota     if (node) {
995*e3feb2ccSEmilio Cota         if (orig_key) {
996*e3feb2ccSEmilio Cota             *orig_key = node->key;
997*e3feb2ccSEmilio Cota         }
998*e3feb2ccSEmilio Cota         if (value) {
999*e3feb2ccSEmilio Cota             *value = node->value;
1000*e3feb2ccSEmilio Cota         }
1001*e3feb2ccSEmilio Cota         return TRUE;
1002*e3feb2ccSEmilio Cota     } else {
1003*e3feb2ccSEmilio Cota         return FALSE;
1004*e3feb2ccSEmilio Cota     }
1005*e3feb2ccSEmilio Cota }
1006*e3feb2ccSEmilio Cota 
1007*e3feb2ccSEmilio Cota /**
1008*e3feb2ccSEmilio Cota  * q_tree_foreach:
1009*e3feb2ccSEmilio Cota  * @tree: a #QTree
1010*e3feb2ccSEmilio Cota  * @func: the function to call for each node visited.
1011*e3feb2ccSEmilio Cota  *     If this function returns %TRUE, the traversal is stopped.
1012*e3feb2ccSEmilio Cota  * @user_data: user data to pass to the function
1013*e3feb2ccSEmilio Cota  *
1014*e3feb2ccSEmilio Cota  * Calls the given function for each of the key/value pairs in the #QTree.
1015*e3feb2ccSEmilio Cota  * The function is passed the key and value of each pair, and the given
1016*e3feb2ccSEmilio Cota  * @data parameter. The tree is traversed in sorted order.
1017*e3feb2ccSEmilio Cota  *
1018*e3feb2ccSEmilio Cota  * The tree may not be modified while iterating over it (you can't
1019*e3feb2ccSEmilio Cota  * add/remove items). To remove all items matching a predicate, you need
1020*e3feb2ccSEmilio Cota  * to add each item to a list in your #GTraverseFunc as you walk over
1021*e3feb2ccSEmilio Cota  * the tree, then walk the list and remove each item.
1022*e3feb2ccSEmilio Cota  */
1023*e3feb2ccSEmilio Cota void
1024*e3feb2ccSEmilio Cota q_tree_foreach(QTree         *tree,
1025*e3feb2ccSEmilio Cota                GTraverseFunc  func,
1026*e3feb2ccSEmilio Cota                gpointer       user_data)
1027*e3feb2ccSEmilio Cota {
1028*e3feb2ccSEmilio Cota     QTreeNode *node;
1029*e3feb2ccSEmilio Cota 
1030*e3feb2ccSEmilio Cota     g_return_if_fail(tree != NULL);
1031*e3feb2ccSEmilio Cota 
1032*e3feb2ccSEmilio Cota     if (!tree->root) {
1033*e3feb2ccSEmilio Cota         return;
1034*e3feb2ccSEmilio Cota     }
1035*e3feb2ccSEmilio Cota 
1036*e3feb2ccSEmilio Cota     node = q_tree_node_first(tree);
1037*e3feb2ccSEmilio Cota 
1038*e3feb2ccSEmilio Cota     while (node) {
1039*e3feb2ccSEmilio Cota         if ((*func)(node->key, node->value, user_data)) {
1040*e3feb2ccSEmilio Cota             break;
1041*e3feb2ccSEmilio Cota         }
1042*e3feb2ccSEmilio Cota 
1043*e3feb2ccSEmilio Cota         node = q_tree_node_next(node);
1044*e3feb2ccSEmilio Cota     }
1045*e3feb2ccSEmilio Cota }
1046*e3feb2ccSEmilio Cota 
1047*e3feb2ccSEmilio Cota /**
1048*e3feb2ccSEmilio Cota  * q_tree_search_node:
1049*e3feb2ccSEmilio Cota  * @tree: a #QTree
1050*e3feb2ccSEmilio Cota  * @search_func: a function used to search the #QTree
1051*e3feb2ccSEmilio Cota  * @user_data: the data passed as the second argument to @search_func
1052*e3feb2ccSEmilio Cota  *
1053*e3feb2ccSEmilio Cota  * Searches a #QTree using @search_func.
1054*e3feb2ccSEmilio Cota  *
1055*e3feb2ccSEmilio Cota  * The @search_func is called with a pointer to the key of a key/value
1056*e3feb2ccSEmilio Cota  * pair in the tree, and the passed in @user_data. If @search_func returns
1057*e3feb2ccSEmilio Cota  * 0 for a key/value pair, then the corresponding node is returned as
1058*e3feb2ccSEmilio Cota  * the result of q_tree_search(). If @search_func returns -1, searching
1059*e3feb2ccSEmilio Cota  * will proceed among the key/value pairs that have a smaller key; if
1060*e3feb2ccSEmilio Cota  * @search_func returns 1, searching will proceed among the key/value
1061*e3feb2ccSEmilio Cota  * pairs that have a larger key.
1062*e3feb2ccSEmilio Cota  *
1063*e3feb2ccSEmilio Cota  * Returns: (nullable) (transfer none): the node corresponding to the
1064*e3feb2ccSEmilio Cota  *          found key, or %NULL if the key was not found
1065*e3feb2ccSEmilio Cota  *
1066*e3feb2ccSEmilio Cota  * Since: 2.68 in GLib. Internal in Qtree, i.e. not in the public API.
1067*e3feb2ccSEmilio Cota  */
1068*e3feb2ccSEmilio Cota static QTreeNode *
1069*e3feb2ccSEmilio Cota q_tree_search_node(QTree         *tree,
1070*e3feb2ccSEmilio Cota                    GCompareFunc   search_func,
1071*e3feb2ccSEmilio Cota                    gconstpointer  user_data)
1072*e3feb2ccSEmilio Cota {
1073*e3feb2ccSEmilio Cota     g_return_val_if_fail(tree != NULL, NULL);
1074*e3feb2ccSEmilio Cota 
1075*e3feb2ccSEmilio Cota     if (!tree->root) {
1076*e3feb2ccSEmilio Cota         return NULL;
1077*e3feb2ccSEmilio Cota     }
1078*e3feb2ccSEmilio Cota 
1079*e3feb2ccSEmilio Cota     return q_tree_node_search(tree->root, search_func, user_data);
1080*e3feb2ccSEmilio Cota }
1081*e3feb2ccSEmilio Cota 
1082*e3feb2ccSEmilio Cota /**
1083*e3feb2ccSEmilio Cota  * q_tree_search:
1084*e3feb2ccSEmilio Cota  * @tree: a #QTree
1085*e3feb2ccSEmilio Cota  * @search_func: a function used to search the #QTree
1086*e3feb2ccSEmilio Cota  * @user_data: the data passed as the second argument to @search_func
1087*e3feb2ccSEmilio Cota  *
1088*e3feb2ccSEmilio Cota  * Searches a #QTree using @search_func.
1089*e3feb2ccSEmilio Cota  *
1090*e3feb2ccSEmilio Cota  * The @search_func is called with a pointer to the key of a key/value
1091*e3feb2ccSEmilio Cota  * pair in the tree, and the passed in @user_data. If @search_func returns
1092*e3feb2ccSEmilio Cota  * 0 for a key/value pair, then the corresponding value is returned as
1093*e3feb2ccSEmilio Cota  * the result of q_tree_search(). If @search_func returns -1, searching
1094*e3feb2ccSEmilio Cota  * will proceed among the key/value pairs that have a smaller key; if
1095*e3feb2ccSEmilio Cota  * @search_func returns 1, searching will proceed among the key/value
1096*e3feb2ccSEmilio Cota  * pairs that have a larger key.
1097*e3feb2ccSEmilio Cota  *
1098*e3feb2ccSEmilio Cota  * Returns: the value corresponding to the found key, or %NULL
1099*e3feb2ccSEmilio Cota  *     if the key was not found
1100*e3feb2ccSEmilio Cota  */
1101*e3feb2ccSEmilio Cota gpointer
1102*e3feb2ccSEmilio Cota q_tree_search(QTree         *tree,
1103*e3feb2ccSEmilio Cota               GCompareFunc   search_func,
1104*e3feb2ccSEmilio Cota               gconstpointer  user_data)
1105*e3feb2ccSEmilio Cota {
1106*e3feb2ccSEmilio Cota     QTreeNode *node;
1107*e3feb2ccSEmilio Cota 
1108*e3feb2ccSEmilio Cota     node = q_tree_search_node(tree, search_func, user_data);
1109*e3feb2ccSEmilio Cota 
1110*e3feb2ccSEmilio Cota     return node ? node->value : NULL;
1111*e3feb2ccSEmilio Cota }
1112*e3feb2ccSEmilio Cota 
1113*e3feb2ccSEmilio Cota /**
1114*e3feb2ccSEmilio Cota  * q_tree_height:
1115*e3feb2ccSEmilio Cota  * @tree: a #QTree
1116*e3feb2ccSEmilio Cota  *
1117*e3feb2ccSEmilio Cota  * Gets the height of a #QTree.
1118*e3feb2ccSEmilio Cota  *
1119*e3feb2ccSEmilio Cota  * If the #QTree contains no nodes, the height is 0.
1120*e3feb2ccSEmilio Cota  * If the #QTree contains only one root node the height is 1.
1121*e3feb2ccSEmilio Cota  * If the root node has children the height is 2, etc.
1122*e3feb2ccSEmilio Cota  *
1123*e3feb2ccSEmilio Cota  * Returns: the height of @tree
1124*e3feb2ccSEmilio Cota  */
1125*e3feb2ccSEmilio Cota gint
1126*e3feb2ccSEmilio Cota q_tree_height(QTree *tree)
1127*e3feb2ccSEmilio Cota {
1128*e3feb2ccSEmilio Cota     QTreeNode *node;
1129*e3feb2ccSEmilio Cota     gint height;
1130*e3feb2ccSEmilio Cota 
1131*e3feb2ccSEmilio Cota     g_return_val_if_fail(tree != NULL, 0);
1132*e3feb2ccSEmilio Cota 
1133*e3feb2ccSEmilio Cota     if (!tree->root) {
1134*e3feb2ccSEmilio Cota         return 0;
1135*e3feb2ccSEmilio Cota     }
1136*e3feb2ccSEmilio Cota 
1137*e3feb2ccSEmilio Cota     height = 0;
1138*e3feb2ccSEmilio Cota     node = tree->root;
1139*e3feb2ccSEmilio Cota 
1140*e3feb2ccSEmilio Cota     while (1) {
1141*e3feb2ccSEmilio Cota         height += 1 + MAX(node->balance, 0);
1142*e3feb2ccSEmilio Cota 
1143*e3feb2ccSEmilio Cota         if (!node->left_child) {
1144*e3feb2ccSEmilio Cota             return height;
1145*e3feb2ccSEmilio Cota         }
1146*e3feb2ccSEmilio Cota 
1147*e3feb2ccSEmilio Cota         node = node->left;
1148*e3feb2ccSEmilio Cota     }
1149*e3feb2ccSEmilio Cota }
1150*e3feb2ccSEmilio Cota 
1151*e3feb2ccSEmilio Cota /**
1152*e3feb2ccSEmilio Cota  * q_tree_nnodes:
1153*e3feb2ccSEmilio Cota  * @tree: a #QTree
1154*e3feb2ccSEmilio Cota  *
1155*e3feb2ccSEmilio Cota  * Gets the number of nodes in a #QTree.
1156*e3feb2ccSEmilio Cota  *
1157*e3feb2ccSEmilio Cota  * Returns: the number of nodes in @tree
1158*e3feb2ccSEmilio Cota  */
1159*e3feb2ccSEmilio Cota gint
1160*e3feb2ccSEmilio Cota q_tree_nnodes(QTree *tree)
1161*e3feb2ccSEmilio Cota {
1162*e3feb2ccSEmilio Cota     g_return_val_if_fail(tree != NULL, 0);
1163*e3feb2ccSEmilio Cota 
1164*e3feb2ccSEmilio Cota     return tree->nnodes;
1165*e3feb2ccSEmilio Cota }
1166*e3feb2ccSEmilio Cota 
1167*e3feb2ccSEmilio Cota static QTreeNode *
1168*e3feb2ccSEmilio Cota q_tree_node_balance(QTreeNode *node)
1169*e3feb2ccSEmilio Cota {
1170*e3feb2ccSEmilio Cota     if (node->balance < -1) {
1171*e3feb2ccSEmilio Cota         if (node->left->balance > 0) {
1172*e3feb2ccSEmilio Cota             node->left = q_tree_node_rotate_left(node->left);
1173*e3feb2ccSEmilio Cota         }
1174*e3feb2ccSEmilio Cota         node = q_tree_node_rotate_right(node);
1175*e3feb2ccSEmilio Cota     } else if (node->balance > 1) {
1176*e3feb2ccSEmilio Cota         if (node->right->balance < 0) {
1177*e3feb2ccSEmilio Cota             node->right = q_tree_node_rotate_right(node->right);
1178*e3feb2ccSEmilio Cota         }
1179*e3feb2ccSEmilio Cota         node = q_tree_node_rotate_left(node);
1180*e3feb2ccSEmilio Cota     }
1181*e3feb2ccSEmilio Cota 
1182*e3feb2ccSEmilio Cota     return node;
1183*e3feb2ccSEmilio Cota }
1184*e3feb2ccSEmilio Cota 
1185*e3feb2ccSEmilio Cota static QTreeNode *
1186*e3feb2ccSEmilio Cota q_tree_find_node(QTree        *tree,
1187*e3feb2ccSEmilio Cota                  gconstpointer key)
1188*e3feb2ccSEmilio Cota {
1189*e3feb2ccSEmilio Cota     QTreeNode *node;
1190*e3feb2ccSEmilio Cota     gint cmp;
1191*e3feb2ccSEmilio Cota 
1192*e3feb2ccSEmilio Cota     node = tree->root;
1193*e3feb2ccSEmilio Cota     if (!node) {
1194*e3feb2ccSEmilio Cota         return NULL;
1195*e3feb2ccSEmilio Cota     }
1196*e3feb2ccSEmilio Cota 
1197*e3feb2ccSEmilio Cota     while (1) {
1198*e3feb2ccSEmilio Cota         cmp = tree->key_compare(key, node->key, tree->key_compare_data);
1199*e3feb2ccSEmilio Cota         if (cmp == 0) {
1200*e3feb2ccSEmilio Cota             return node;
1201*e3feb2ccSEmilio Cota         } else if (cmp < 0) {
1202*e3feb2ccSEmilio Cota             if (!node->left_child) {
1203*e3feb2ccSEmilio Cota                 return NULL;
1204*e3feb2ccSEmilio Cota             }
1205*e3feb2ccSEmilio Cota 
1206*e3feb2ccSEmilio Cota             node = node->left;
1207*e3feb2ccSEmilio Cota         } else {
1208*e3feb2ccSEmilio Cota             if (!node->right_child) {
1209*e3feb2ccSEmilio Cota                 return NULL;
1210*e3feb2ccSEmilio Cota             }
1211*e3feb2ccSEmilio Cota 
1212*e3feb2ccSEmilio Cota             node = node->right;
1213*e3feb2ccSEmilio Cota         }
1214*e3feb2ccSEmilio Cota     }
1215*e3feb2ccSEmilio Cota }
1216*e3feb2ccSEmilio Cota 
1217*e3feb2ccSEmilio Cota static QTreeNode *
1218*e3feb2ccSEmilio Cota q_tree_node_search(QTreeNode     *node,
1219*e3feb2ccSEmilio Cota                    GCompareFunc   search_func,
1220*e3feb2ccSEmilio Cota                    gconstpointer  data)
1221*e3feb2ccSEmilio Cota {
1222*e3feb2ccSEmilio Cota     gint dir;
1223*e3feb2ccSEmilio Cota 
1224*e3feb2ccSEmilio Cota     if (!node) {
1225*e3feb2ccSEmilio Cota         return NULL;
1226*e3feb2ccSEmilio Cota     }
1227*e3feb2ccSEmilio Cota 
1228*e3feb2ccSEmilio Cota     while (1) {
1229*e3feb2ccSEmilio Cota         dir = (*search_func)(node->key, data);
1230*e3feb2ccSEmilio Cota         if (dir == 0) {
1231*e3feb2ccSEmilio Cota             return node;
1232*e3feb2ccSEmilio Cota         } else if (dir < 0) {
1233*e3feb2ccSEmilio Cota             if (!node->left_child) {
1234*e3feb2ccSEmilio Cota                 return NULL;
1235*e3feb2ccSEmilio Cota             }
1236*e3feb2ccSEmilio Cota 
1237*e3feb2ccSEmilio Cota             node = node->left;
1238*e3feb2ccSEmilio Cota         } else {
1239*e3feb2ccSEmilio Cota             if (!node->right_child) {
1240*e3feb2ccSEmilio Cota                 return NULL;
1241*e3feb2ccSEmilio Cota             }
1242*e3feb2ccSEmilio Cota 
1243*e3feb2ccSEmilio Cota             node = node->right;
1244*e3feb2ccSEmilio Cota         }
1245*e3feb2ccSEmilio Cota     }
1246*e3feb2ccSEmilio Cota }
1247*e3feb2ccSEmilio Cota 
1248*e3feb2ccSEmilio Cota static QTreeNode *
1249*e3feb2ccSEmilio Cota q_tree_node_rotate_left(QTreeNode *node)
1250*e3feb2ccSEmilio Cota {
1251*e3feb2ccSEmilio Cota     QTreeNode *right;
1252*e3feb2ccSEmilio Cota     gint a_bal;
1253*e3feb2ccSEmilio Cota     gint b_bal;
1254*e3feb2ccSEmilio Cota 
1255*e3feb2ccSEmilio Cota     right = node->right;
1256*e3feb2ccSEmilio Cota 
1257*e3feb2ccSEmilio Cota     if (right->left_child) {
1258*e3feb2ccSEmilio Cota         node->right = right->left;
1259*e3feb2ccSEmilio Cota     } else {
1260*e3feb2ccSEmilio Cota         node->right_child = FALSE;
1261*e3feb2ccSEmilio Cota         right->left_child = TRUE;
1262*e3feb2ccSEmilio Cota     }
1263*e3feb2ccSEmilio Cota     right->left = node;
1264*e3feb2ccSEmilio Cota 
1265*e3feb2ccSEmilio Cota     a_bal = node->balance;
1266*e3feb2ccSEmilio Cota     b_bal = right->balance;
1267*e3feb2ccSEmilio Cota 
1268*e3feb2ccSEmilio Cota     if (b_bal <= 0) {
1269*e3feb2ccSEmilio Cota         if (a_bal >= 1) {
1270*e3feb2ccSEmilio Cota             right->balance = b_bal - 1;
1271*e3feb2ccSEmilio Cota         } else {
1272*e3feb2ccSEmilio Cota             right->balance = a_bal + b_bal - 2;
1273*e3feb2ccSEmilio Cota         }
1274*e3feb2ccSEmilio Cota         node->balance = a_bal - 1;
1275*e3feb2ccSEmilio Cota     } else {
1276*e3feb2ccSEmilio Cota         if (a_bal <= b_bal) {
1277*e3feb2ccSEmilio Cota             right->balance = a_bal - 2;
1278*e3feb2ccSEmilio Cota         } else {
1279*e3feb2ccSEmilio Cota             right->balance = b_bal - 1;
1280*e3feb2ccSEmilio Cota         }
1281*e3feb2ccSEmilio Cota         node->balance = a_bal - b_bal - 1;
1282*e3feb2ccSEmilio Cota     }
1283*e3feb2ccSEmilio Cota 
1284*e3feb2ccSEmilio Cota     return right;
1285*e3feb2ccSEmilio Cota }
1286*e3feb2ccSEmilio Cota 
1287*e3feb2ccSEmilio Cota static QTreeNode *
1288*e3feb2ccSEmilio Cota q_tree_node_rotate_right(QTreeNode *node)
1289*e3feb2ccSEmilio Cota {
1290*e3feb2ccSEmilio Cota     QTreeNode *left;
1291*e3feb2ccSEmilio Cota     gint a_bal;
1292*e3feb2ccSEmilio Cota     gint b_bal;
1293*e3feb2ccSEmilio Cota 
1294*e3feb2ccSEmilio Cota     left = node->left;
1295*e3feb2ccSEmilio Cota 
1296*e3feb2ccSEmilio Cota     if (left->right_child) {
1297*e3feb2ccSEmilio Cota         node->left = left->right;
1298*e3feb2ccSEmilio Cota     } else {
1299*e3feb2ccSEmilio Cota         node->left_child = FALSE;
1300*e3feb2ccSEmilio Cota         left->right_child = TRUE;
1301*e3feb2ccSEmilio Cota     }
1302*e3feb2ccSEmilio Cota     left->right = node;
1303*e3feb2ccSEmilio Cota 
1304*e3feb2ccSEmilio Cota     a_bal = node->balance;
1305*e3feb2ccSEmilio Cota     b_bal = left->balance;
1306*e3feb2ccSEmilio Cota 
1307*e3feb2ccSEmilio Cota     if (b_bal <= 0) {
1308*e3feb2ccSEmilio Cota         if (b_bal > a_bal) {
1309*e3feb2ccSEmilio Cota             left->balance = b_bal + 1;
1310*e3feb2ccSEmilio Cota         } else {
1311*e3feb2ccSEmilio Cota             left->balance = a_bal + 2;
1312*e3feb2ccSEmilio Cota         }
1313*e3feb2ccSEmilio Cota         node->balance = a_bal - b_bal + 1;
1314*e3feb2ccSEmilio Cota     } else {
1315*e3feb2ccSEmilio Cota         if (a_bal <= -1) {
1316*e3feb2ccSEmilio Cota             left->balance = b_bal + 1;
1317*e3feb2ccSEmilio Cota         } else {
1318*e3feb2ccSEmilio Cota             left->balance = a_bal + b_bal + 2;
1319*e3feb2ccSEmilio Cota         }
1320*e3feb2ccSEmilio Cota         node->balance = a_bal + 1;
1321*e3feb2ccSEmilio Cota     }
1322*e3feb2ccSEmilio Cota 
1323*e3feb2ccSEmilio Cota     return left;
1324*e3feb2ccSEmilio Cota }
1325*e3feb2ccSEmilio Cota 
1326*e3feb2ccSEmilio Cota #ifdef Q_TREE_DEBUG
1327*e3feb2ccSEmilio Cota static gint
1328*e3feb2ccSEmilio Cota q_tree_node_height(QTreeNode *node)
1329*e3feb2ccSEmilio Cota {
1330*e3feb2ccSEmilio Cota     gint left_height;
1331*e3feb2ccSEmilio Cota     gint right_height;
1332*e3feb2ccSEmilio Cota 
1333*e3feb2ccSEmilio Cota     if (node) {
1334*e3feb2ccSEmilio Cota         left_height = 0;
1335*e3feb2ccSEmilio Cota         right_height = 0;
1336*e3feb2ccSEmilio Cota 
1337*e3feb2ccSEmilio Cota         if (node->left_child) {
1338*e3feb2ccSEmilio Cota             left_height = q_tree_node_height(node->left);
1339*e3feb2ccSEmilio Cota         }
1340*e3feb2ccSEmilio Cota 
1341*e3feb2ccSEmilio Cota         if (node->right_child) {
1342*e3feb2ccSEmilio Cota             right_height = q_tree_node_height(node->right);
1343*e3feb2ccSEmilio Cota         }
1344*e3feb2ccSEmilio Cota 
1345*e3feb2ccSEmilio Cota         return MAX(left_height, right_height) + 1;
1346*e3feb2ccSEmilio Cota     }
1347*e3feb2ccSEmilio Cota 
1348*e3feb2ccSEmilio Cota     return 0;
1349*e3feb2ccSEmilio Cota }
1350*e3feb2ccSEmilio Cota 
1351*e3feb2ccSEmilio Cota static void q_tree_node_check(QTreeNode *node)
1352*e3feb2ccSEmilio Cota {
1353*e3feb2ccSEmilio Cota     gint left_height;
1354*e3feb2ccSEmilio Cota     gint right_height;
1355*e3feb2ccSEmilio Cota     gint balance;
1356*e3feb2ccSEmilio Cota     QTreeNode *tmp;
1357*e3feb2ccSEmilio Cota 
1358*e3feb2ccSEmilio Cota     if (node) {
1359*e3feb2ccSEmilio Cota         if (node->left_child) {
1360*e3feb2ccSEmilio Cota             tmp = q_tree_node_previous(node);
1361*e3feb2ccSEmilio Cota             g_assert(tmp->right == node);
1362*e3feb2ccSEmilio Cota         }
1363*e3feb2ccSEmilio Cota 
1364*e3feb2ccSEmilio Cota         if (node->right_child) {
1365*e3feb2ccSEmilio Cota             tmp = q_tree_node_next(node);
1366*e3feb2ccSEmilio Cota             g_assert(tmp->left == node);
1367*e3feb2ccSEmilio Cota         }
1368*e3feb2ccSEmilio Cota 
1369*e3feb2ccSEmilio Cota         left_height = 0;
1370*e3feb2ccSEmilio Cota         right_height = 0;
1371*e3feb2ccSEmilio Cota 
1372*e3feb2ccSEmilio Cota         if (node->left_child) {
1373*e3feb2ccSEmilio Cota             left_height = q_tree_node_height(node->left);
1374*e3feb2ccSEmilio Cota         }
1375*e3feb2ccSEmilio Cota         if (node->right_child) {
1376*e3feb2ccSEmilio Cota             right_height = q_tree_node_height(node->right);
1377*e3feb2ccSEmilio Cota         }
1378*e3feb2ccSEmilio Cota 
1379*e3feb2ccSEmilio Cota         balance = right_height - left_height;
1380*e3feb2ccSEmilio Cota         g_assert(balance == node->balance);
1381*e3feb2ccSEmilio Cota 
1382*e3feb2ccSEmilio Cota         if (node->left_child) {
1383*e3feb2ccSEmilio Cota             q_tree_node_check(node->left);
1384*e3feb2ccSEmilio Cota         }
1385*e3feb2ccSEmilio Cota         if (node->right_child) {
1386*e3feb2ccSEmilio Cota             q_tree_node_check(node->right);
1387*e3feb2ccSEmilio Cota         }
1388*e3feb2ccSEmilio Cota     }
1389*e3feb2ccSEmilio Cota }
1390*e3feb2ccSEmilio Cota #endif
1391