Add GLIB_SIZEOF_VOID_P and GLIB_SIZEOF_LONG.
[glib.git] / glib / gtree.c
blob39c1668eef6bb9c992b8ece029bd9ac55730b93d
1 /* GLIB - Library of useful routines for C programming
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 * Modified by the GLib Team and others 1997-2000. See the AUTHORS
22 * file for a list of people on the GLib Team. See the ChangeLog
23 * files for a list of changes. These files are distributed with
24 * GLib at ftp://ftp.gtk.org/pub/gtk/.
27 /*
28 * MT safe
31 #ifdef HAVE_CONFIG_H
32 #include <config.h>
33 #endif
35 #include "glib.h"
38 typedef struct _GRealTree GRealTree;
39 typedef struct _GTreeNode GTreeNode;
41 struct _GRealTree
43 GTreeNode *root;
44 GCompareFuncData key_compare;
45 gpointer key_compare_data;
48 struct _GTreeNode
50 gint balance; /* height (left) - height (right) */
51 GTreeNode *left; /* left subtree */
52 GTreeNode *right; /* right subtree */
53 gpointer key; /* key for this node */
54 gpointer value; /* value stored at this node */
58 static GTreeNode* g_tree_node_new (gpointer key,
59 gpointer value);
60 static void g_tree_node_destroy (GTreeNode *node);
61 static GTreeNode* g_tree_node_insert (GTreeNode *node,
62 GCompareFuncData compare,
63 gpointer comp_data,
64 gpointer key,
65 gpointer value,
66 gint *inserted);
67 static GTreeNode* g_tree_node_remove (GTreeNode *node,
68 GCompareFuncData compare,
69 gpointer comp_data,
70 gconstpointer key);
71 static GTreeNode* g_tree_node_balance (GTreeNode *node);
72 static GTreeNode* g_tree_node_remove_leftmost (GTreeNode *node,
73 GTreeNode **leftmost);
74 static GTreeNode* g_tree_node_restore_left_balance (GTreeNode *node,
75 gint old_balance);
76 static GTreeNode* g_tree_node_restore_right_balance (GTreeNode *node,
77 gint old_balance);
78 static gpointer g_tree_node_lookup (GTreeNode *node,
79 GCompareFuncData compare,
80 gpointer comp_data,
81 gconstpointer key);
82 static gint g_tree_node_count (GTreeNode *node);
83 static gint g_tree_node_pre_order (GTreeNode *node,
84 GTraverseFunc traverse_func,
85 gpointer data);
86 static gint g_tree_node_in_order (GTreeNode *node,
87 GTraverseFunc traverse_func,
88 gpointer data);
89 static gint g_tree_node_post_order (GTreeNode *node,
90 GTraverseFunc traverse_func,
91 gpointer data);
92 static gpointer g_tree_node_search (GTreeNode *node,
93 GCompareFunc search_func,
94 gconstpointer data);
95 static gint g_tree_node_height (GTreeNode *node);
96 static GTreeNode* g_tree_node_rotate_left (GTreeNode *node);
97 static GTreeNode* g_tree_node_rotate_right (GTreeNode *node);
98 static void g_tree_node_check (GTreeNode *node);
101 G_LOCK_DEFINE_STATIC (g_tree_global);
102 static GMemChunk *node_mem_chunk = NULL;
103 static GTreeNode *node_free_list = NULL;
106 static GTreeNode*
107 g_tree_node_new (gpointer key,
108 gpointer value)
110 GTreeNode *node;
112 G_LOCK (g_tree_global);
113 if (node_free_list)
115 node = node_free_list;
116 node_free_list = node->right;
118 else
120 if (!node_mem_chunk)
121 node_mem_chunk = g_mem_chunk_new ("GLib GTreeNode mem chunk",
122 sizeof (GTreeNode),
123 1024,
124 G_ALLOC_ONLY);
126 node = g_chunk_new (GTreeNode, node_mem_chunk);
128 G_UNLOCK (g_tree_global);
130 node->balance = 0;
131 node->left = NULL;
132 node->right = NULL;
133 node->key = key;
134 node->value = value;
136 return node;
139 static void
140 g_tree_node_destroy (GTreeNode *node)
142 if (node)
144 g_tree_node_destroy (node->right);
145 g_tree_node_destroy (node->left);
147 #ifdef ENABLE_GC_FRIENDLY
148 node->left = NULL;
149 node->key = NULL;
150 node->value = NULL;
151 #endif /* ENABLE_GC_FRIENDLY */
153 G_LOCK (g_tree_global);
154 node->right = node_free_list;
155 node_free_list = node;
156 G_UNLOCK (g_tree_global);
160 GTree* g_tree_new_udata(GCompareFuncData key_compare_func,
161 gpointer key_compare_data)
163 GRealTree *rtree;
165 g_return_val_if_fail (key_compare_func != NULL, NULL);
167 rtree = g_new (GRealTree, 1);
168 rtree->root = NULL;
169 rtree->key_compare = key_compare_func;
170 rtree->key_compare_data = key_compare_data;
172 return (GTree*) rtree;
175 GTree*
176 g_tree_new (GCompareFunc key_compare_func)
178 return g_tree_new_udata ((GCompareFuncData) key_compare_func, NULL);
182 void
183 g_tree_destroy (GTree *tree)
185 GRealTree *rtree;
187 g_return_if_fail (tree != NULL);
189 rtree = (GRealTree*) tree;
191 g_tree_node_destroy (rtree->root);
192 g_free (rtree);
195 void
196 g_tree_insert (GTree *tree,
197 gpointer key,
198 gpointer value)
200 GRealTree *rtree;
201 gint inserted;
203 g_return_if_fail (tree != NULL);
205 rtree = (GRealTree*) tree;
207 inserted = FALSE;
208 rtree->root = g_tree_node_insert (rtree->root, rtree->key_compare,
209 rtree->key_compare_data,
210 key, value, &inserted);
213 void
214 g_tree_remove (GTree *tree,
215 gconstpointer key)
217 GRealTree *rtree;
219 g_return_if_fail (tree != NULL);
221 rtree = (GRealTree*) tree;
223 rtree->root = g_tree_node_remove (rtree->root, rtree->key_compare,
224 rtree->key_compare_data, key);
227 gpointer
228 g_tree_lookup (GTree *tree,
229 gconstpointer key)
231 GRealTree *rtree;
233 g_return_val_if_fail (tree != NULL, NULL);
235 rtree = (GRealTree*) tree;
237 return g_tree_node_lookup (rtree->root, rtree->key_compare,
238 rtree->key_compare_data, key);
241 void
242 g_tree_traverse (GTree *tree,
243 GTraverseFunc traverse_func,
244 GTraverseType traverse_type,
245 gpointer data)
247 GRealTree *rtree;
249 g_return_if_fail (tree != NULL);
251 rtree = (GRealTree*) tree;
253 if (!rtree->root)
254 return;
256 switch (traverse_type)
258 case G_PRE_ORDER:
259 g_tree_node_pre_order (rtree->root, traverse_func, data);
260 break;
262 case G_IN_ORDER:
263 g_tree_node_in_order (rtree->root, traverse_func, data);
264 break;
266 case G_POST_ORDER:
267 g_tree_node_post_order (rtree->root, traverse_func, data);
268 break;
270 case G_LEVEL_ORDER:
271 g_warning ("g_tree_traverse(): traverse type G_LEVEL_ORDER isn't implemented.");
272 break;
276 gpointer
277 g_tree_search (GTree *tree,
278 GCompareFunc search_func,
279 gconstpointer data)
281 GRealTree *rtree;
283 g_return_val_if_fail (tree != NULL, NULL);
285 rtree = (GRealTree*) tree;
287 if (rtree->root)
288 return g_tree_node_search (rtree->root, search_func, data);
289 else
290 return NULL;
293 gint
294 g_tree_height (GTree *tree)
296 GRealTree *rtree;
298 g_return_val_if_fail (tree != NULL, 0);
300 rtree = (GRealTree*) tree;
302 if (rtree->root)
303 return g_tree_node_height (rtree->root);
304 else
305 return 0;
308 gint
309 g_tree_nnodes (GTree *tree)
311 GRealTree *rtree;
313 g_return_val_if_fail (tree != NULL, 0);
315 rtree = (GRealTree*) tree;
317 if (rtree->root)
318 return g_tree_node_count (rtree->root);
319 else
320 return 0;
323 static GTreeNode*
324 g_tree_node_insert (GTreeNode *node,
325 GCompareFuncData compare,
326 gpointer compare_data,
327 gpointer key,
328 gpointer value,
329 gint *inserted)
331 gint old_balance;
332 gint cmp;
334 if (!node)
336 *inserted = TRUE;
337 return g_tree_node_new (key, value);
340 cmp = (* compare) (key, node->key, compare_data);
341 if (cmp == 0)
343 *inserted = FALSE;
344 node->value = value;
345 return node;
348 if (cmp < 0)
350 if (node->left)
352 old_balance = node->left->balance;
353 node->left = g_tree_node_insert (node->left, compare, compare_data,
354 key, value, inserted);
356 if ((old_balance != node->left->balance) && node->left->balance)
357 node->balance -= 1;
359 else
361 *inserted = TRUE;
362 node->left = g_tree_node_new (key, value);
363 node->balance -= 1;
366 else if (cmp > 0)
368 if (node->right)
370 old_balance = node->right->balance;
371 node->right = g_tree_node_insert (node->right, compare, compare_data,
372 key, value, inserted);
374 if ((old_balance != node->right->balance) && node->right->balance)
375 node->balance += 1;
377 else
379 *inserted = TRUE;
380 node->right = g_tree_node_new (key, value);
381 node->balance += 1;
385 if (*inserted)
387 if ((node->balance < -1) || (node->balance > 1))
388 node = g_tree_node_balance (node);
391 return node;
394 static GTreeNode*
395 g_tree_node_remove (GTreeNode *node,
396 GCompareFuncData compare,
397 gpointer compare_data,
398 gconstpointer key)
400 GTreeNode *new_root;
401 gint old_balance;
402 gint cmp;
404 if (!node)
405 return NULL;
407 cmp = (* compare) (key, node->key, compare_data);
408 if (cmp == 0)
410 GTreeNode *garbage;
412 garbage = node;
414 if (!node->right)
416 node = node->left;
418 else
420 old_balance = node->right->balance;
421 node->right = g_tree_node_remove_leftmost (node->right, &new_root);
422 new_root->left = node->left;
423 new_root->right = node->right;
424 new_root->balance = node->balance;
425 node = g_tree_node_restore_right_balance (new_root, old_balance);
428 #ifdef ENABLE_GC_FRIENDLY
429 garbage->left = NULL;
430 garbage->key = NULL;
431 garbage->value = NULL;
432 #endif /* ENABLE_GC_FRIENDLY */
434 G_LOCK (g_tree_global);
435 garbage->right = node_free_list;
436 node_free_list = garbage;
437 G_UNLOCK (g_tree_global);
439 else if (cmp < 0)
441 if (node->left)
443 old_balance = node->left->balance;
444 node->left = g_tree_node_remove (node->left, compare, compare_data, key);
445 node = g_tree_node_restore_left_balance (node, old_balance);
448 else if (cmp > 0)
450 if (node->right)
452 old_balance = node->right->balance;
453 node->right = g_tree_node_remove (node->right, compare, compare_data, key);
454 node = g_tree_node_restore_right_balance (node, old_balance);
458 return node;
461 static GTreeNode*
462 g_tree_node_balance (GTreeNode *node)
464 if (node->balance < -1)
466 if (node->left->balance > 0)
467 node->left = g_tree_node_rotate_left (node->left);
468 node = g_tree_node_rotate_right (node);
470 else if (node->balance > 1)
472 if (node->right->balance < 0)
473 node->right = g_tree_node_rotate_right (node->right);
474 node = g_tree_node_rotate_left (node);
477 return node;
480 static GTreeNode*
481 g_tree_node_remove_leftmost (GTreeNode *node,
482 GTreeNode **leftmost)
484 gint old_balance;
486 if (!node->left)
488 *leftmost = node;
489 return node->right;
492 old_balance = node->left->balance;
493 node->left = g_tree_node_remove_leftmost (node->left, leftmost);
494 return g_tree_node_restore_left_balance (node, old_balance);
497 static GTreeNode*
498 g_tree_node_restore_left_balance (GTreeNode *node,
499 gint old_balance)
501 if (!node->left)
502 node->balance += 1;
503 else if ((node->left->balance != old_balance) &&
504 (node->left->balance == 0))
505 node->balance += 1;
507 if (node->balance > 1)
508 return g_tree_node_balance (node);
509 return node;
512 static GTreeNode*
513 g_tree_node_restore_right_balance (GTreeNode *node,
514 gint old_balance)
516 if (!node->right)
517 node->balance -= 1;
518 else if ((node->right->balance != old_balance) &&
519 (node->right->balance == 0))
520 node->balance -= 1;
522 if (node->balance < -1)
523 return g_tree_node_balance (node);
524 return node;
527 static gpointer
528 g_tree_node_lookup (GTreeNode *node,
529 GCompareFuncData compare,
530 gpointer compare_data,
531 gconstpointer key)
533 gint cmp;
535 if (!node)
536 return NULL;
538 cmp = (* compare) (key, node->key, compare_data);
539 if (cmp == 0)
540 return node->value;
542 if (cmp < 0)
544 if (node->left)
545 return g_tree_node_lookup (node->left, compare, compare_data, key);
547 else if (cmp > 0)
549 if (node->right)
550 return g_tree_node_lookup (node->right, compare, compare_data, key);
553 return NULL;
556 static gint
557 g_tree_node_count (GTreeNode *node)
559 gint count;
561 count = 1;
562 if (node->left)
563 count += g_tree_node_count (node->left);
564 if (node->right)
565 count += g_tree_node_count (node->right);
567 return count;
570 static gint
571 g_tree_node_pre_order (GTreeNode *node,
572 GTraverseFunc traverse_func,
573 gpointer data)
575 if ((*traverse_func) (node->key, node->value, data))
576 return TRUE;
577 if (node->left)
579 if (g_tree_node_pre_order (node->left, traverse_func, data))
580 return TRUE;
582 if (node->right)
584 if (g_tree_node_pre_order (node->right, traverse_func, data))
585 return TRUE;
588 return FALSE;
591 static gint
592 g_tree_node_in_order (GTreeNode *node,
593 GTraverseFunc traverse_func,
594 gpointer data)
596 if (node->left)
598 if (g_tree_node_in_order (node->left, traverse_func, data))
599 return TRUE;
601 if ((*traverse_func) (node->key, node->value, data))
602 return TRUE;
603 if (node->right)
605 if (g_tree_node_in_order (node->right, traverse_func, data))
606 return TRUE;
609 return FALSE;
612 static gint
613 g_tree_node_post_order (GTreeNode *node,
614 GTraverseFunc traverse_func,
615 gpointer data)
617 if (node->left)
619 if (g_tree_node_post_order (node->left, traverse_func, data))
620 return TRUE;
622 if (node->right)
624 if (g_tree_node_post_order (node->right, traverse_func, data))
625 return TRUE;
627 if ((*traverse_func) (node->key, node->value, data))
628 return TRUE;
630 return FALSE;
633 static gpointer
634 g_tree_node_search (GTreeNode *node,
635 GCompareFunc search_func,
636 gconstpointer data)
638 gint dir;
640 if (!node)
641 return NULL;
643 do {
644 dir = (* search_func) (node->key, data);
645 if (dir == 0)
646 return node->value;
648 if (dir < 0)
649 node = node->left;
650 else if (dir > 0)
651 node = node->right;
652 } while (node && (dir != 0));
654 return NULL;
657 static gint
658 g_tree_node_height (GTreeNode *node)
660 gint left_height;
661 gint right_height;
663 if (node)
665 left_height = 0;
666 right_height = 0;
668 if (node->left)
669 left_height = g_tree_node_height (node->left);
671 if (node->right)
672 right_height = g_tree_node_height (node->right);
674 return MAX (left_height, right_height) + 1;
677 return 0;
680 static GTreeNode*
681 g_tree_node_rotate_left (GTreeNode *node)
683 GTreeNode *right;
684 gint a_bal;
685 gint b_bal;
687 right = node->right;
689 node->right = right->left;
690 right->left = node;
692 a_bal = node->balance;
693 b_bal = right->balance;
695 if (b_bal <= 0)
697 if (a_bal >= 1)
698 right->balance = b_bal - 1;
699 else
700 right->balance = a_bal + b_bal - 2;
701 node->balance = a_bal - 1;
703 else
705 if (a_bal <= b_bal)
706 right->balance = a_bal - 2;
707 else
708 right->balance = b_bal - 1;
709 node->balance = a_bal - b_bal - 1;
712 return right;
715 static GTreeNode*
716 g_tree_node_rotate_right (GTreeNode *node)
718 GTreeNode *left;
719 gint a_bal;
720 gint b_bal;
722 left = node->left;
724 node->left = left->right;
725 left->right = node;
727 a_bal = node->balance;
728 b_bal = left->balance;
730 if (b_bal <= 0)
732 if (b_bal > a_bal)
733 left->balance = b_bal + 1;
734 else
735 left->balance = a_bal + 2;
736 node->balance = a_bal - b_bal + 1;
738 else
740 if (a_bal <= -1)
741 left->balance = b_bal + 1;
742 else
743 left->balance = a_bal + b_bal + 2;
744 node->balance = a_bal + 1;
747 return left;
750 static void
751 g_tree_node_check (GTreeNode *node)
753 gint left_height;
754 gint right_height;
755 gint balance;
757 if (node)
759 left_height = 0;
760 right_height = 0;
762 if (node->left)
763 left_height = g_tree_node_height (node->left);
764 if (node->right)
765 right_height = g_tree_node_height (node->right);
767 balance = right_height - left_height;
768 if (balance != node->balance)
769 g_log (g_log_domain_glib, G_LOG_LEVEL_INFO,
770 "g_tree_node_check: failed: %d ( %d )\n",
771 balance, node->balance);
773 if (node->left)
774 g_tree_node_check (node->left);
775 if (node->right)
776 g_tree_node_check (node->right);