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