lilypond-1.3.130
[lilypond.git] / lily / scm-bintree.cc
blob7477c1b2d4bce2c372d853ca7762f589ef7908f7
1 /*
2 scm-bintree.cc -- implement binary trees, an experiment in GC.
4 source file of the GNU LilyPond music typesetter
6 (c) 1999 Han-Wen Nienhuys <hanwen@cs.uu.nl>
8 */
10 #include <stdio.h>
11 #include "libc-extension.hh"
12 #include "lily-guile.hh"
13 #include "main.hh"
14 #include "debug.hh"
20 Layout of nodes:
22 (key . (left_child . right_child))
24 SCM_EOL is the nil-pointer (should use SCM_NIMP() ?)
27 #define left_child(s) SCM_CADR((s))
28 #define right_child(s) SCM_CDDR((s))
29 #define key(s) SCM_CAR((s))
32 Garble pointers, to prevent unbalanced tree due to ordered inserts.
35 unsigned int
36 munge (SCM s)
38 const int SHIFT = 18;
39 return (unsigned int)(s << (32-SHIFT) | s >> SHIFT );
42 SCM
43 ly_new_bintree_node (SCM val)
45 return gh_cons (val, gh_cons (SCM_EOL, SCM_EOL));
50 add VAL to TREE. TREE must be non-nil
52 void
53 ly_addto_bintree (SCM *tree, SCM val)
55 while(*tree != SCM_EOL)
57 if (munge (val) <= munge (key (*tree)))
58 tree = &left_child (*tree);
59 else
60 tree = &right_child (*tree);
63 *tree = ly_new_bintree_node (val);
68 find the address of a node in the tree represented by *NODE with key VAL
70 SCM *
71 ly_find_in_bintree (SCM *node, SCM val)
73 while (*node != SCM_EOL)
75 if (munge (val) < munge (key(*node) ))
76 node = &left_child(*node);
77 else if (munge (val) > munge (key (*node)))
78 node = &right_child (*node);
79 else
80 return node;
82 return node;
85 void
86 ly_remove_from_bintree (SCM *node)
88 SCM r = right_child (*node);
89 SCM l = left_child (*node);
91 if (r == SCM_EOL)
93 *node = l;
95 else if (l == SCM_EOL)
97 *node = r;
99 else
101 /*deleting from binary trees. See Knuth's TAOCP.
103 SCM *t = node;
104 SCM *left_t = &left_child (*t);
107 INV: LEFT_T is the left child of T
109 while (*left_t != SCM_EOL)
111 t = left_t;
112 left_t = &left_child (*t);
116 POST: T is the leftmost right child of NODE which has no left child,
118 leftchild (LASTT) == T
120 key(*node) = key(*t);
121 *left_t = right_child (*t);
126 static SCM protect_tree_root;
129 ly_protect_scm (SCM s)
131 ly_addto_bintree (&protect_tree_root, s);
132 return s;
136 ly_unprotect_scm (SCM s)
138 SCM *to_remove = ly_find_in_bintree (&protect_tree_root, s);
141 this shouldn't happen, according to me. But it does.
143 if (*to_remove != SCM_EOL)
144 ly_remove_from_bintree (to_remove);
145 return s;
148 void
149 ly_init_protection ()
151 protect_tree_root = scm_protect_object (ly_new_bintree_node(SCM_EOL));
152 key (protect_tree_root) = protect_tree_root;
157 ly_count_elements (SCM tree)
159 if (tree == SCM_EOL)
160 return 0;
161 else
162 return 1 + ly_count_elements (left_child (tree)) + ly_count_elements (right_child( tree));
166 ly_tree_depth (SCM tree)
168 if (tree == SCM_EOL)
169 return 0;
170 else
171 return 1 + (ly_tree_depth (left_child (tree)) >? ly_tree_depth (right_child(tree)));
174 void
175 ly_print_bintree (SCM node)
177 #ifndef NPRINT
178 if (node == SCM_EOL)
179 return;
180 DOUT << "{val = " << key(node) << " \nleft = ";
181 ly_print_bintree (left_child (node));
182 DOUT << "\n right =";
183 ly_print_bintree (right_child (node));
184 DOUT << "}";
185 #endif
189 struct Imbalance { int imbalance; int total; };
191 Imbalance
192 ly_calc_imbalance (SCM node)
194 Imbalance t;
195 if (node == SCM_EOL)
197 t.imbalance = 0;
198 t.total = 0;
199 return t;
202 Imbalance l = ly_calc_imbalance (left_child (node));
203 Imbalance r = ly_calc_imbalance (right_child (node));
205 t.total = l.total + r.total + 1;
206 int dif = l.total - r.total;
207 if (dif < 0)
208 dif = -dif;
209 t.imbalance = l.imbalance + r.imbalance + dif;
210 return t;