mirror: return mirror-specific information upon query
[qemu/kevin.git] / util / qtree.c
blob31f0b46182e8b1f183f4e2809d1bee8864671a9e
1 /*
2 * GLIB - Library of useful routines for C programming
3 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
5 * SPDX-License-Identifier: LGPL-2.1-or-later
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
22 * Modified by the GLib Team and others 1997-2000. See the AUTHORS
23 * file for a list of people on the GLib Team. See the ChangeLog
24 * files for a list of changes. These files are distributed with
25 * GLib at ftp://ftp.gtk.org/pub/gtk/.
29 * MT safe
32 #include "qemu/osdep.h"
33 #include "qemu/qtree.h"
35 /**
36 * SECTION:trees-binary
37 * @title: Balanced Binary Trees
38 * @short_description: a sorted collection of key/value pairs optimized
39 * for searching and traversing in order
41 * The #QTree structure and its associated functions provide a sorted
42 * collection of key/value pairs optimized for searching and traversing
43 * in order. This means that most of the operations (access, search,
44 * insertion, deletion, ...) on #QTree are O(log(n)) in average and O(n)
45 * in worst case for time complexity. But, note that maintaining a
46 * balanced sorted #QTree of n elements is done in time O(n log(n)).
48 * To create a new #QTree use q_tree_new().
50 * To insert a key/value pair into a #QTree use q_tree_insert()
51 * (O(n log(n))).
53 * To remove a key/value pair use q_tree_remove() (O(n log(n))).
55 * To look up the value corresponding to a given key, use
56 * q_tree_lookup() and q_tree_lookup_extended().
58 * To find out the number of nodes in a #QTree, use q_tree_nnodes(). To
59 * get the height of a #QTree, use q_tree_height().
61 * To traverse a #QTree, calling a function for each node visited in
62 * the traversal, use q_tree_foreach().
64 * To destroy a #QTree, use q_tree_destroy().
65 **/
67 #define MAX_GTREE_HEIGHT 40
69 /**
70 * QTree:
72 * The QTree struct is an opaque data structure representing a
73 * [balanced binary tree][glib-Balanced-Binary-Trees]. It should be
74 * accessed only by using the following functions.
76 struct _QTree {
77 QTreeNode *root;
78 GCompareDataFunc key_compare;
79 GDestroyNotify key_destroy_func;
80 GDestroyNotify value_destroy_func;
81 gpointer key_compare_data;
82 guint nnodes;
83 gint ref_count;
86 struct _QTreeNode {
87 gpointer key; /* key for this node */
88 gpointer value; /* value stored at this node */
89 QTreeNode *left; /* left subtree */
90 QTreeNode *right; /* right subtree */
91 gint8 balance; /* height (right) - height (left) */
92 guint8 left_child;
93 guint8 right_child;
97 static QTreeNode *q_tree_node_new(gpointer key,
98 gpointer value);
99 static QTreeNode *q_tree_insert_internal(QTree *tree,
100 gpointer key,
101 gpointer value,
102 gboolean replace);
103 static gboolean q_tree_remove_internal(QTree *tree,
104 gconstpointer key,
105 gboolean steal);
106 static QTreeNode *q_tree_node_balance(QTreeNode *node);
107 static QTreeNode *q_tree_find_node(QTree *tree,
108 gconstpointer key);
109 static QTreeNode *q_tree_node_search(QTreeNode *node,
110 GCompareFunc search_func,
111 gconstpointer data);
112 static QTreeNode *q_tree_node_rotate_left(QTreeNode *node);
113 static QTreeNode *q_tree_node_rotate_right(QTreeNode *node);
114 #ifdef Q_TREE_DEBUG
115 static void q_tree_node_check(QTreeNode *node);
116 #endif
118 static QTreeNode*
119 q_tree_node_new(gpointer key,
120 gpointer value)
122 QTreeNode *node = g_new(QTreeNode, 1);
124 node->balance = 0;
125 node->left = NULL;
126 node->right = NULL;
127 node->left_child = FALSE;
128 node->right_child = FALSE;
129 node->key = key;
130 node->value = value;
132 return node;
136 * q_tree_new:
137 * @key_compare_func: the function used to order the nodes in the #QTree.
138 * It should return values similar to the standard strcmp() function -
139 * 0 if the two arguments are equal, a negative value if the first argument
140 * comes before the second, or a positive value if the first argument comes
141 * after the second.
143 * Creates a new #QTree.
145 * Returns: a newly allocated #QTree
147 QTree *
148 q_tree_new(GCompareFunc key_compare_func)
150 g_return_val_if_fail(key_compare_func != NULL, NULL);
152 return q_tree_new_full((GCompareDataFunc) key_compare_func, NULL,
153 NULL, NULL);
157 * q_tree_new_with_data:
158 * @key_compare_func: qsort()-style comparison function
159 * @key_compare_data: data to pass to comparison function
161 * Creates a new #QTree with a comparison function that accepts user data.
162 * See q_tree_new() for more details.
164 * Returns: a newly allocated #QTree
166 QTree *
167 q_tree_new_with_data(GCompareDataFunc key_compare_func,
168 gpointer key_compare_data)
170 g_return_val_if_fail(key_compare_func != NULL, NULL);
172 return q_tree_new_full(key_compare_func, key_compare_data,
173 NULL, NULL);
177 * q_tree_new_full:
178 * @key_compare_func: qsort()-style comparison function
179 * @key_compare_data: data to pass to comparison function
180 * @key_destroy_func: a function to free the memory allocated for the key
181 * used when removing the entry from the #QTree or %NULL if you don't
182 * want to supply such a function
183 * @value_destroy_func: a function to free the memory allocated for the
184 * value used when removing the entry from the #QTree or %NULL if you
185 * don't want to supply such a function
187 * Creates a new #QTree like q_tree_new() and allows to specify functions
188 * to free the memory allocated for the key and value that get called when
189 * removing the entry from the #QTree.
191 * Returns: a newly allocated #QTree
193 QTree *
194 q_tree_new_full(GCompareDataFunc key_compare_func,
195 gpointer key_compare_data,
196 GDestroyNotify key_destroy_func,
197 GDestroyNotify value_destroy_func)
199 QTree *tree;
201 g_return_val_if_fail(key_compare_func != NULL, NULL);
203 tree = g_new(QTree, 1);
204 tree->root = NULL;
205 tree->key_compare = key_compare_func;
206 tree->key_destroy_func = key_destroy_func;
207 tree->value_destroy_func = value_destroy_func;
208 tree->key_compare_data = key_compare_data;
209 tree->nnodes = 0;
210 tree->ref_count = 1;
212 return tree;
216 * q_tree_node_first:
217 * @tree: a #QTree
219 * Returns the first in-order node of the tree, or %NULL
220 * for an empty tree.
222 * Returns: (nullable) (transfer none): the first node in the tree
224 * Since: 2.68 in GLib. Internal in Qtree, i.e. not in the public API.
226 static QTreeNode *
227 q_tree_node_first(QTree *tree)
229 QTreeNode *tmp;
231 g_return_val_if_fail(tree != NULL, NULL);
233 if (!tree->root) {
234 return NULL;
237 tmp = tree->root;
239 while (tmp->left_child) {
240 tmp = tmp->left;
243 return tmp;
247 * q_tree_node_previous
248 * @node: a #QTree node
250 * Returns the previous in-order node of the tree, or %NULL
251 * if the passed node was already the first one.
253 * Returns: (nullable) (transfer none): the previous node in the tree
255 * Since: 2.68 in GLib. Internal in Qtree, i.e. not in the public API.
257 static QTreeNode *
258 q_tree_node_previous(QTreeNode *node)
260 QTreeNode *tmp;
262 g_return_val_if_fail(node != NULL, NULL);
264 tmp = node->left;
266 if (node->left_child) {
267 while (tmp->right_child) {
268 tmp = tmp->right;
272 return tmp;
276 * q_tree_node_next
277 * @node: a #QTree node
279 * Returns the next in-order node of the tree, or %NULL
280 * if the passed node was already the last one.
282 * Returns: (nullable) (transfer none): the next node in the tree
284 * Since: 2.68 in GLib. Internal in Qtree, i.e. not in the public API.
286 static QTreeNode *
287 q_tree_node_next(QTreeNode *node)
289 QTreeNode *tmp;
291 g_return_val_if_fail(node != NULL, NULL);
293 tmp = node->right;
295 if (node->right_child) {
296 while (tmp->left_child) {
297 tmp = tmp->left;
301 return tmp;
305 * q_tree_remove_all:
306 * @tree: a #QTree
308 * Removes all nodes from a #QTree and destroys their keys and values,
309 * then resets the #QTree’s root to %NULL.
311 * Since: 2.70 in GLib. Internal in Qtree, i.e. not in the public API.
313 static void QEMU_DISABLE_CFI
314 q_tree_remove_all(QTree *tree)
316 QTreeNode *node;
317 QTreeNode *next;
319 g_return_if_fail(tree != NULL);
321 node = q_tree_node_first(tree);
323 while (node) {
324 next = q_tree_node_next(node);
326 if (tree->key_destroy_func) {
327 tree->key_destroy_func(node->key);
329 if (tree->value_destroy_func) {
330 tree->value_destroy_func(node->value);
332 g_free(node);
334 #ifdef Q_TREE_DEBUG
335 g_assert(tree->nnodes > 0);
336 tree->nnodes--;
337 #endif
339 node = next;
342 #ifdef Q_TREE_DEBUG
343 g_assert(tree->nnodes == 0);
344 #endif
346 tree->root = NULL;
347 #ifndef Q_TREE_DEBUG
348 tree->nnodes = 0;
349 #endif
353 * q_tree_ref:
354 * @tree: a #QTree
356 * Increments the reference count of @tree by one.
358 * It is safe to call this function from any thread.
360 * Returns: the passed in #QTree
362 * Since: 2.22
364 QTree *
365 q_tree_ref(QTree *tree)
367 g_return_val_if_fail(tree != NULL, NULL);
369 g_atomic_int_inc(&tree->ref_count);
371 return tree;
375 * q_tree_unref:
376 * @tree: a #QTree
378 * Decrements the reference count of @tree by one.
379 * If the reference count drops to 0, all keys and values will
380 * be destroyed (if destroy functions were specified) and all
381 * memory allocated by @tree will be released.
383 * It is safe to call this function from any thread.
385 * Since: 2.22
387 void
388 q_tree_unref(QTree *tree)
390 g_return_if_fail(tree != NULL);
392 if (g_atomic_int_dec_and_test(&tree->ref_count)) {
393 q_tree_remove_all(tree);
394 g_free(tree);
399 * q_tree_destroy:
400 * @tree: a #QTree
402 * Removes all keys and values from the #QTree and decreases its
403 * reference count by one. If keys and/or values are dynamically
404 * allocated, you should either free them first or create the #QTree
405 * using q_tree_new_full(). In the latter case the destroy functions
406 * you supplied will be called on all keys and values before destroying
407 * the #QTree.
409 void
410 q_tree_destroy(QTree *tree)
412 g_return_if_fail(tree != NULL);
414 q_tree_remove_all(tree);
415 q_tree_unref(tree);
419 * q_tree_insert_node:
420 * @tree: a #QTree
421 * @key: the key to insert
422 * @value: the value corresponding to the key
424 * Inserts a key/value pair into a #QTree.
426 * If the given key already exists in the #QTree its corresponding value
427 * is set to the new value. If you supplied a @value_destroy_func when
428 * creating the #QTree, the old value is freed using that function. If
429 * you supplied a @key_destroy_func when creating the #QTree, the passed
430 * key is freed using that function.
432 * The tree is automatically 'balanced' as new key/value pairs are added,
433 * so that the distance from the root to every leaf is as small as possible.
434 * The cost of maintaining a balanced tree while inserting new key/value
435 * result in a O(n log(n)) operation where most of the other operations
436 * are O(log(n)).
438 * Returns: (transfer none): the inserted (or set) node.
440 * Since: 2.68 in GLib. Internal in Qtree, i.e. not in the public API.
442 static QTreeNode *
443 q_tree_insert_node(QTree *tree,
444 gpointer key,
445 gpointer value)
447 QTreeNode *node;
449 g_return_val_if_fail(tree != NULL, NULL);
451 node = q_tree_insert_internal(tree, key, value, FALSE);
453 #ifdef Q_TREE_DEBUG
454 q_tree_node_check(tree->root);
455 #endif
457 return node;
461 * q_tree_insert:
462 * @tree: a #QTree
463 * @key: the key to insert
464 * @value: the value corresponding to the key
466 * Inserts a key/value pair into a #QTree.
468 * Inserts a new key and value into a #QTree as q_tree_insert_node() does,
469 * only this function does not return the inserted or set node.
471 void
472 q_tree_insert(QTree *tree,
473 gpointer key,
474 gpointer value)
476 q_tree_insert_node(tree, key, value);
480 * q_tree_replace_node:
481 * @tree: a #QTree
482 * @key: the key to insert
483 * @value: the value corresponding to the key
485 * Inserts a new key and value into a #QTree similar to q_tree_insert_node().
486 * The difference is that if the key already exists in the #QTree, it gets
487 * replaced by the new key. If you supplied a @value_destroy_func when
488 * creating the #QTree, the old value is freed using that function. If you
489 * supplied a @key_destroy_func when creating the #QTree, the old key is
490 * freed using that function.
492 * The tree is automatically 'balanced' as new key/value pairs are added,
493 * so that the distance from the root to every leaf is as small as possible.
495 * Returns: (transfer none): the inserted (or set) node.
497 * Since: 2.68 in GLib. Internal in Qtree, i.e. not in the public API.
499 static QTreeNode *
500 q_tree_replace_node(QTree *tree,
501 gpointer key,
502 gpointer value)
504 QTreeNode *node;
506 g_return_val_if_fail(tree != NULL, NULL);
508 node = q_tree_insert_internal(tree, key, value, TRUE);
510 #ifdef Q_TREE_DEBUG
511 q_tree_node_check(tree->root);
512 #endif
514 return node;
518 * q_tree_replace:
519 * @tree: a #QTree
520 * @key: the key to insert
521 * @value: the value corresponding to the key
523 * Inserts a new key and value into a #QTree as q_tree_replace_node() does,
524 * only this function does not return the inserted or set node.
526 void
527 q_tree_replace(QTree *tree,
528 gpointer key,
529 gpointer value)
531 q_tree_replace_node(tree, key, value);
534 /* internal insert routine */
535 static QTreeNode * QEMU_DISABLE_CFI
536 q_tree_insert_internal(QTree *tree,
537 gpointer key,
538 gpointer value,
539 gboolean replace)
541 QTreeNode *node, *retnode;
542 QTreeNode *path[MAX_GTREE_HEIGHT];
543 int idx;
545 g_return_val_if_fail(tree != NULL, NULL);
547 if (!tree->root) {
548 tree->root = q_tree_node_new(key, value);
549 tree->nnodes++;
550 return tree->root;
553 idx = 0;
554 path[idx++] = NULL;
555 node = tree->root;
557 while (1) {
558 int cmp = tree->key_compare(key, node->key, tree->key_compare_data);
560 if (cmp == 0) {
561 if (tree->value_destroy_func) {
562 tree->value_destroy_func(node->value);
565 node->value = value;
567 if (replace) {
568 if (tree->key_destroy_func) {
569 tree->key_destroy_func(node->key);
572 node->key = key;
573 } else {
574 /* free the passed key */
575 if (tree->key_destroy_func) {
576 tree->key_destroy_func(key);
580 return node;
581 } else if (cmp < 0) {
582 if (node->left_child) {
583 path[idx++] = node;
584 node = node->left;
585 } else {
586 QTreeNode *child = q_tree_node_new(key, value);
588 child->left = node->left;
589 child->right = node;
590 node->left = child;
591 node->left_child = TRUE;
592 node->balance -= 1;
594 tree->nnodes++;
596 retnode = child;
597 break;
599 } else {
600 if (node->right_child) {
601 path[idx++] = node;
602 node = node->right;
603 } else {
604 QTreeNode *child = q_tree_node_new(key, value);
606 child->right = node->right;
607 child->left = node;
608 node->right = child;
609 node->right_child = TRUE;
610 node->balance += 1;
612 tree->nnodes++;
614 retnode = child;
615 break;
621 * Restore balance. This is the goodness of a non-recursive
622 * implementation, when we are done with balancing we 'break'
623 * the loop and we are done.
625 while (1) {
626 QTreeNode *bparent = path[--idx];
627 gboolean left_node = (bparent && node == bparent->left);
628 g_assert(!bparent || bparent->left == node || bparent->right == node);
630 if (node->balance < -1 || node->balance > 1) {
631 node = q_tree_node_balance(node);
632 if (bparent == NULL) {
633 tree->root = node;
634 } else if (left_node) {
635 bparent->left = node;
636 } else {
637 bparent->right = node;
641 if (node->balance == 0 || bparent == NULL) {
642 break;
645 if (left_node) {
646 bparent->balance -= 1;
647 } else {
648 bparent->balance += 1;
651 node = bparent;
654 return retnode;
658 * q_tree_remove:
659 * @tree: a #QTree
660 * @key: the key to remove
662 * Removes a key/value pair from a #QTree.
664 * If the #QTree was created using q_tree_new_full(), the key and value
665 * are freed using the supplied destroy functions, otherwise you have to
666 * make sure that any dynamically allocated values are freed yourself.
667 * If the key does not exist in the #QTree, the function does nothing.
669 * The cost of maintaining a balanced tree while removing a key/value
670 * result in a O(n log(n)) operation where most of the other operations
671 * are O(log(n)).
673 * Returns: %TRUE if the key was found (prior to 2.8, this function
674 * returned nothing)
676 gboolean
677 q_tree_remove(QTree *tree,
678 gconstpointer key)
680 gboolean removed;
682 g_return_val_if_fail(tree != NULL, FALSE);
684 removed = q_tree_remove_internal(tree, key, FALSE);
686 #ifdef Q_TREE_DEBUG
687 q_tree_node_check(tree->root);
688 #endif
690 return removed;
694 * q_tree_steal:
695 * @tree: a #QTree
696 * @key: the key to remove
698 * Removes a key and its associated value from a #QTree without calling
699 * the key and value destroy functions.
701 * If the key does not exist in the #QTree, the function does nothing.
703 * Returns: %TRUE if the key was found (prior to 2.8, this function
704 * returned nothing)
706 gboolean
707 q_tree_steal(QTree *tree,
708 gconstpointer key)
710 gboolean removed;
712 g_return_val_if_fail(tree != NULL, FALSE);
714 removed = q_tree_remove_internal(tree, key, TRUE);
716 #ifdef Q_TREE_DEBUG
717 q_tree_node_check(tree->root);
718 #endif
720 return removed;
723 /* internal remove routine */
724 static gboolean QEMU_DISABLE_CFI
725 q_tree_remove_internal(QTree *tree,
726 gconstpointer key,
727 gboolean steal)
729 QTreeNode *node, *parent, *balance;
730 QTreeNode *path[MAX_GTREE_HEIGHT];
731 int idx;
732 gboolean left_node;
734 g_return_val_if_fail(tree != NULL, FALSE);
736 if (!tree->root) {
737 return FALSE;
740 idx = 0;
741 path[idx++] = NULL;
742 node = tree->root;
744 while (1) {
745 int cmp = tree->key_compare(key, node->key, tree->key_compare_data);
747 if (cmp == 0) {
748 break;
749 } else if (cmp < 0) {
750 if (!node->left_child) {
751 return FALSE;
754 path[idx++] = node;
755 node = node->left;
756 } else {
757 if (!node->right_child) {
758 return FALSE;
761 path[idx++] = node;
762 node = node->right;
767 * The following code is almost equal to q_tree_remove_node,
768 * except that we do not have to call q_tree_node_parent.
770 balance = parent = path[--idx];
771 g_assert(!parent || parent->left == node || parent->right == node);
772 left_node = (parent && node == parent->left);
774 if (!node->left_child) {
775 if (!node->right_child) {
776 if (!parent) {
777 tree->root = NULL;
778 } else if (left_node) {
779 parent->left_child = FALSE;
780 parent->left = node->left;
781 parent->balance += 1;
782 } else {
783 parent->right_child = FALSE;
784 parent->right = node->right;
785 parent->balance -= 1;
787 } else {
788 /* node has a right child */
789 QTreeNode *tmp = q_tree_node_next(node);
790 tmp->left = node->left;
792 if (!parent) {
793 tree->root = node->right;
794 } else if (left_node) {
795 parent->left = node->right;
796 parent->balance += 1;
797 } else {
798 parent->right = node->right;
799 parent->balance -= 1;
802 } else {
803 /* node has a left child */
804 if (!node->right_child) {
805 QTreeNode *tmp = q_tree_node_previous(node);
806 tmp->right = node->right;
808 if (parent == NULL) {
809 tree->root = node->left;
810 } else if (left_node) {
811 parent->left = node->left;
812 parent->balance += 1;
813 } else {
814 parent->right = node->left;
815 parent->balance -= 1;
817 } else {
818 /* node has a both children (pant, pant!) */
819 QTreeNode *prev = node->left;
820 QTreeNode *next = node->right;
821 QTreeNode *nextp = node;
822 int old_idx = idx + 1;
823 idx++;
825 /* path[idx] == parent */
826 /* find the immediately next node (and its parent) */
827 while (next->left_child) {
828 path[++idx] = nextp = next;
829 next = next->left;
832 path[old_idx] = next;
833 balance = path[idx];
835 /* remove 'next' from the tree */
836 if (nextp != node) {
837 if (next->right_child) {
838 nextp->left = next->right;
839 } else {
840 nextp->left_child = FALSE;
842 nextp->balance += 1;
844 next->right_child = TRUE;
845 next->right = node->right;
846 } else {
847 node->balance -= 1;
850 /* set the prev to point to the right place */
851 while (prev->right_child) {
852 prev = prev->right;
854 prev->right = next;
856 /* prepare 'next' to replace 'node' */
857 next->left_child = TRUE;
858 next->left = node->left;
859 next->balance = node->balance;
861 if (!parent) {
862 tree->root = next;
863 } else if (left_node) {
864 parent->left = next;
865 } else {
866 parent->right = next;
871 /* restore balance */
872 if (balance) {
873 while (1) {
874 QTreeNode *bparent = path[--idx];
875 g_assert(!bparent ||
876 bparent->left == balance ||
877 bparent->right == balance);
878 left_node = (bparent && balance == bparent->left);
880 if (balance->balance < -1 || balance->balance > 1) {
881 balance = q_tree_node_balance(balance);
882 if (!bparent) {
883 tree->root = balance;
884 } else if (left_node) {
885 bparent->left = balance;
886 } else {
887 bparent->right = balance;
891 if (balance->balance != 0 || !bparent) {
892 break;
895 if (left_node) {
896 bparent->balance += 1;
897 } else {
898 bparent->balance -= 1;
901 balance = bparent;
905 if (!steal) {
906 if (tree->key_destroy_func) {
907 tree->key_destroy_func(node->key);
909 if (tree->value_destroy_func) {
910 tree->value_destroy_func(node->value);
914 g_free(node);
916 tree->nnodes--;
918 return TRUE;
922 * q_tree_lookup_node:
923 * @tree: a #QTree
924 * @key: the key to look up
926 * Gets the tree node corresponding to the given key. Since a #QTree is
927 * automatically balanced as key/value pairs are added, key lookup
928 * is O(log n) (where n is the number of key/value pairs in the tree).
930 * Returns: (nullable) (transfer none): the tree node corresponding to
931 * the key, or %NULL if the key was not found
933 * Since: 2.68 in GLib. Internal in Qtree, i.e. not in the public API.
935 static QTreeNode *
936 q_tree_lookup_node(QTree *tree,
937 gconstpointer key)
939 g_return_val_if_fail(tree != NULL, NULL);
941 return q_tree_find_node(tree, key);
945 * q_tree_lookup:
946 * @tree: a #QTree
947 * @key: the key to look up
949 * Gets the value corresponding to the given key. Since a #QTree is
950 * automatically balanced as key/value pairs are added, key lookup
951 * is O(log n) (where n is the number of key/value pairs in the tree).
953 * Returns: the value corresponding to the key, or %NULL
954 * if the key was not found
956 gpointer
957 q_tree_lookup(QTree *tree,
958 gconstpointer key)
960 QTreeNode *node;
962 node = q_tree_lookup_node(tree, key);
964 return node ? node->value : NULL;
968 * q_tree_lookup_extended:
969 * @tree: a #QTree
970 * @lookup_key: the key to look up
971 * @orig_key: (out) (optional) (nullable): returns the original key
972 * @value: (out) (optional) (nullable): returns the value associated with
973 * the key
975 * Looks up a key in the #QTree, returning the original key and the
976 * associated value. This is useful if you need to free the memory
977 * allocated for the original key, for example before calling
978 * q_tree_remove().
980 * Returns: %TRUE if the key was found in the #QTree
982 gboolean
983 q_tree_lookup_extended(QTree *tree,
984 gconstpointer lookup_key,
985 gpointer *orig_key,
986 gpointer *value)
988 QTreeNode *node;
990 g_return_val_if_fail(tree != NULL, FALSE);
992 node = q_tree_find_node(tree, lookup_key);
994 if (node) {
995 if (orig_key) {
996 *orig_key = node->key;
998 if (value) {
999 *value = node->value;
1001 return TRUE;
1002 } else {
1003 return FALSE;
1008 * q_tree_foreach:
1009 * @tree: a #QTree
1010 * @func: the function to call for each node visited.
1011 * If this function returns %TRUE, the traversal is stopped.
1012 * @user_data: user data to pass to the function
1014 * Calls the given function for each of the key/value pairs in the #QTree.
1015 * The function is passed the key and value of each pair, and the given
1016 * @data parameter. The tree is traversed in sorted order.
1018 * The tree may not be modified while iterating over it (you can't
1019 * add/remove items). To remove all items matching a predicate, you need
1020 * to add each item to a list in your #GTraverseFunc as you walk over
1021 * the tree, then walk the list and remove each item.
1023 void
1024 q_tree_foreach(QTree *tree,
1025 GTraverseFunc func,
1026 gpointer user_data)
1028 QTreeNode *node;
1030 g_return_if_fail(tree != NULL);
1032 if (!tree->root) {
1033 return;
1036 node = q_tree_node_first(tree);
1038 while (node) {
1039 if ((*func)(node->key, node->value, user_data)) {
1040 break;
1043 node = q_tree_node_next(node);
1048 * q_tree_search_node:
1049 * @tree: a #QTree
1050 * @search_func: a function used to search the #QTree
1051 * @user_data: the data passed as the second argument to @search_func
1053 * Searches a #QTree using @search_func.
1055 * The @search_func is called with a pointer to the key of a key/value
1056 * pair in the tree, and the passed in @user_data. If @search_func returns
1057 * 0 for a key/value pair, then the corresponding node is returned as
1058 * the result of q_tree_search(). If @search_func returns -1, searching
1059 * will proceed among the key/value pairs that have a smaller key; if
1060 * @search_func returns 1, searching will proceed among the key/value
1061 * pairs that have a larger key.
1063 * Returns: (nullable) (transfer none): the node corresponding to the
1064 * found key, or %NULL if the key was not found
1066 * Since: 2.68 in GLib. Internal in Qtree, i.e. not in the public API.
1068 static QTreeNode *
1069 q_tree_search_node(QTree *tree,
1070 GCompareFunc search_func,
1071 gconstpointer user_data)
1073 g_return_val_if_fail(tree != NULL, NULL);
1075 if (!tree->root) {
1076 return NULL;
1079 return q_tree_node_search(tree->root, search_func, user_data);
1083 * q_tree_search:
1084 * @tree: a #QTree
1085 * @search_func: a function used to search the #QTree
1086 * @user_data: the data passed as the second argument to @search_func
1088 * Searches a #QTree using @search_func.
1090 * The @search_func is called with a pointer to the key of a key/value
1091 * pair in the tree, and the passed in @user_data. If @search_func returns
1092 * 0 for a key/value pair, then the corresponding value is returned as
1093 * the result of q_tree_search(). If @search_func returns -1, searching
1094 * will proceed among the key/value pairs that have a smaller key; if
1095 * @search_func returns 1, searching will proceed among the key/value
1096 * pairs that have a larger key.
1098 * Returns: the value corresponding to the found key, or %NULL
1099 * if the key was not found
1101 gpointer
1102 q_tree_search(QTree *tree,
1103 GCompareFunc search_func,
1104 gconstpointer user_data)
1106 QTreeNode *node;
1108 node = q_tree_search_node(tree, search_func, user_data);
1110 return node ? node->value : NULL;
1114 * q_tree_height:
1115 * @tree: a #QTree
1117 * Gets the height of a #QTree.
1119 * If the #QTree contains no nodes, the height is 0.
1120 * If the #QTree contains only one root node the height is 1.
1121 * If the root node has children the height is 2, etc.
1123 * Returns: the height of @tree
1125 gint
1126 q_tree_height(QTree *tree)
1128 QTreeNode *node;
1129 gint height;
1131 g_return_val_if_fail(tree != NULL, 0);
1133 if (!tree->root) {
1134 return 0;
1137 height = 0;
1138 node = tree->root;
1140 while (1) {
1141 height += 1 + MAX(node->balance, 0);
1143 if (!node->left_child) {
1144 return height;
1147 node = node->left;
1152 * q_tree_nnodes:
1153 * @tree: a #QTree
1155 * Gets the number of nodes in a #QTree.
1157 * Returns: the number of nodes in @tree
1159 gint
1160 q_tree_nnodes(QTree *tree)
1162 g_return_val_if_fail(tree != NULL, 0);
1164 return tree->nnodes;
1167 static QTreeNode *
1168 q_tree_node_balance(QTreeNode *node)
1170 if (node->balance < -1) {
1171 if (node->left->balance > 0) {
1172 node->left = q_tree_node_rotate_left(node->left);
1174 node = q_tree_node_rotate_right(node);
1175 } else if (node->balance > 1) {
1176 if (node->right->balance < 0) {
1177 node->right = q_tree_node_rotate_right(node->right);
1179 node = q_tree_node_rotate_left(node);
1182 return node;
1185 static QTreeNode * QEMU_DISABLE_CFI
1186 q_tree_find_node(QTree *tree,
1187 gconstpointer key)
1189 QTreeNode *node;
1190 gint cmp;
1192 node = tree->root;
1193 if (!node) {
1194 return NULL;
1197 while (1) {
1198 cmp = tree->key_compare(key, node->key, tree->key_compare_data);
1199 if (cmp == 0) {
1200 return node;
1201 } else if (cmp < 0) {
1202 if (!node->left_child) {
1203 return NULL;
1206 node = node->left;
1207 } else {
1208 if (!node->right_child) {
1209 return NULL;
1212 node = node->right;
1217 static QTreeNode *
1218 q_tree_node_search(QTreeNode *node,
1219 GCompareFunc search_func,
1220 gconstpointer data)
1222 gint dir;
1224 if (!node) {
1225 return NULL;
1228 while (1) {
1229 dir = (*search_func)(node->key, data);
1230 if (dir == 0) {
1231 return node;
1232 } else if (dir < 0) {
1233 if (!node->left_child) {
1234 return NULL;
1237 node = node->left;
1238 } else {
1239 if (!node->right_child) {
1240 return NULL;
1243 node = node->right;
1248 static QTreeNode *
1249 q_tree_node_rotate_left(QTreeNode *node)
1251 QTreeNode *right;
1252 gint a_bal;
1253 gint b_bal;
1255 right = node->right;
1257 if (right->left_child) {
1258 node->right = right->left;
1259 } else {
1260 node->right_child = FALSE;
1261 right->left_child = TRUE;
1263 right->left = node;
1265 a_bal = node->balance;
1266 b_bal = right->balance;
1268 if (b_bal <= 0) {
1269 if (a_bal >= 1) {
1270 right->balance = b_bal - 1;
1271 } else {
1272 right->balance = a_bal + b_bal - 2;
1274 node->balance = a_bal - 1;
1275 } else {
1276 if (a_bal <= b_bal) {
1277 right->balance = a_bal - 2;
1278 } else {
1279 right->balance = b_bal - 1;
1281 node->balance = a_bal - b_bal - 1;
1284 return right;
1287 static QTreeNode *
1288 q_tree_node_rotate_right(QTreeNode *node)
1290 QTreeNode *left;
1291 gint a_bal;
1292 gint b_bal;
1294 left = node->left;
1296 if (left->right_child) {
1297 node->left = left->right;
1298 } else {
1299 node->left_child = FALSE;
1300 left->right_child = TRUE;
1302 left->right = node;
1304 a_bal = node->balance;
1305 b_bal = left->balance;
1307 if (b_bal <= 0) {
1308 if (b_bal > a_bal) {
1309 left->balance = b_bal + 1;
1310 } else {
1311 left->balance = a_bal + 2;
1313 node->balance = a_bal - b_bal + 1;
1314 } else {
1315 if (a_bal <= -1) {
1316 left->balance = b_bal + 1;
1317 } else {
1318 left->balance = a_bal + b_bal + 2;
1320 node->balance = a_bal + 1;
1323 return left;
1326 #ifdef Q_TREE_DEBUG
1327 static gint
1328 q_tree_node_height(QTreeNode *node)
1330 gint left_height;
1331 gint right_height;
1333 if (node) {
1334 left_height = 0;
1335 right_height = 0;
1337 if (node->left_child) {
1338 left_height = q_tree_node_height(node->left);
1341 if (node->right_child) {
1342 right_height = q_tree_node_height(node->right);
1345 return MAX(left_height, right_height) + 1;
1348 return 0;
1351 static void q_tree_node_check(QTreeNode *node)
1353 gint left_height;
1354 gint right_height;
1355 gint balance;
1356 QTreeNode *tmp;
1358 if (node) {
1359 if (node->left_child) {
1360 tmp = q_tree_node_previous(node);
1361 g_assert(tmp->right == node);
1364 if (node->right_child) {
1365 tmp = q_tree_node_next(node);
1366 g_assert(tmp->left == node);
1369 left_height = 0;
1370 right_height = 0;
1372 if (node->left_child) {
1373 left_height = q_tree_node_height(node->left);
1375 if (node->right_child) {
1376 right_height = q_tree_node_height(node->right);
1379 balance = right_height - left_height;
1380 g_assert(balance == node->balance);
1382 if (node->left_child) {
1383 q_tree_node_check(node->left);
1385 if (node->right_child) {
1386 q_tree_node_check(node->right);
1390 #endif