Updates to Tomato RAF including NGINX && PHP
[tomato.git] / release / src / router / glib / gtree.c
blobe6c3f19e947044498944c42e9fb75a852a87cd83
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.
21 * Modified by the GLib Team and others 1997-1999. 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 #include "glib.h"
34 typedef struct _GRealTree GRealTree;
35 typedef struct _GTreeNode GTreeNode;
37 struct _GRealTree
39 GTreeNode *root;
40 GCompareFunc key_compare;
43 struct _GTreeNode
45 gint balance; /* height (left) - height (right) */
46 GTreeNode *left; /* left subtree */
47 GTreeNode *right; /* right subtree */
48 gpointer key; /* key for this node */
49 gpointer value; /* value stored at this node */
53 static GTreeNode* g_tree_node_new (gpointer key,
54 gpointer value);
55 static void g_tree_node_destroy (GTreeNode *node);
56 static GTreeNode* g_tree_node_insert (GTreeNode *node,
57 GCompareFunc compare,
58 gpointer key,
59 gpointer value,
60 gint *inserted);
61 static GTreeNode* g_tree_node_remove (GTreeNode *node,
62 GCompareFunc compare,
63 gpointer key);
64 static GTreeNode* g_tree_node_balance (GTreeNode *node);
65 static GTreeNode* g_tree_node_remove_leftmost (GTreeNode *node,
66 GTreeNode **leftmost);
67 static GTreeNode* g_tree_node_restore_left_balance (GTreeNode *node,
68 gint old_balance);
69 static GTreeNode* g_tree_node_restore_right_balance (GTreeNode *node,
70 gint old_balance);
71 static gpointer g_tree_node_lookup (GTreeNode *node,
72 GCompareFunc compare,
73 gpointer key);
74 static gint g_tree_node_count (GTreeNode *node);
75 static gint g_tree_node_pre_order (GTreeNode *node,
76 GTraverseFunc traverse_func,
77 gpointer data);
78 static gint g_tree_node_in_order (GTreeNode *node,
79 GTraverseFunc traverse_func,
80 gpointer data);
81 static gint g_tree_node_post_order (GTreeNode *node,
82 GTraverseFunc traverse_func,
83 gpointer data);
84 static gpointer g_tree_node_search (GTreeNode *node,
85 GSearchFunc search_func,
86 gpointer data);
87 static gint g_tree_node_height (GTreeNode *node);
88 static GTreeNode* g_tree_node_rotate_left (GTreeNode *node);
89 static GTreeNode* g_tree_node_rotate_right (GTreeNode *node);
90 static void g_tree_node_check (GTreeNode *node);
93 G_LOCK_DEFINE_STATIC (g_tree_global);
94 static GMemChunk *node_mem_chunk = NULL;
95 static GTreeNode *node_free_list = NULL;
98 static GTreeNode*
99 g_tree_node_new (gpointer key,
100 gpointer value)
102 GTreeNode *node;
104 G_LOCK (g_tree_global);
105 if (node_free_list)
107 node = node_free_list;
108 node_free_list = node->right;
110 else
112 if (!node_mem_chunk)
113 node_mem_chunk = g_mem_chunk_new ("GLib GTreeNode mem chunk",
114 sizeof (GTreeNode),
115 1024,
116 G_ALLOC_ONLY);
118 node = g_chunk_new (GTreeNode, node_mem_chunk);
120 G_UNLOCK (g_tree_global);
122 node->balance = 0;
123 node->left = NULL;
124 node->right = NULL;
125 node->key = key;
126 node->value = value;
128 return node;
131 static void
132 g_tree_node_destroy (GTreeNode *node)
134 if (node)
136 g_tree_node_destroy (node->right);
137 g_tree_node_destroy (node->left);
138 G_LOCK (g_tree_global);
139 node->right = node_free_list;
140 node_free_list = node;
141 G_UNLOCK (g_tree_global);
146 GTree*
147 g_tree_new (GCompareFunc key_compare_func)
149 GRealTree *rtree;
151 g_return_val_if_fail (key_compare_func != NULL, NULL);
153 rtree = g_new (GRealTree, 1);
154 rtree->root = NULL;
155 rtree->key_compare = key_compare_func;
157 return (GTree*) rtree;
160 void
161 g_tree_destroy (GTree *tree)
163 GRealTree *rtree;
165 g_return_if_fail (tree != NULL);
167 rtree = (GRealTree*) tree;
169 g_tree_node_destroy (rtree->root);
170 g_free (rtree);
173 void
174 g_tree_insert (GTree *tree,
175 gpointer key,
176 gpointer value)
178 GRealTree *rtree;
179 gint inserted;
181 g_return_if_fail (tree != NULL);
183 rtree = (GRealTree*) tree;
185 inserted = FALSE;
186 rtree->root = g_tree_node_insert (rtree->root, rtree->key_compare,
187 key, value, &inserted);
190 void
191 g_tree_remove (GTree *tree,
192 gpointer key)
194 GRealTree *rtree;
196 g_return_if_fail (tree != NULL);
198 rtree = (GRealTree*) tree;
200 rtree->root = g_tree_node_remove (rtree->root, rtree->key_compare, key);
203 gpointer
204 g_tree_lookup (GTree *tree,
205 gpointer key)
207 GRealTree *rtree;
209 g_return_val_if_fail (tree != NULL, NULL);
211 rtree = (GRealTree*) tree;
213 return g_tree_node_lookup (rtree->root, rtree->key_compare, key);
216 void
217 g_tree_traverse (GTree *tree,
218 GTraverseFunc traverse_func,
219 GTraverseType traverse_type,
220 gpointer data)
222 GRealTree *rtree;
224 g_return_if_fail (tree != NULL);
226 rtree = (GRealTree*) tree;
228 if (!rtree->root)
229 return;
231 switch (traverse_type)
233 case G_PRE_ORDER:
234 g_tree_node_pre_order (rtree->root, traverse_func, data);
235 break;
237 case G_IN_ORDER:
238 g_tree_node_in_order (rtree->root, traverse_func, data);
239 break;
241 case G_POST_ORDER:
242 g_tree_node_post_order (rtree->root, traverse_func, data);
243 break;
245 case G_LEVEL_ORDER:
246 g_warning ("g_tree_traverse(): traverse type G_LEVEL_ORDER isn't implemented.");
247 break;
251 gpointer
252 g_tree_search (GTree *tree,
253 GSearchFunc search_func,
254 gpointer data)
256 GRealTree *rtree;
258 g_return_val_if_fail (tree != NULL, NULL);
260 rtree = (GRealTree*) tree;
262 if (rtree->root)
263 return g_tree_node_search (rtree->root, search_func, data);
264 else
265 return NULL;
268 gint
269 g_tree_height (GTree *tree)
271 GRealTree *rtree;
273 g_return_val_if_fail (tree != NULL, 0);
275 rtree = (GRealTree*) tree;
277 if (rtree->root)
278 return g_tree_node_height (rtree->root);
279 else
280 return 0;
283 gint
284 g_tree_nnodes (GTree *tree)
286 GRealTree *rtree;
288 g_return_val_if_fail (tree != NULL, 0);
290 rtree = (GRealTree*) tree;
292 if (rtree->root)
293 return g_tree_node_count (rtree->root);
294 else
295 return 0;
298 static GTreeNode*
299 g_tree_node_insert (GTreeNode *node,
300 GCompareFunc compare,
301 gpointer key,
302 gpointer value,
303 gint *inserted)
305 gint old_balance;
306 gint cmp;
308 if (!node)
310 *inserted = TRUE;
311 return g_tree_node_new (key, value);
314 cmp = (* compare) (key, node->key);
315 if (cmp == 0)
317 *inserted = FALSE;
318 node->value = value;
319 return node;
322 if (cmp < 0)
324 if (node->left)
326 old_balance = node->left->balance;
327 node->left = g_tree_node_insert (node->left, compare, key, value, inserted);
329 if ((old_balance != node->left->balance) && node->left->balance)
330 node->balance -= 1;
332 else
334 *inserted = TRUE;
335 node->left = g_tree_node_new (key, value);
336 node->balance -= 1;
339 else if (cmp > 0)
341 if (node->right)
343 old_balance = node->right->balance;
344 node->right = g_tree_node_insert (node->right, compare, key, value, inserted);
346 if ((old_balance != node->right->balance) && node->right->balance)
347 node->balance += 1;
349 else
351 *inserted = TRUE;
352 node->right = g_tree_node_new (key, value);
353 node->balance += 1;
357 if (*inserted)
359 if ((node->balance < -1) || (node->balance > 1))
360 node = g_tree_node_balance (node);
363 return node;
366 static GTreeNode*
367 g_tree_node_remove (GTreeNode *node,
368 GCompareFunc compare,
369 gpointer key)
371 GTreeNode *new_root;
372 gint old_balance;
373 gint cmp;
375 if (!node)
376 return NULL;
378 cmp = (* compare) (key, node->key);
379 if (cmp == 0)
381 GTreeNode *garbage;
383 garbage = node;
385 if (!node->right)
387 node = node->left;
389 else
391 old_balance = node->right->balance;
392 node->right = g_tree_node_remove_leftmost (node->right, &new_root);
393 new_root->left = node->left;
394 new_root->right = node->right;
395 new_root->balance = node->balance;
396 node = g_tree_node_restore_right_balance (new_root, old_balance);
399 G_LOCK (g_tree_global);
400 garbage->right = node_free_list;
401 node_free_list = garbage;
402 G_UNLOCK (g_tree_global);
404 else if (cmp < 0)
406 if (node->left)
408 old_balance = node->left->balance;
409 node->left = g_tree_node_remove (node->left, compare, key);
410 node = g_tree_node_restore_left_balance (node, old_balance);
413 else if (cmp > 0)
415 if (node->right)
417 old_balance = node->right->balance;
418 node->right = g_tree_node_remove (node->right, compare, key);
419 node = g_tree_node_restore_right_balance (node, old_balance);
423 return node;
426 static GTreeNode*
427 g_tree_node_balance (GTreeNode *node)
429 if (node->balance < -1)
431 if (node->left->balance > 0)
432 node->left = g_tree_node_rotate_left (node->left);
433 node = g_tree_node_rotate_right (node);
435 else if (node->balance > 1)
437 if (node->right->balance < 0)
438 node->right = g_tree_node_rotate_right (node->right);
439 node = g_tree_node_rotate_left (node);
442 return node;
445 static GTreeNode*
446 g_tree_node_remove_leftmost (GTreeNode *node,
447 GTreeNode **leftmost)
449 gint old_balance;
451 if (!node->left)
453 *leftmost = node;
454 return node->right;
457 old_balance = node->left->balance;
458 node->left = g_tree_node_remove_leftmost (node->left, leftmost);
459 return g_tree_node_restore_left_balance (node, old_balance);
462 static GTreeNode*
463 g_tree_node_restore_left_balance (GTreeNode *node,
464 gint old_balance)
466 if (!node->left)
467 node->balance += 1;
468 else if ((node->left->balance != old_balance) &&
469 (node->left->balance == 0))
470 node->balance += 1;
472 if (node->balance > 1)
473 return g_tree_node_balance (node);
474 return node;
477 static GTreeNode*
478 g_tree_node_restore_right_balance (GTreeNode *node,
479 gint old_balance)
481 if (!node->right)
482 node->balance -= 1;
483 else if ((node->right->balance != old_balance) &&
484 (node->right->balance == 0))
485 node->balance -= 1;
487 if (node->balance < -1)
488 return g_tree_node_balance (node);
489 return node;
492 static gpointer
493 g_tree_node_lookup (GTreeNode *node,
494 GCompareFunc compare,
495 gpointer key)
497 gint cmp;
499 if (!node)
500 return NULL;
502 cmp = (* compare) (key, node->key);
503 if (cmp == 0)
504 return node->value;
506 if (cmp < 0)
508 if (node->left)
509 return g_tree_node_lookup (node->left, compare, key);
511 else if (cmp > 0)
513 if (node->right)
514 return g_tree_node_lookup (node->right, compare, key);
517 return NULL;
520 static gint
521 g_tree_node_count (GTreeNode *node)
523 gint count;
525 count = 1;
526 if (node->left)
527 count += g_tree_node_count (node->left);
528 if (node->right)
529 count += g_tree_node_count (node->right);
531 return count;
534 static gint
535 g_tree_node_pre_order (GTreeNode *node,
536 GTraverseFunc traverse_func,
537 gpointer data)
539 if ((*traverse_func) (node->key, node->value, data))
540 return TRUE;
541 if (node->left)
543 if (g_tree_node_pre_order (node->left, traverse_func, data))
544 return TRUE;
546 if (node->right)
548 if (g_tree_node_pre_order (node->right, traverse_func, data))
549 return TRUE;
552 return FALSE;
555 static gint
556 g_tree_node_in_order (GTreeNode *node,
557 GTraverseFunc traverse_func,
558 gpointer data)
560 if (node->left)
562 if (g_tree_node_in_order (node->left, traverse_func, data))
563 return TRUE;
565 if ((*traverse_func) (node->key, node->value, data))
566 return TRUE;
567 if (node->right)
569 if (g_tree_node_in_order (node->right, traverse_func, data))
570 return TRUE;
573 return FALSE;
576 static gint
577 g_tree_node_post_order (GTreeNode *node,
578 GTraverseFunc traverse_func,
579 gpointer data)
581 if (node->left)
583 if (g_tree_node_post_order (node->left, traverse_func, data))
584 return TRUE;
586 if (node->right)
588 if (g_tree_node_post_order (node->right, traverse_func, data))
589 return TRUE;
591 if ((*traverse_func) (node->key, node->value, data))
592 return TRUE;
594 return FALSE;
597 static gpointer
598 g_tree_node_search (GTreeNode *node,
599 GSearchFunc search_func,
600 gpointer data)
602 gint dir;
604 if (!node)
605 return NULL;
607 do {
608 dir = (* search_func) (node->key, data);
609 if (dir == 0)
610 return node->value;
612 if (dir < 0)
613 node = node->left;
614 else if (dir > 0)
615 node = node->right;
616 } while (node && (dir != 0));
618 return NULL;
621 static gint
622 g_tree_node_height (GTreeNode *node)
624 gint left_height;
625 gint right_height;
627 if (node)
629 left_height = 0;
630 right_height = 0;
632 if (node->left)
633 left_height = g_tree_node_height (node->left);
635 if (node->right)
636 right_height = g_tree_node_height (node->right);
638 return MAX (left_height, right_height) + 1;
641 return 0;
644 static GTreeNode*
645 g_tree_node_rotate_left (GTreeNode *node)
647 GTreeNode *left;
648 GTreeNode *right;
649 gint a_bal;
650 gint b_bal;
652 left = node->left;
653 right = node->right;
655 node->right = right->left;
656 right->left = node;
658 a_bal = node->balance;
659 b_bal = right->balance;
661 if (b_bal <= 0)
663 if (a_bal >= 1)
664 right->balance = b_bal - 1;
665 else
666 right->balance = a_bal + b_bal - 2;
667 node->balance = a_bal - 1;
669 else
671 if (a_bal <= b_bal)
672 right->balance = a_bal - 2;
673 else
674 right->balance = b_bal - 1;
675 node->balance = a_bal - b_bal - 1;
678 return right;
681 static GTreeNode*
682 g_tree_node_rotate_right (GTreeNode *node)
684 GTreeNode *left;
685 gint a_bal;
686 gint b_bal;
688 left = node->left;
690 node->left = left->right;
691 left->right = node;
693 a_bal = node->balance;
694 b_bal = left->balance;
696 if (b_bal <= 0)
698 if (b_bal > a_bal)
699 left->balance = b_bal + 1;
700 else
701 left->balance = a_bal + 2;
702 node->balance = a_bal - b_bal + 1;
704 else
706 if (a_bal <= -1)
707 left->balance = b_bal + 1;
708 else
709 left->balance = a_bal + b_bal + 2;
710 node->balance = a_bal + 1;
713 return left;
716 static void
717 g_tree_node_check (GTreeNode *node)
719 gint left_height;
720 gint right_height;
721 gint balance;
723 if (node)
725 left_height = 0;
726 right_height = 0;
728 if (node->left)
729 left_height = g_tree_node_height (node->left);
730 if (node->right)
731 right_height = g_tree_node_height (node->right);
733 balance = right_height - left_height;
734 if (balance != node->balance)
735 g_log (g_log_domain_glib, G_LOG_LEVEL_INFO,
736 "g_tree_node_check: failed: %d ( %d )\n",
737 balance, node->balance);
739 if (node->left)
740 g_tree_node_check (node->left);
741 if (node->right)
742 g_tree_node_check (node->right);