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, see <http://www.gnu.org/licenses/>.
19 * Modified by the GLib Team and others 1997-2000. See the AUTHORS
20 * file for a list of people on the GLib Team. See the ChangeLog
21 * files for a list of changes. These files are distributed with
22 * GLib at ftp://ftp.gtk.org/pub/gtk/.
25 #undef G_DISABLE_ASSERT
34 #define C2P(c) ((gpointer) ((long) (c)))
35 #define P2C(p) ((gchar) ((long) (p)))
43 node_build_string (GNode
*node
,
46 CallbackData
*d
= data
;
48 g_string_append_c (d
->s
, P2C (node
->data
));
59 GTraverseType traverse
;
63 const gchar
*expected
;
78 TraverseData orders
[] = {
79 { G_PRE_ORDER
, G_TRAVERSE_ALL
, -1, -1, "ABCDEFGHIJK" },
80 { G_PRE_ORDER
, G_TRAVERSE_ALL
, 1, -1, "A" },
81 { G_PRE_ORDER
, G_TRAVERSE_ALL
, 2, -1, "ABF" },
82 { G_PRE_ORDER
, G_TRAVERSE_ALL
, 3, -1, "ABCDEFG" },
83 { G_PRE_ORDER
, G_TRAVERSE_ALL
, 3, -1, "ABCDEFG" },
84 { G_POST_ORDER
, G_TRAVERSE_ALL
, -1, -1, "CDEBHIJKGFA" },
85 { G_POST_ORDER
, G_TRAVERSE_ALL
, 1, -1, "A" },
86 { G_POST_ORDER
, G_TRAVERSE_ALL
, 2, -1, "BFA" },
87 { G_POST_ORDER
, G_TRAVERSE_ALL
, 3, -1, "CDEBGFA" },
88 { G_IN_ORDER
, G_TRAVERSE_ALL
, -1, -1, "CBDEAHGIJKF" },
89 { G_IN_ORDER
, G_TRAVERSE_ALL
, 1, -1, "A" },
90 { G_IN_ORDER
, G_TRAVERSE_ALL
, 2, -1, "BAF" },
91 { G_IN_ORDER
, G_TRAVERSE_ALL
, 3, -1, "CBDEAGF" },
92 { G_LEVEL_ORDER
, G_TRAVERSE_ALL
, -1, -1, "ABFCDEGHIJK" },
93 { G_LEVEL_ORDER
, G_TRAVERSE_ALL
, 1, -1, "A" },
94 { G_LEVEL_ORDER
, G_TRAVERSE_ALL
, 2, -1, "ABF" },
95 { G_LEVEL_ORDER
, G_TRAVERSE_ALL
, 3, -1, "ABFCDEG" },
96 { G_LEVEL_ORDER
, G_TRAVERSE_LEAFS
, -1, -1, "CDEHIJK" },
97 { G_LEVEL_ORDER
, G_TRAVERSE_NON_LEAFS
, -1, -1, "ABFG" },
98 { G_PRE_ORDER
, G_TRAVERSE_ALL
, -1, 1, "A" },
99 { G_PRE_ORDER
, G_TRAVERSE_ALL
, -1, 2, "AB" },
100 { G_PRE_ORDER
, G_TRAVERSE_ALL
, -1, 3, "ABC" },
101 { G_PRE_ORDER
, G_TRAVERSE_ALL
, -1, 4, "ABCD" },
102 { G_PRE_ORDER
, G_TRAVERSE_ALL
, -1, 5, "ABCDE" },
103 { G_PRE_ORDER
, G_TRAVERSE_ALL
, -1, 6, "ABCDEF" },
104 { G_PRE_ORDER
, G_TRAVERSE_ALL
, -1, 7, "ABCDEFG" },
105 { G_PRE_ORDER
, G_TRAVERSE_ALL
, -1, 8, "ABCDEFGH" },
106 { G_PRE_ORDER
, G_TRAVERSE_ALL
, -1, 9, "ABCDEFGHI" },
107 { G_PRE_ORDER
, G_TRAVERSE_ALL
, -1, 10, "ABCDEFGHIJ" },
108 { G_PRE_ORDER
, G_TRAVERSE_ALL
, 3, 1, "A" },
109 { G_PRE_ORDER
, G_TRAVERSE_ALL
, 3, 2, "AB" },
110 { G_PRE_ORDER
, G_TRAVERSE_ALL
, 3, 3, "ABC" },
111 { G_PRE_ORDER
, G_TRAVERSE_ALL
, 3, 4, "ABCD" },
112 { G_PRE_ORDER
, G_TRAVERSE_ALL
, 3, 5, "ABCDE" },
113 { G_PRE_ORDER
, G_TRAVERSE_ALL
, 3, 6, "ABCDEF" },
114 { G_PRE_ORDER
, G_TRAVERSE_ALL
, 3, 7, "ABCDEFG" },
115 { G_PRE_ORDER
, G_TRAVERSE_ALL
, 3, 8, "ABCDEFG" },
116 { G_POST_ORDER
, G_TRAVERSE_ALL
, -1, 1, "C" },
117 { G_POST_ORDER
, G_TRAVERSE_ALL
, -1, 2, "CD" },
118 { G_POST_ORDER
, G_TRAVERSE_ALL
, -1, 3, "CDE" },
119 { G_POST_ORDER
, G_TRAVERSE_ALL
, -1, 4, "CDEB" },
120 { G_POST_ORDER
, G_TRAVERSE_ALL
, -1, 5, "CDEBH" },
121 { G_POST_ORDER
, G_TRAVERSE_ALL
, -1, 6, "CDEBHI" },
122 { G_POST_ORDER
, G_TRAVERSE_ALL
, -1, 7, "CDEBHIJ" },
123 { G_POST_ORDER
, G_TRAVERSE_ALL
, -1, 8, "CDEBHIJK" },
124 { G_POST_ORDER
, G_TRAVERSE_ALL
, -1, 9, "CDEBHIJKG" },
125 { G_POST_ORDER
, G_TRAVERSE_ALL
, -1, 10, "CDEBHIJKGF" },
126 { G_POST_ORDER
, G_TRAVERSE_ALL
, 3, 1, "C" },
127 { G_POST_ORDER
, G_TRAVERSE_ALL
, 3, 2, "CD" },
128 { G_POST_ORDER
, G_TRAVERSE_ALL
, 3, 3, "CDE" },
129 { G_POST_ORDER
, G_TRAVERSE_ALL
, 3, 4, "CDEB" },
130 { G_POST_ORDER
, G_TRAVERSE_ALL
, 3, 5, "CDEBG" },
131 { G_POST_ORDER
, G_TRAVERSE_ALL
, 3, 6, "CDEBGF" },
132 { G_POST_ORDER
, G_TRAVERSE_ALL
, 3, 7, "CDEBGFA" },
133 { G_POST_ORDER
, G_TRAVERSE_ALL
, 3, 8, "CDEBGFA" },
134 { G_IN_ORDER
, G_TRAVERSE_ALL
, -1, 1, "C" },
135 { G_IN_ORDER
, G_TRAVERSE_ALL
, -1, 2, "CB" },
136 { G_IN_ORDER
, G_TRAVERSE_ALL
, -1, 3, "CBD" },
137 { G_IN_ORDER
, G_TRAVERSE_ALL
, -1, 4, "CBDE" },
138 { G_IN_ORDER
, G_TRAVERSE_ALL
, -1, 5, "CBDEA" },
139 { G_IN_ORDER
, G_TRAVERSE_ALL
, -1, 6, "CBDEAH" },
140 { G_IN_ORDER
, G_TRAVERSE_ALL
, -1, 7, "CBDEAHG" },
141 { G_IN_ORDER
, G_TRAVERSE_ALL
, -1, 8, "CBDEAHGI" },
142 { G_IN_ORDER
, G_TRAVERSE_ALL
, -1, 9, "CBDEAHGIJ" },
143 { G_IN_ORDER
, G_TRAVERSE_ALL
, -1, 10, "CBDEAHGIJK" },
144 { G_IN_ORDER
, G_TRAVERSE_ALL
, 3, 1, "C" },
145 { G_IN_ORDER
, G_TRAVERSE_ALL
, 3, 2, "CB" },
146 { G_IN_ORDER
, G_TRAVERSE_ALL
, 3, 3, "CBD" },
147 { G_IN_ORDER
, G_TRAVERSE_ALL
, 3, 4, "CBDE" },
148 { G_IN_ORDER
, G_TRAVERSE_ALL
, 3, 5, "CBDEA" },
149 { G_IN_ORDER
, G_TRAVERSE_ALL
, 3, 6, "CBDEAG" },
150 { G_IN_ORDER
, G_TRAVERSE_ALL
, 3, 7, "CBDEAGF" },
151 { G_IN_ORDER
, G_TRAVERSE_ALL
, 3, 8, "CBDEAGF" },
152 { G_LEVEL_ORDER
, G_TRAVERSE_ALL
, -1, 1, "A" },
153 { G_LEVEL_ORDER
, G_TRAVERSE_ALL
, -1, 2, "AB" },
154 { G_LEVEL_ORDER
, G_TRAVERSE_ALL
, -1, 3, "ABF" },
155 { G_LEVEL_ORDER
, G_TRAVERSE_ALL
, -1, 4, "ABFC" },
156 { G_LEVEL_ORDER
, G_TRAVERSE_ALL
, -1, 5, "ABFCD" },
157 { G_LEVEL_ORDER
, G_TRAVERSE_ALL
, -1, 6, "ABFCDE" },
158 { G_LEVEL_ORDER
, G_TRAVERSE_ALL
, -1, 7, "ABFCDEG" },
159 { G_LEVEL_ORDER
, G_TRAVERSE_ALL
, -1, 8, "ABFCDEGH" },
160 { G_LEVEL_ORDER
, G_TRAVERSE_ALL
, -1, 9, "ABFCDEGHI" },
161 { G_LEVEL_ORDER
, G_TRAVERSE_ALL
, -1, 10, "ABFCDEGHIJ" },
162 { G_LEVEL_ORDER
, G_TRAVERSE_ALL
, 3, 1, "A" },
163 { G_LEVEL_ORDER
, G_TRAVERSE_ALL
, 3, 2, "AB" },
164 { G_LEVEL_ORDER
, G_TRAVERSE_ALL
, 3, 3, "ABF" },
165 { G_LEVEL_ORDER
, G_TRAVERSE_ALL
, 3, 4, "ABFC" },
166 { G_LEVEL_ORDER
, G_TRAVERSE_ALL
, 3, 5, "ABFCD" },
167 { G_LEVEL_ORDER
, G_TRAVERSE_ALL
, 3, 6, "ABFCDE" },
168 { G_LEVEL_ORDER
, G_TRAVERSE_ALL
, 3, 7, "ABFCDEG" },
169 { G_LEVEL_ORDER
, G_TRAVERSE_ALL
, 3, 8, "ABFCDEG" },
174 root
= g_node_new (C2P ('A'));
175 node_B
= g_node_new (C2P ('B'));
176 g_node_append (root
, node_B
);
177 g_node_append_data (node_B
, C2P ('E'));
178 g_node_prepend_data (node_B
, C2P ('C'));
179 node_D
= g_node_new (C2P ('D'));
180 g_node_insert (node_B
, 1, node_D
);
181 node_F
= g_node_new (C2P ('F'));
182 g_node_append (root
, node_F
);
183 node_G
= g_node_new (C2P ('G'));
184 g_node_append (node_F
, node_G
);
185 node_J
= g_node_new (C2P ('J'));
186 g_node_prepend (node_G
, node_J
);
187 g_node_insert (node_G
, 42, g_node_new (C2P ('K')));
188 g_node_insert_data (node_G
, 0, C2P ('H'));
189 g_node_insert (node_G
, 1, g_node_new (C2P ('I')));
199 * for in-order traversal, 'G' is considered to be the "left"
200 * child of 'F', which will cause 'F' to be the last node visited.
203 node_C
= node_B
->children
;
204 node_E
= node_D
->next
;
206 n
= g_node_last_sibling (node_C
);
207 g_assert (n
== node_E
);
208 n
= g_node_last_sibling (node_D
);
209 g_assert (n
== node_E
);
210 n
= g_node_last_sibling (node_E
);
211 g_assert (n
== node_E
);
213 data
.s
= g_string_new ("");
214 for (i
= 0; i
< G_N_ELEMENTS (orders
); i
++)
216 g_string_set_size (data
.s
, 0);
217 data
.count
= orders
[i
].limit
;
218 g_node_traverse (root
, orders
[i
].traverse
, orders
[i
].flags
, orders
[i
].depth
, node_build_string
, &data
);
219 g_assert_cmpstr (data
.s
->str
, ==, orders
[i
].expected
);
222 g_node_reverse_children (node_B
);
223 g_node_reverse_children (node_G
);
225 g_string_set_size (data
.s
, 0);
227 g_node_traverse (root
, G_LEVEL_ORDER
, G_TRAVERSE_ALL
, -1, node_build_string
, &data
);
228 g_assert_cmpstr (data
.s
->str
, ==, "ABFEDCGKJIH");
230 g_node_append (node_D
, g_node_new (C2P ('L')));
231 g_node_insert (node_D
, -1, g_node_new (C2P ('M')));
233 g_string_set_size (data
.s
, 0);
235 g_node_traverse (root
, G_LEVEL_ORDER
, G_TRAVERSE_ALL
, -1, node_build_string
, &data
);
236 g_assert_cmpstr (data
.s
->str
, ==, "ABFEDCGLMKJIH");
238 g_node_destroy (root
);
239 g_string_free (data
.s
, TRUE
);
243 construct_test (void)
255 root
= g_node_new (C2P ('A'));
256 g_assert_cmpint (g_node_depth (root
), ==, 1);
257 g_assert_cmpint (g_node_max_height (root
), ==, 1);
259 node_B
= g_node_new (C2P ('B'));
260 g_node_append (root
, node_B
);
261 g_assert (root
->children
== node_B
);
263 g_node_append_data (node_B
, C2P ('E'));
264 g_node_prepend_data (node_B
, C2P ('C'));
265 node_D
= g_node_new (C2P ('D'));
266 g_node_insert (node_B
, 1, node_D
);
268 node_F
= g_node_new (C2P ('F'));
269 g_node_append (root
, node_F
);
270 g_assert (root
->children
->next
== node_F
);
272 node_G
= g_node_new (C2P ('G'));
273 g_node_append (node_F
, node_G
);
274 node_J
= g_node_new (C2P ('J'));
275 g_node_insert_after (node_G
, NULL
, node_J
);
276 g_node_insert (node_G
, 42, g_node_new (C2P ('K')));
277 node_H
= g_node_new (C2P ('H'));
278 g_node_insert_after (node_G
, NULL
, node_H
);
279 g_node_insert (node_G
, 1, g_node_new (C2P ('I')));
289 g_assert_cmpint (g_node_depth (root
), ==, 1);
290 g_assert_cmpint (g_node_max_height (root
), ==, 4);
291 g_assert_cmpint (g_node_depth (node_G
->children
->next
), ==, 4);
292 g_assert_cmpint (g_node_n_nodes (root
, G_TRAVERSE_LEAFS
), ==, 7);
293 g_assert_cmpint (g_node_n_nodes (root
, G_TRAVERSE_NON_LEAFS
), ==, 4);
294 g_assert_cmpint (g_node_n_nodes (root
, G_TRAVERSE_ALL
), ==, 11);
295 g_assert_cmpint (g_node_max_height (node_F
), ==, 3);
296 g_assert_cmpint (g_node_n_children (node_G
), ==, 4);
297 g_assert (g_node_find_child (root
, G_TRAVERSE_ALL
, C2P ('F')) == node_F
);
298 g_assert (g_node_find_child (node_G
, G_TRAVERSE_LEAFS
, C2P ('H')) == node_H
);
299 g_assert (g_node_find_child (root
, G_TRAVERSE_ALL
, C2P ('H')) == NULL
);
300 g_assert (g_node_find (root
, G_LEVEL_ORDER
, G_TRAVERSE_NON_LEAFS
, C2P ('I')) == NULL
);
301 g_assert (g_node_find (root
, G_IN_ORDER
, G_TRAVERSE_LEAFS
, C2P ('J')) == node_J
);
303 for (i
= 0; i
< g_node_n_children (node_B
); i
++)
305 node
= g_node_nth_child (node_B
, i
);
306 g_assert_cmpint (P2C (node
->data
), ==, ('C' + i
));
309 for (i
= 0; i
< g_node_n_children (node_G
); i
++)
310 g_assert_cmpint (g_node_child_position (node_G
, g_node_nth_child (node_G
, i
)), ==, i
);
312 g_node_destroy (root
);
316 allocation_test (void)
322 root
= g_node_new (NULL
);
325 for (i
= 0; i
< 2048; i
++)
327 g_node_append (node
, g_node_new (NULL
));
329 node
= node
->children
->next
;
331 g_assert_cmpint (g_node_max_height (root
), >, 100);
332 g_assert_cmpint (g_node_n_nodes (root
, G_TRAVERSE_ALL
), ==, 1 + 2048);
334 g_node_destroy (root
);
348 root
= g_node_new (C2P ('A'));
349 node_B
= g_node_new (C2P ('B'));
350 g_node_append (root
, node_B
);
351 node_D
= g_node_new (C2P ('D'));
352 g_node_append (root
, node_D
);
353 node_C
= g_node_new (C2P ('C'));
354 g_node_insert_after (root
, node_B
, node_C
);
355 node_E
= g_node_new (C2P ('E'));
356 g_node_append (node_C
, node_E
);
358 g_assert (g_node_get_root (node_E
) == root
);
359 g_assert (g_node_is_ancestor (root
, node_B
));
360 g_assert (g_node_is_ancestor (root
, node_E
));
361 g_assert (!g_node_is_ancestor (node_B
, node_D
));
362 g_assert (g_node_first_sibling (node_D
) == node_B
);
363 g_assert (g_node_first_sibling (node_E
) == node_E
);
364 g_assert (g_node_first_sibling (root
) == root
);
365 g_assert_cmpint (g_node_child_index (root
, C2P ('B')), ==, 0);
366 g_assert_cmpint (g_node_child_index (root
, C2P ('C')), ==, 1);
367 g_assert_cmpint (g_node_child_index (root
, C2P ('D')), ==, 2);
368 g_assert_cmpint (g_node_child_index (root
, C2P ('E')), ==, -1);
370 data
.s
= g_string_new ("");
372 g_node_children_foreach (root
, G_TRAVERSE_ALL
, (GNodeForeachFunc
)node_build_string
, &data
);
373 g_assert_cmpstr (data
.s
->str
, ==, "BCD");
375 g_string_set_size (data
.s
, 0);
377 g_node_children_foreach (root
, G_TRAVERSE_LEAVES
, (GNodeForeachFunc
)node_build_string
, &data
);
378 g_assert_cmpstr (data
.s
->str
, ==, "BD");
380 g_string_set_size (data
.s
, 0);
382 g_node_children_foreach (root
, G_TRAVERSE_NON_LEAVES
, (GNodeForeachFunc
)node_build_string
, &data
);
383 g_assert_cmpstr (data
.s
->str
, ==, "C");
384 g_string_free (data
.s
, TRUE
);
386 g_node_destroy (root
);
390 check_order (GNode
*node
,
393 gchar
**expected
= data
;
396 d
= GPOINTER_TO_INT (node
->data
);
397 g_assert_cmpint (d
, ==, **expected
);
413 * -------- a --------
421 root
= g_node_new (C2P ('a'));
422 node
= bnode
= g_node_append_data (root
, C2P ('b'));
423 g_node_append_data (node
, C2P ('e'));
424 g_node_append_data (node
, C2P ('f'));
425 g_node_append_data (node
, C2P ('g'));
427 node
= cnode
= g_node_append_data (root
, C2P ('c'));
428 g_node_append_data (node
, C2P ('h'));
429 g_node_append_data (node
, C2P ('i'));
430 g_node_append_data (node
, C2P ('j'));
432 node
= g_node_append_data (root
, C2P ('d'));
433 g_node_append_data (node
, C2P ('k'));
434 g_node_append_data (node
, C2P ('l'));
435 g_node_append_data (node
, C2P ('m'));
437 g_node_unlink (cnode
);
439 expected
= "abdefgklm";
440 g_node_traverse (root
, G_LEVEL_ORDER
, G_TRAVERSE_ALL
, -1, check_order
, &expected
);
443 g_node_traverse (root
, G_LEVEL_ORDER
, G_TRAVERSE_ALL
, 1, check_order
, &expected
);
446 g_node_traverse (cnode
, G_LEVEL_ORDER
, G_TRAVERSE_ALL
, -1, check_order
, &expected
);
448 g_node_destroy (bnode
);
451 g_node_traverse (root
, G_LEVEL_ORDER
, G_TRAVERSE_ALL
, -1, check_order
, &expected
);
453 g_node_destroy (root
);
454 g_node_destroy (cnode
);
458 copy_up (gconstpointer src
,
463 l
= GPOINTER_TO_INT (src
);
464 u
= g_ascii_toupper (l
);
466 return GINT_TO_POINTER ((int)u
);
476 root
= g_node_new (C2P ('a'));
477 g_node_append_data (root
, C2P ('b'));
478 g_node_append_data (root
, C2P ('c'));
479 g_node_append_data (root
, C2P ('d'));
482 g_node_traverse (root
, G_LEVEL_ORDER
, G_TRAVERSE_ALL
, -1, check_order
, &expected
);
484 copy
= g_node_copy (root
);
487 g_node_traverse (copy
, G_LEVEL_ORDER
, G_TRAVERSE_ALL
, -1, check_order
, &expected
);
489 g_node_destroy (copy
);
491 copy
= g_node_copy_deep (root
, copy_up
, NULL
);
494 g_node_traverse (copy
, G_LEVEL_ORDER
, G_TRAVERSE_ALL
, -1, check_order
, &expected
);
496 g_node_destroy (copy
);
498 g_node_destroy (root
);
505 g_test_init (&argc
, &argv
, NULL
);
507 g_test_add_func ("/node/allocation", allocation_test
);
508 g_test_add_func ("/node/construction", construct_test
);
509 g_test_add_func ("/node/traversal", traversal_test
);
510 g_test_add_func ("/node/misc", misc_test
);
511 g_test_add_func ("/node/unlink", unlink_test
);
512 g_test_add_func ("/node/copy", copy_test
);
514 return g_test_run ();