Copy all elements of the allocations[] array, including the last. (Pointed
[glib.git] / gtree.c
blob5b4e342bb3385510357f965cec897c235e78f513
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 Library 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 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library 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.
20 /*
21 * MT safe
24 #include "glib.h"
27 typedef struct _GRealTree GRealTree;
28 typedef struct _GTreeNode GTreeNode;
30 struct _GRealTree
32 GTreeNode *root;
33 GCompareFunc key_compare;
36 struct _GTreeNode
38 gint balance; /* height (left) - height (right) */
39 GTreeNode *left; /* left subtree */
40 GTreeNode *right; /* right subtree */
41 gpointer key; /* key for this node */
42 gpointer value; /* value stored at this node */
46 static GTreeNode* g_tree_node_new (gpointer key,
47 gpointer value);
48 static void g_tree_node_destroy (GTreeNode *node);
49 static GTreeNode* g_tree_node_insert (GTreeNode *node,
50 GCompareFunc compare,
51 gpointer key,
52 gpointer value,
53 gint *inserted);
54 static GTreeNode* g_tree_node_remove (GTreeNode *node,
55 GCompareFunc compare,
56 gpointer key);
57 static GTreeNode* g_tree_node_balance (GTreeNode *node);
58 static GTreeNode* g_tree_node_remove_leftmost (GTreeNode *node,
59 GTreeNode **leftmost);
60 static GTreeNode* g_tree_node_restore_left_balance (GTreeNode *node,
61 gint old_balance);
62 static GTreeNode* g_tree_node_restore_right_balance (GTreeNode *node,
63 gint old_balance);
64 static gpointer g_tree_node_lookup (GTreeNode *node,
65 GCompareFunc compare,
66 gpointer key);
67 static gint g_tree_node_count (GTreeNode *node);
68 static gint g_tree_node_pre_order (GTreeNode *node,
69 GTraverseFunc traverse_func,
70 gpointer data);
71 static gint g_tree_node_in_order (GTreeNode *node,
72 GTraverseFunc traverse_func,
73 gpointer data);
74 static gint g_tree_node_post_order (GTreeNode *node,
75 GTraverseFunc traverse_func,
76 gpointer data);
77 static gpointer g_tree_node_search (GTreeNode *node,
78 GSearchFunc search_func,
79 gpointer data);
80 static gint g_tree_node_height (GTreeNode *node);
81 static GTreeNode* g_tree_node_rotate_left (GTreeNode *node);
82 static GTreeNode* g_tree_node_rotate_right (GTreeNode *node);
83 static void g_tree_node_check (GTreeNode *node);
86 G_LOCK_DECLARE_STATIC (g_tree_global);
87 static GMemChunk *node_mem_chunk = NULL;
88 static GTreeNode *node_free_list = NULL;
91 static GTreeNode*
92 g_tree_node_new (gpointer key,
93 gpointer value)
95 GTreeNode *node;
97 G_LOCK (g_tree_global);
98 if (node_free_list)
100 node = node_free_list;
101 node_free_list = node->right;
103 else
105 if (!node_mem_chunk)
106 node_mem_chunk = g_mem_chunk_new ("GLib GTreeNode mem chunk",
107 sizeof (GTreeNode),
108 1024,
109 G_ALLOC_ONLY);
111 node = g_chunk_new (GTreeNode, node_mem_chunk);
113 G_UNLOCK (g_tree_global);
115 node->balance = 0;
116 node->left = NULL;
117 node->right = NULL;
118 node->key = key;
119 node->value = value;
121 return node;
124 static void
125 g_tree_node_destroy (GTreeNode *node)
127 if (node)
129 g_tree_node_destroy (node->right);
130 g_tree_node_destroy (node->left);
131 G_LOCK (g_tree_global);
132 node->right = node_free_list;
133 node_free_list = node;
134 G_UNLOCK (g_tree_global);
139 GTree*
140 g_tree_new (GCompareFunc key_compare_func)
142 GRealTree *rtree;
144 g_return_val_if_fail (key_compare_func != NULL, NULL);
146 rtree = g_new (GRealTree, 1);
147 rtree->root = NULL;
148 rtree->key_compare = key_compare_func;
150 return (GTree*) rtree;
153 void
154 g_tree_destroy (GTree *tree)
156 GRealTree *rtree;
158 g_return_if_fail (tree != NULL);
160 rtree = (GRealTree*) tree;
162 g_tree_node_destroy (rtree->root);
163 g_free (rtree);
166 void
167 g_tree_insert (GTree *tree,
168 gpointer key,
169 gpointer value)
171 GRealTree *rtree;
172 gint inserted;
174 g_return_if_fail (tree != NULL);
176 rtree = (GRealTree*) tree;
178 inserted = FALSE;
179 rtree->root = g_tree_node_insert (rtree->root, rtree->key_compare,
180 key, value, &inserted);
183 void
184 g_tree_remove (GTree *tree,
185 gpointer key)
187 GRealTree *rtree;
189 g_return_if_fail (tree != NULL);
191 rtree = (GRealTree*) tree;
193 rtree->root = g_tree_node_remove (rtree->root, rtree->key_compare, key);
196 gpointer
197 g_tree_lookup (GTree *tree,
198 gpointer key)
200 GRealTree *rtree;
202 g_return_val_if_fail (tree != NULL, NULL);
204 rtree = (GRealTree*) tree;
206 return g_tree_node_lookup (rtree->root, rtree->key_compare, key);
209 void
210 g_tree_traverse (GTree *tree,
211 GTraverseFunc traverse_func,
212 GTraverseType traverse_type,
213 gpointer data)
215 GRealTree *rtree;
217 g_return_if_fail (tree != NULL);
219 rtree = (GRealTree*) tree;
221 if (!rtree->root)
222 return;
224 switch (traverse_type)
226 case G_PRE_ORDER:
227 g_tree_node_pre_order (rtree->root, traverse_func, data);
228 break;
230 case G_IN_ORDER:
231 g_tree_node_in_order (rtree->root, traverse_func, data);
232 break;
234 case G_POST_ORDER:
235 g_tree_node_post_order (rtree->root, traverse_func, data);
236 break;
238 case G_LEVEL_ORDER:
239 g_warning ("g_tree_traverse(): traverse type G_LEVEL_ORDER isn't implemented.");
240 break;
244 gpointer
245 g_tree_search (GTree *tree,
246 GSearchFunc search_func,
247 gpointer data)
249 GRealTree *rtree;
251 g_return_val_if_fail (tree != NULL, NULL);
253 rtree = (GRealTree*) tree;
255 if (rtree->root)
256 return g_tree_node_search (rtree->root, search_func, data);
257 else
258 return NULL;
261 gint
262 g_tree_height (GTree *tree)
264 GRealTree *rtree;
266 g_return_val_if_fail (tree != NULL, 0);
268 rtree = (GRealTree*) tree;
270 if (rtree->root)
271 return g_tree_node_height (rtree->root);
272 else
273 return 0;
276 gint
277 g_tree_nnodes (GTree *tree)
279 GRealTree *rtree;
281 g_return_val_if_fail (tree != NULL, 0);
283 rtree = (GRealTree*) tree;
285 if (rtree->root)
286 return g_tree_node_count (rtree->root);
287 else
288 return 0;
291 static GTreeNode*
292 g_tree_node_insert (GTreeNode *node,
293 GCompareFunc compare,
294 gpointer key,
295 gpointer value,
296 gint *inserted)
298 gint old_balance;
299 gint cmp;
301 if (!node)
303 *inserted = TRUE;
304 return g_tree_node_new (key, value);
307 cmp = (* compare) (key, node->key);
308 if (cmp == 0)
310 *inserted = FALSE;
311 node->value = value;
312 return node;
315 if (cmp < 0)
317 if (node->left)
319 old_balance = node->left->balance;
320 node->left = g_tree_node_insert (node->left, compare, key, value, inserted);
322 if ((old_balance != node->left->balance) && node->left->balance)
323 node->balance -= 1;
325 else
327 *inserted = TRUE;
328 node->left = g_tree_node_new (key, value);
329 node->balance -= 1;
332 else if (cmp > 0)
334 if (node->right)
336 old_balance = node->right->balance;
337 node->right = g_tree_node_insert (node->right, compare, key, value, inserted);
339 if ((old_balance != node->right->balance) && node->right->balance)
340 node->balance += 1;
342 else
344 *inserted = TRUE;
345 node->right = g_tree_node_new (key, value);
346 node->balance += 1;
350 if (*inserted)
352 if ((node->balance < -1) || (node->balance > 1))
353 node = g_tree_node_balance (node);
356 return node;
359 static GTreeNode*
360 g_tree_node_remove (GTreeNode *node,
361 GCompareFunc compare,
362 gpointer key)
364 GTreeNode *new_root;
365 gint old_balance;
366 gint cmp;
368 if (!node)
369 return NULL;
371 cmp = (* compare) (key, node->key);
372 if (cmp == 0)
374 GTreeNode *garbage;
376 garbage = node;
378 if (!node->right)
380 node = node->left;
382 else
384 old_balance = node->right->balance;
385 node->right = g_tree_node_remove_leftmost (node->right, &new_root);
386 new_root->left = node->left;
387 new_root->right = node->right;
388 new_root->balance = node->balance;
389 node = g_tree_node_restore_right_balance (new_root, old_balance);
392 G_LOCK (g_tree_global);
393 garbage->right = node_free_list;
394 node_free_list = garbage;
395 G_UNLOCK (g_tree_global);
397 else if (cmp < 0)
399 if (node->left)
401 old_balance = node->left->balance;
402 node->left = g_tree_node_remove (node->left, compare, key);
403 node = g_tree_node_restore_left_balance (node, old_balance);
406 else if (cmp > 0)
408 if (node->right)
410 old_balance = node->right->balance;
411 node->right = g_tree_node_remove (node->right, compare, key);
412 node = g_tree_node_restore_right_balance (node, old_balance);
416 return node;
419 static GTreeNode*
420 g_tree_node_balance (GTreeNode *node)
422 if (node->balance < -1)
424 if (node->left->balance > 0)
425 node->left = g_tree_node_rotate_left (node->left);
426 node = g_tree_node_rotate_right (node);
428 else if (node->balance > 1)
430 if (node->right->balance < 0)
431 node->right = g_tree_node_rotate_right (node->right);
432 node = g_tree_node_rotate_left (node);
435 return node;
438 static GTreeNode*
439 g_tree_node_remove_leftmost (GTreeNode *node,
440 GTreeNode **leftmost)
442 gint old_balance;
444 if (!node->left)
446 *leftmost = node;
447 return node->right;
450 old_balance = node->left->balance;
451 node->left = g_tree_node_remove_leftmost (node->left, leftmost);
452 return g_tree_node_restore_left_balance (node, old_balance);
455 static GTreeNode*
456 g_tree_node_restore_left_balance (GTreeNode *node,
457 gint old_balance)
459 if (!node->left)
460 node->balance += 1;
461 else if ((node->left->balance != old_balance) &&
462 (node->left->balance == 0))
463 node->balance += 1;
465 if (node->balance > 1)
466 return g_tree_node_balance (node);
467 return node;
470 static GTreeNode*
471 g_tree_node_restore_right_balance (GTreeNode *node,
472 gint old_balance)
474 if (!node->right)
475 node->balance -= 1;
476 else if ((node->right->balance != old_balance) &&
477 (node->right->balance == 0))
478 node->balance -= 1;
480 if (node->balance < -1)
481 return g_tree_node_balance (node);
482 return node;
485 static gpointer
486 g_tree_node_lookup (GTreeNode *node,
487 GCompareFunc compare,
488 gpointer key)
490 gint cmp;
492 if (!node)
493 return NULL;
495 cmp = (* compare) (key, node->key);
496 if (cmp == 0)
497 return node->value;
499 if (cmp < 0)
501 if (node->left)
502 return g_tree_node_lookup (node->left, compare, key);
504 else if (cmp > 0)
506 if (node->right)
507 return g_tree_node_lookup (node->right, compare, key);
510 return NULL;
513 static gint
514 g_tree_node_count (GTreeNode *node)
516 gint count;
518 count = 1;
519 if (node->left)
520 count += g_tree_node_count (node->left);
521 if (node->right)
522 count += g_tree_node_count (node->right);
524 return count;
527 static gint
528 g_tree_node_pre_order (GTreeNode *node,
529 GTraverseFunc traverse_func,
530 gpointer data)
532 if ((*traverse_func) (node->key, node->value, data))
533 return TRUE;
534 if (node->left)
536 if (g_tree_node_pre_order (node->left, traverse_func, data))
537 return TRUE;
539 if (node->right)
541 if (g_tree_node_pre_order (node->right, traverse_func, data))
542 return TRUE;
545 return FALSE;
548 static gint
549 g_tree_node_in_order (GTreeNode *node,
550 GTraverseFunc traverse_func,
551 gpointer data)
553 if (node->left)
555 if (g_tree_node_in_order (node->left, traverse_func, data))
556 return TRUE;
558 if ((*traverse_func) (node->key, node->value, data))
559 return TRUE;
560 if (node->right)
562 if (g_tree_node_in_order (node->right, traverse_func, data))
563 return TRUE;
566 return FALSE;
569 static gint
570 g_tree_node_post_order (GTreeNode *node,
571 GTraverseFunc traverse_func,
572 gpointer data)
574 if (node->left)
576 if (g_tree_node_post_order (node->left, traverse_func, data))
577 return TRUE;
579 if (node->right)
581 if (g_tree_node_post_order (node->right, traverse_func, data))
582 return TRUE;
584 if ((*traverse_func) (node->key, node->value, data))
585 return TRUE;
587 return FALSE;
590 static gpointer
591 g_tree_node_search (GTreeNode *node,
592 GSearchFunc search_func,
593 gpointer data)
595 gint dir;
597 if (!node)
598 return NULL;
600 do {
601 dir = (* search_func) (node->key, data);
602 if (dir == 0)
603 return node->value;
605 if (dir < 0)
606 node = node->left;
607 else if (dir > 0)
608 node = node->right;
609 } while (node && (dir != 0));
611 return NULL;
614 static gint
615 g_tree_node_height (GTreeNode *node)
617 gint left_height;
618 gint right_height;
620 if (node)
622 left_height = 0;
623 right_height = 0;
625 if (node->left)
626 left_height = g_tree_node_height (node->left);
628 if (node->right)
629 right_height = g_tree_node_height (node->right);
631 return MAX (left_height, right_height) + 1;
634 return 0;
637 static GTreeNode*
638 g_tree_node_rotate_left (GTreeNode *node)
640 GTreeNode *left;
641 GTreeNode *right;
642 gint a_bal;
643 gint b_bal;
645 left = node->left;
646 right = node->right;
648 node->right = right->left;
649 right->left = node;
651 a_bal = node->balance;
652 b_bal = right->balance;
654 if (b_bal <= 0)
656 if (a_bal >= 1)
657 right->balance = b_bal - 1;
658 else
659 right->balance = a_bal + b_bal - 2;
660 node->balance = a_bal - 1;
662 else
664 if (a_bal <= b_bal)
665 right->balance = a_bal - 2;
666 else
667 right->balance = b_bal - 1;
668 node->balance = a_bal - b_bal - 1;
671 return right;
674 static GTreeNode*
675 g_tree_node_rotate_right (GTreeNode *node)
677 GTreeNode *left;
678 GTreeNode *right;
679 gint a_bal;
680 gint b_bal;
682 left = node->left;
683 right = node->right;
685 node->left = left->right;
686 left->right = node;
688 a_bal = node->balance;
689 b_bal = left->balance;
691 if (b_bal <= 0)
693 if (b_bal > a_bal)
694 left->balance = b_bal + 1;
695 else
696 left->balance = a_bal + 2;
697 node->balance = a_bal - b_bal + 1;
699 else
701 if (a_bal <= -1)
702 left->balance = b_bal + 1;
703 else
704 left->balance = a_bal + b_bal + 2;
705 node->balance = a_bal + 1;
708 return left;
711 static void
712 g_tree_node_check (GTreeNode *node)
714 gint left_height;
715 gint right_height;
716 gint balance;
718 if (node)
720 left_height = 0;
721 right_height = 0;
723 if (node->left)
724 left_height = g_tree_node_height (node->left);
725 if (node->right)
726 right_height = g_tree_node_height (node->right);
728 balance = right_height - left_height;
729 if (balance != node->balance)
730 g_log (g_log_domain_glib, G_LOG_LEVEL_INFO,
731 "g_tree_node_check: failed: %d ( %d )\n",
732 balance, node->balance);
734 if (node->left)
735 g_tree_node_check (node->left);
736 if (node->right)
737 g_tree_node_check (node->right);