summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Janik <timj@gtk.org>1998-07-31 20:21:10 +0000
committerTim Janik <timj@src.gnome.org>1998-07-31 20:21:10 +0000
commit5272119ce910740d98415f70c662bbb8942a4a5f (patch)
treed982d8b5bf9347600720a85e28e734468bbe49cb
parente502a2345c2a1bb3868389578e2dc83fe0416b67 (diff)
added a GNode test.
Fri Jul 31 22:17:05 1998 Tim Janik <timj@gtk.org> * testglib.c (g_node_test): added a GNode test. Fri Jul 31 09:08:16 1998 Tim Janik <timj@gtk.org> * Makefile.am: compile gnode.c. * glib.h: * gnode.c: added implementation of n-way trees. * gtree.c (g_tree_traverse): added a warning to the switch() statement which says that G_LEVEL_ORDER is not implemented.
-rw-r--r--ChangeLog14
-rw-r--r--ChangeLog.pre-2-014
-rw-r--r--ChangeLog.pre-2-1014
-rw-r--r--ChangeLog.pre-2-1214
-rw-r--r--ChangeLog.pre-2-214
-rw-r--r--ChangeLog.pre-2-414
-rw-r--r--ChangeLog.pre-2-614
-rw-r--r--ChangeLog.pre-2-814
-rw-r--r--Makefile.am1
-rw-r--r--glib.h111
-rw-r--r--glib/Makefile.am1
-rw-r--r--glib/glib.h111
-rw-r--r--glib/gnode.c887
-rw-r--r--glib/gtree.c4
-rw-r--r--gnode.c887
-rw-r--r--gtree.c4
-rw-r--r--testglib.c158
-rw-r--r--tests/testglib.c158
18 files changed, 2428 insertions, 6 deletions
diff --git a/ChangeLog b/ChangeLog
index e334e34f9..9ba7458ca 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+Fri Jul 31 22:17:05 1998 Tim Janik <timj@gtk.org>
+
+ * testglib.c (g_node_test): added a GNode test.
+
+Fri Jul 31 09:08:16 1998 Tim Janik <timj@gtk.org>
+
+ * Makefile.am: compile gnode.c.
+
+ * glib.h:
+ * gnode.c: added implementation of n-way trees.
+
+ * gtree.c (g_tree_traverse): added a warning to the switch() statement
+ which says that G_LEVEL_ORDER is not implemented.
+
Mon Jul 27 00:17:30 CDT 1998 Shawn T. Amundson <amundson@gtk.org>
* Released GLib 1.1.0
diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0
index e334e34f9..9ba7458ca 100644
--- a/ChangeLog.pre-2-0
+++ b/ChangeLog.pre-2-0
@@ -1,3 +1,17 @@
+Fri Jul 31 22:17:05 1998 Tim Janik <timj@gtk.org>
+
+ * testglib.c (g_node_test): added a GNode test.
+
+Fri Jul 31 09:08:16 1998 Tim Janik <timj@gtk.org>
+
+ * Makefile.am: compile gnode.c.
+
+ * glib.h:
+ * gnode.c: added implementation of n-way trees.
+
+ * gtree.c (g_tree_traverse): added a warning to the switch() statement
+ which says that G_LEVEL_ORDER is not implemented.
+
Mon Jul 27 00:17:30 CDT 1998 Shawn T. Amundson <amundson@gtk.org>
* Released GLib 1.1.0
diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10
index e334e34f9..9ba7458ca 100644
--- a/ChangeLog.pre-2-10
+++ b/ChangeLog.pre-2-10
@@ -1,3 +1,17 @@
+Fri Jul 31 22:17:05 1998 Tim Janik <timj@gtk.org>
+
+ * testglib.c (g_node_test): added a GNode test.
+
+Fri Jul 31 09:08:16 1998 Tim Janik <timj@gtk.org>
+
+ * Makefile.am: compile gnode.c.
+
+ * glib.h:
+ * gnode.c: added implementation of n-way trees.
+
+ * gtree.c (g_tree_traverse): added a warning to the switch() statement
+ which says that G_LEVEL_ORDER is not implemented.
+
Mon Jul 27 00:17:30 CDT 1998 Shawn T. Amundson <amundson@gtk.org>
* Released GLib 1.1.0
diff --git a/ChangeLog.pre-2-12 b/ChangeLog.pre-2-12
index e334e34f9..9ba7458ca 100644
--- a/ChangeLog.pre-2-12
+++ b/ChangeLog.pre-2-12
@@ -1,3 +1,17 @@
+Fri Jul 31 22:17:05 1998 Tim Janik <timj@gtk.org>
+
+ * testglib.c (g_node_test): added a GNode test.
+
+Fri Jul 31 09:08:16 1998 Tim Janik <timj@gtk.org>
+
+ * Makefile.am: compile gnode.c.
+
+ * glib.h:
+ * gnode.c: added implementation of n-way trees.
+
+ * gtree.c (g_tree_traverse): added a warning to the switch() statement
+ which says that G_LEVEL_ORDER is not implemented.
+
Mon Jul 27 00:17:30 CDT 1998 Shawn T. Amundson <amundson@gtk.org>
* Released GLib 1.1.0
diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2
index e334e34f9..9ba7458ca 100644
--- a/ChangeLog.pre-2-2
+++ b/ChangeLog.pre-2-2
@@ -1,3 +1,17 @@
+Fri Jul 31 22:17:05 1998 Tim Janik <timj@gtk.org>
+
+ * testglib.c (g_node_test): added a GNode test.
+
+Fri Jul 31 09:08:16 1998 Tim Janik <timj@gtk.org>
+
+ * Makefile.am: compile gnode.c.
+
+ * glib.h:
+ * gnode.c: added implementation of n-way trees.
+
+ * gtree.c (g_tree_traverse): added a warning to the switch() statement
+ which says that G_LEVEL_ORDER is not implemented.
+
Mon Jul 27 00:17:30 CDT 1998 Shawn T. Amundson <amundson@gtk.org>
* Released GLib 1.1.0
diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4
index e334e34f9..9ba7458ca 100644
--- a/ChangeLog.pre-2-4
+++ b/ChangeLog.pre-2-4
@@ -1,3 +1,17 @@
+Fri Jul 31 22:17:05 1998 Tim Janik <timj@gtk.org>
+
+ * testglib.c (g_node_test): added a GNode test.
+
+Fri Jul 31 09:08:16 1998 Tim Janik <timj@gtk.org>
+
+ * Makefile.am: compile gnode.c.
+
+ * glib.h:
+ * gnode.c: added implementation of n-way trees.
+
+ * gtree.c (g_tree_traverse): added a warning to the switch() statement
+ which says that G_LEVEL_ORDER is not implemented.
+
Mon Jul 27 00:17:30 CDT 1998 Shawn T. Amundson <amundson@gtk.org>
* Released GLib 1.1.0
diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6
index e334e34f9..9ba7458ca 100644
--- a/ChangeLog.pre-2-6
+++ b/ChangeLog.pre-2-6
@@ -1,3 +1,17 @@
+Fri Jul 31 22:17:05 1998 Tim Janik <timj@gtk.org>
+
+ * testglib.c (g_node_test): added a GNode test.
+
+Fri Jul 31 09:08:16 1998 Tim Janik <timj@gtk.org>
+
+ * Makefile.am: compile gnode.c.
+
+ * glib.h:
+ * gnode.c: added implementation of n-way trees.
+
+ * gtree.c (g_tree_traverse): added a warning to the switch() statement
+ which says that G_LEVEL_ORDER is not implemented.
+
Mon Jul 27 00:17:30 CDT 1998 Shawn T. Amundson <amundson@gtk.org>
* Released GLib 1.1.0
diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8
index e334e34f9..9ba7458ca 100644
--- a/ChangeLog.pre-2-8
+++ b/ChangeLog.pre-2-8
@@ -1,3 +1,17 @@
+Fri Jul 31 22:17:05 1998 Tim Janik <timj@gtk.org>
+
+ * testglib.c (g_node_test): added a GNode test.
+
+Fri Jul 31 09:08:16 1998 Tim Janik <timj@gtk.org>
+
+ * Makefile.am: compile gnode.c.
+
+ * glib.h:
+ * gnode.c: added implementation of n-way trees.
+
+ * gtree.c (g_tree_traverse): added a warning to the switch() statement
+ which says that G_LEVEL_ORDER is not implemented.
+
Mon Jul 27 00:17:30 CDT 1998 Shawn T. Amundson <amundson@gtk.org>
* Released GLib 1.1.0
diff --git a/Makefile.am b/Makefile.am
index 7bcc118cd..50faf48ef 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -20,6 +20,7 @@ libglib_1_1_la_SOURCES = \
glist.c \
gmem.c \
gmessages.c \
+ gnode.c \
gprimes.c \
gslist.c \
gtimer.c \
diff --git a/glib.h b/glib.h
index 69ad8adcb..b48ed1108 100644
--- a/glib.h
+++ b/glib.h
@@ -475,6 +475,7 @@ typedef union _GValue GValue;
typedef struct _GCompletion GCompletion;
typedef struct _GRelation GRelation;
typedef struct _GTuples GTuples;
+typedef struct _GNode GNode;
typedef void (*GFunc) (gpointer data,
@@ -488,6 +489,10 @@ typedef void (*GCacheDestroyFunc) (gpointer value);
typedef gint (*GTraverseFunc) (gpointer key,
gpointer value,
gpointer data);
+typedef gboolean (*GNodeTraverseFunc) (GNode *node,
+ gpointer data);
+typedef void (*GNodeForeachFunc) (GNode *node,
+ gpointer data);
typedef gint (*GSearchFunc) (gpointer key,
gpointer data);
typedef void (*GErrorFunc) (gchar *str);
@@ -562,9 +567,18 @@ typedef enum
{
G_IN_ORDER,
G_PRE_ORDER,
- G_POST_ORDER
+ G_POST_ORDER,
+ G_LEVEL_ORDER
} GTraverseType;
+typedef enum
+{
+ G_TRAVERSE_LEAFS = 1 << 0,
+ G_TRAVERSE_NON_LEAFS = 1 << 1,
+ G_TRAVERSE_ALL = G_TRAVERSE_LEAFS | G_TRAVERSE_NON_LEAFS,
+ G_TRAVERSE_MASK = 0x03
+} GTraverseFlags;
+
/* Doubly linked lists
*/
GList* g_list_alloc (void);
@@ -707,7 +721,7 @@ void g_cache_value_foreach (GCache *cache,
gpointer user_data);
-/* Trees
+/* Balanced binary trees
*/
GTree* g_tree_new (GCompareFunc key_compare_func);
void g_tree_destroy (GTree *tree);
@@ -729,6 +743,99 @@ gint g_tree_height (GTree *tree);
gint g_tree_nnodes (GTree *tree);
+
+/* N-way tree implementation
+ */
+struct _GNode
+{
+ GNode *prev;
+ GNode *next;
+ GNode *parent;
+ GNode *children;
+
+ gpointer data;
+};
+
+#define G_NODE_IS_ROOT(node) (((GNode*) (node))->parent == NULL && \
+ ((GNode*) (node))->prev == NULL && \
+ ((GNode*) (node))->next == NULL)
+#define G_NODE_IS_LEAF(node) (((GNode*) (node))->children == NULL)
+
+GNode* g_node_new (gpointer data);
+void g_node_destroy (GNode *root);
+void g_node_unlink (GNode *node);
+void g_node_insert (GNode *parent,
+ gint position,
+ GNode *node);
+void g_node_insert_before (GNode *parent,
+ GNode *sibling,
+ GNode *node);
+void g_node_prepend (GNode *parent,
+ GNode *node);
+guint g_node_n_nodes (GNode *root,
+ GTraverseFlags flags);
+GNode* g_node_get_root (GNode *node);
+gboolean g_node_is_ancestor (GNode *node,
+ GNode *descendant);
+guint g_node_depth (GNode *node);
+GNode* g_node_find (GNode *root,
+ GTraverseType order,
+ GTraverseFlags flags,
+ gpointer data);
+
+/* traversal function, assumes that `node' is root
+ * (only traverses `node' and its subtree).
+ * this function is just a high level interface to
+ * low level traversal functions, optimized for speed.
+ */
+void g_node_traverse (GNode *root,
+ GTraverseType order,
+ GTraverseFlags flags,
+ gint max_depth,
+ GNodeTraverseFunc func,
+ gpointer data);
+
+/* return the maximum tree height starting with `node', this is an expensive
+ * operation, since we need to visit all nodes. this could be shortened by
+ * adding `guint height' to struct _GNode, but then again, this is not very
+ * often needed, and would make g_node_insert() more time consuming.
+ */
+guint g_node_max_height (GNode *root);
+
+void g_node_children_foreach (GNode *node,
+ GTraverseFlags flags,
+ GNodeForeachFunc func,
+ gpointer data);
+void g_node_reverse_children (GNode *node);
+guint g_node_n_children (GNode *node);
+GNode* g_node_nth_child (GNode *node,
+ guint n);
+GNode* g_node_last_child (GNode *node);
+GNode* g_node_find_child (GNode *node,
+ GTraverseFlags flags,
+ gpointer data);
+gint g_node_child_position (GNode *node,
+ GNode *child);
+gint g_node_child_index (GNode *node,
+ gpointer data);
+
+GNode* g_node_first_sibling (GNode *node);
+GNode* g_node_last_sibling (GNode *node);
+
+#define g_node_prev_sibling(node) ((node) ? \
+ ((GNode*) (node))->prev : NULL)
+#define g_node_next_sibling(node) ((node) ? \
+ ((GNode*) (node))->next : NULL)
+#define g_node_first_child(node) ((node) ? \
+ ((GNode*) (node))->children : NULL)
+#define g_node_append(parent, node) G_STMT_START { \
+ g_node_insert_before ((parent), \
+ NULL, \
+ (node)); \
+ } G_STMT_END
+
+
+
/* Memory
*/
diff --git a/glib/Makefile.am b/glib/Makefile.am
index 7bcc118cd..50faf48ef 100644
--- a/glib/Makefile.am
+++ b/glib/Makefile.am
@@ -20,6 +20,7 @@ libglib_1_1_la_SOURCES = \
glist.c \
gmem.c \
gmessages.c \
+ gnode.c \
gprimes.c \
gslist.c \
gtimer.c \
diff --git a/glib/glib.h b/glib/glib.h
index 69ad8adcb..b48ed1108 100644
--- a/glib/glib.h
+++ b/glib/glib.h
@@ -475,6 +475,7 @@ typedef union _GValue GValue;
typedef struct _GCompletion GCompletion;
typedef struct _GRelation GRelation;
typedef struct _GTuples GTuples;
+typedef struct _GNode GNode;
typedef void (*GFunc) (gpointer data,
@@ -488,6 +489,10 @@ typedef void (*GCacheDestroyFunc) (gpointer value);
typedef gint (*GTraverseFunc) (gpointer key,
gpointer value,
gpointer data);
+typedef gboolean (*GNodeTraverseFunc) (GNode *node,
+ gpointer data);
+typedef void (*GNodeForeachFunc) (GNode *node,
+ gpointer data);
typedef gint (*GSearchFunc) (gpointer key,
gpointer data);
typedef void (*GErrorFunc) (gchar *str);
@@ -562,9 +567,18 @@ typedef enum
{
G_IN_ORDER,
G_PRE_ORDER,
- G_POST_ORDER
+ G_POST_ORDER,
+ G_LEVEL_ORDER
} GTraverseType;
+typedef enum
+{
+ G_TRAVERSE_LEAFS = 1 << 0,
+ G_TRAVERSE_NON_LEAFS = 1 << 1,
+ G_TRAVERSE_ALL = G_TRAVERSE_LEAFS | G_TRAVERSE_NON_LEAFS,
+ G_TRAVERSE_MASK = 0x03
+} GTraverseFlags;
+
/* Doubly linked lists
*/
GList* g_list_alloc (void);
@@ -707,7 +721,7 @@ void g_cache_value_foreach (GCache *cache,
gpointer user_data);
-/* Trees
+/* Balanced binary trees
*/
GTree* g_tree_new (GCompareFunc key_compare_func);
void g_tree_destroy (GTree *tree);
@@ -729,6 +743,99 @@ gint g_tree_height (GTree *tree);
gint g_tree_nnodes (GTree *tree);
+
+/* N-way tree implementation
+ */
+struct _GNode
+{
+ GNode *prev;
+ GNode *next;
+ GNode *parent;
+ GNode *children;
+
+ gpointer data;
+};
+
+#define G_NODE_IS_ROOT(node) (((GNode*) (node))->parent == NULL && \
+ ((GNode*) (node))->prev == NULL && \
+ ((GNode*) (node))->next == NULL)
+#define G_NODE_IS_LEAF(node) (((GNode*) (node))->children == NULL)
+
+GNode* g_node_new (gpointer data);
+void g_node_destroy (GNode *root);
+void g_node_unlink (GNode *node);
+void g_node_insert (GNode *parent,
+ gint position,
+ GNode *node);
+void g_node_insert_before (GNode *parent,
+ GNode *sibling,
+ GNode *node);
+void g_node_prepend (GNode *parent,
+ GNode *node);
+guint g_node_n_nodes (GNode *root,
+ GTraverseFlags flags);
+GNode* g_node_get_root (GNode *node);
+gboolean g_node_is_ancestor (GNode *node,
+ GNode *descendant);
+guint g_node_depth (GNode *node);
+GNode* g_node_find (GNode *root,
+ GTraverseType order,
+ GTraverseFlags flags,
+ gpointer data);
+
+/* traversal function, assumes that `node' is root
+ * (only traverses `node' and its subtree).
+ * this function is just a high level interface to
+ * low level traversal functions, optimized for speed.
+ */
+void g_node_traverse (GNode *root,
+ GTraverseType order,
+ GTraverseFlags flags,
+ gint max_depth,
+ GNodeTraverseFunc func,
+ gpointer data);
+
+/* return the maximum tree height starting with `node', this is an expensive
+ * operation, since we need to visit all nodes. this could be shortened by
+ * adding `guint height' to struct _GNode, but then again, this is not very
+ * often needed, and would make g_node_insert() more time consuming.
+ */
+guint g_node_max_height (GNode *root);
+
+void g_node_children_foreach (GNode *node,
+ GTraverseFlags flags,
+ GNodeForeachFunc func,
+ gpointer data);
+void g_node_reverse_children (GNode *node);
+guint g_node_n_children (GNode *node);
+GNode* g_node_nth_child (GNode *node,
+ guint n);
+GNode* g_node_last_child (GNode *node);
+GNode* g_node_find_child (GNode *node,
+ GTraverseFlags flags,
+ gpointer data);
+gint g_node_child_position (GNode *node,
+ GNode *child);
+gint g_node_child_index (GNode *node,
+ gpointer data);
+
+GNode* g_node_first_sibling (GNode *node);
+GNode* g_node_last_sibling (GNode *node);
+
+#define g_node_prev_sibling(node) ((node) ? \
+ ((GNode*) (node))->prev : NULL)
+#define g_node_next_sibling(node) ((node) ? \
+ ((GNode*) (node))->next : NULL)
+#define g_node_first_child(node) ((node) ? \
+ ((GNode*) (node))->children : NULL)
+#define g_node_append(parent, node) G_STMT_START { \
+ g_node_insert_before ((parent), \
+ NULL, \
+ (node)); \
+ } G_STMT_END
+
+
+
/* Memory
*/
diff --git a/glib/gnode.c b/glib/gnode.c
new file mode 100644
index 000000000..2279de212
--- /dev/null
+++ b/glib/gnode.c
@@ -0,0 +1,887 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * GNode: N-way tree implementation.
+ * Copyright (C) 1998 Tim Janik
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#include "glib.h"
+
+
+#define KEEP_NODES (1024)
+
+
+/* --- variables --- */
+static GMemChunk *g_tree_node_chunk = NULL;
+static GNode *free_nodes = NULL;
+static guint n_free_nodes = 0;
+
+
+/* --- functions --- */
+GNode*
+g_node_new (gpointer data)
+{
+ register GNode *node;
+
+ if (!g_tree_node_chunk)
+ g_tree_node_chunk = g_mem_chunk_create (GNode, 1024, G_ALLOC_AND_FREE);
+
+ if (n_free_nodes)
+ {
+ node = free_nodes;
+ free_nodes = free_nodes->next;
+ n_free_nodes--;
+ }
+ else
+ node = g_chunk_new (GNode, g_tree_node_chunk);
+
+ node->prev = NULL;
+ node->next = NULL;
+ node->parent = NULL;
+ node->children = NULL;
+ node->data = data;
+
+ return node;
+}
+
+static void
+g_node_free (GNode *parent)
+{
+ GNode *node;
+
+ node = parent->children;
+
+ while (node)
+ {
+ register GNode *free_node;
+
+ free_node = node;
+ node = free_node->next;
+ g_node_free (free_node);
+ }
+
+ if (n_free_nodes < KEEP_NODES)
+ {
+ parent->next = free_nodes;
+ free_nodes = parent;
+ n_free_nodes++;
+ }
+ else
+ g_chunk_free (parent, g_tree_node_chunk);
+}
+
+void
+g_node_destroy (GNode *root)
+{
+ g_return_if_fail (root != NULL);
+
+ if (!G_NODE_IS_ROOT (root))
+ g_node_unlink (root);
+
+ g_node_free (root);
+}
+
+void
+g_node_unlink (GNode *node)
+{
+ g_return_if_fail (node != NULL);
+
+ if (node->prev)
+ node->prev->next = node->next;
+ else if (node->parent)
+ node->parent->children = node->next;
+ node->parent = NULL;
+ if (node->next)
+ {
+ node->next->prev = node->prev;
+ node->next = NULL;
+ }
+ node->prev = NULL;
+}
+
+void
+g_node_insert (GNode *parent,
+ gint position,
+ GNode *node)
+{
+ g_return_if_fail (parent != NULL);
+ g_return_if_fail (node != NULL);
+ g_return_if_fail (G_NODE_IS_ROOT (node));
+
+ if (position > 0)
+ g_node_insert_before (parent,
+ g_node_nth_child (parent, position),
+ node);
+ else if (position == 0)
+ g_node_prepend (parent, node);
+ else if (position < 0)
+ g_node_append (parent, node);
+}
+
+void
+g_node_insert_before (GNode *parent,
+ GNode *sibling,
+ GNode *node)
+{
+ g_return_if_fail (parent != NULL);
+ g_return_if_fail (node != NULL);
+ g_return_if_fail (G_NODE_IS_ROOT (node));
+ if (sibling)
+ g_return_if_fail (sibling->parent == parent);
+
+ node->parent = parent;
+
+ if (sibling)
+ {
+ if (sibling->prev)
+ {
+ node->prev = sibling->prev;
+ node->prev->next = node;
+ node->next = sibling;
+ sibling->prev = node;
+ }
+ else
+ {
+ node->parent->children = node;
+ node->next = sibling;
+ sibling->prev = node;
+ }
+ }
+ else
+ {
+ if (parent->children)
+ {
+ sibling = parent->children;
+ while (sibling->next)
+ sibling = sibling->next;
+ node->prev = sibling;
+ sibling->next = node;
+ }
+ else
+ node->parent->children = node;
+ }
+}
+
+void
+g_node_prepend (GNode *parent,
+ GNode *node)
+{
+ g_return_if_fail (parent != NULL);
+
+ g_node_insert_before (parent, parent->children, node);
+}
+
+GNode*
+g_node_get_root (GNode *node)
+{
+ g_return_val_if_fail (node != NULL, NULL);
+
+ while (node->parent)
+ node = node->parent;
+
+ return node;
+}
+
+gboolean
+g_node_is_ancestor (GNode *node,
+ GNode *descendant)
+{
+ g_return_val_if_fail (node != NULL, FALSE);
+ g_return_val_if_fail (descendant != NULL, FALSE);
+
+ while (descendant)
+ {
+ if (descendant->parent == node)
+ return TRUE;
+
+ descendant = descendant->parent;
+ }
+
+ return FALSE;
+}
+
+/* returns 1 for root, 2 for first level children,
+ * 3 for children's children...
+ */
+guint
+g_node_depth (GNode *node)
+{
+ register guint depth = 0;
+
+ while (node)
+ {
+ depth++;
+ node = node->parent;
+ }
+
+ return depth;
+}
+
+void
+g_node_reverse_children (GNode *node)
+{
+ GNode *child;
+ GNode *last;
+
+ g_return_if_fail (node != NULL);
+
+ child = node->children;
+ last = NULL;
+ while (child)
+ {
+ last = child;
+ child = last->next;
+ last->next = last->prev;
+ last->prev = child;
+ }
+ node->children = last;
+}
+
+guint
+g_node_max_height (GNode *root)
+{
+ register GNode *child;
+ register guint max_height = 0;
+
+ if (!root)
+ return 0;
+
+ child = root->children;
+ while (child)
+ {
+ register guint tmp_height;
+
+ tmp_height = g_node_max_height (child);
+ if (tmp_height > max_height)
+ max_height = tmp_height;
+ child = child->next;
+ }
+
+ return max_height + 1;
+}
+
+static gboolean
+g_node_traverse_pre_order (GNode *node,
+ GTraverseFlags flags,
+ GNodeTraverseFunc func,
+ gpointer data)
+{
+ if (node->children)
+ {
+ GNode *child;
+
+ if ((flags & G_TRAVERSE_NON_LEAFS) &&
+ func (node, data))
+ return TRUE;
+
+ child = node->children;
+ while (child)
+ {
+ register GNode *current;
+
+ current = child;
+ child = current->next;
+ if (g_node_traverse_pre_order (current, flags, func, data))
+ return TRUE;
+ }
+ }
+ else if ((flags & G_TRAVERSE_LEAFS) &&
+ func (node, data))
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean
+g_node_depth_traverse_pre_order (GNode *node,
+ GTraverseFlags flags,
+ guint depth,
+ GNodeTraverseFunc func,
+ gpointer data)
+{
+ if (node->children)
+ {
+ GNode *child;
+
+ if ((flags & G_TRAVERSE_NON_LEAFS) &&
+ func (node, data))
+ return TRUE;
+
+ depth--;
+ if (!depth)
+ return FALSE;
+
+ child = node->children;
+ while (child)
+ {
+ register GNode *current;
+
+ current = child;
+ child = current->next;
+ if (g_node_depth_traverse_pre_order (current, flags, depth, func, data))
+ return TRUE;
+ }
+ }
+ else if ((flags & G_TRAVERSE_LEAFS) &&
+ func (node, data))
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean
+g_node_traverse_post_order (GNode *node,
+ GTraverseFlags flags,
+ GNodeTraverseFunc func,
+ gpointer data)
+{
+ if (node->children)
+ {
+ GNode *child;
+
+ child = node->children;
+ while (child)
+ {
+ register GNode *current;
+
+ current = child;
+ child = current->next;
+ if (g_node_traverse_post_order (current, flags, func, data))
+ return TRUE;
+ }
+
+ if ((flags & G_TRAVERSE_NON_LEAFS) &&
+ func (node, data))
+ return TRUE;
+
+ }
+ else if ((flags & G_TRAVERSE_LEAFS) &&
+ func (node, data))
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean
+g_node_depth_traverse_post_order (GNode *node,
+ GTraverseFlags flags,
+ guint depth,
+ GNodeTraverseFunc func,
+ gpointer data)
+{
+ if (node->children)
+ {
+ depth--;
+ if (depth)
+ {
+ GNode *child;
+
+ child = node->children;
+ while (child)
+ {
+ register GNode *current;
+
+ current = child;
+ child = current->next;
+ if (g_node_depth_traverse_post_order (current, flags, depth, func, data))
+ return TRUE;
+ }
+ }
+
+ if ((flags & G_TRAVERSE_NON_LEAFS) &&
+ func (node, data))
+ return TRUE;
+
+ }
+ else if ((flags & G_TRAVERSE_LEAFS) &&
+ func (node, data))
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean
+g_node_traverse_in_order (GNode *node,
+ GTraverseFlags flags,
+ GNodeTraverseFunc func,
+ gpointer data)
+{
+ if (node->children)
+ {
+ GNode *child;
+ register GNode *current;
+
+ child = node->children;
+ current = child;
+ child = current->next;
+
+ if (g_node_traverse_in_order (current, flags, func, data))
+ return TRUE;
+
+ if ((flags & G_TRAVERSE_NON_LEAFS) &&
+ func (node, data))
+ return TRUE;
+
+ while (child)
+ {
+ current = child;
+ child = current->next;
+ if (g_node_traverse_in_order (current, flags, func, data))
+ return TRUE;
+ }
+ }
+ else if ((flags & G_TRAVERSE_LEAFS) &&
+ func (node, data))
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean
+g_node_depth_traverse_in_order (GNode *node,
+ GTraverseFlags flags,
+ guint depth,
+ GNodeTraverseFunc func,
+ gpointer data)
+{
+ if (node->children)
+ {
+ depth--;
+ if (depth)
+ {
+ GNode *child;
+ register GNode *current;
+
+ child = node->children;
+ current = child;
+ child = current->next;
+
+ if (g_node_depth_traverse_in_order (current, flags, depth, func, data))
+ return TRUE;
+
+ if ((flags & G_TRAVERSE_NON_LEAFS) &&
+ func (node, data))
+ return TRUE;
+
+ while (child)
+ {
+ current = child;
+ child = current->next;
+ if (g_node_depth_traverse_in_order (current, flags, depth, func, data))
+ return TRUE;
+ }
+ }
+ else if ((flags & G_TRAVERSE_NON_LEAFS) &&
+ func (node, data))
+ return TRUE;
+ }
+ else if ((flags & G_TRAVERSE_LEAFS) &&
+ func (node, data))
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean
+g_node_traverse_children (GNode *node,
+ GTraverseFlags flags,
+ GNodeTraverseFunc func,
+ gpointer data)
+{
+ GNode *child;
+
+ child = node->children;
+
+ while (child)
+ {
+ register GNode *current;
+
+ current = child;
+ child = current->next;
+
+ if (current->children)
+ {
+ if ((flags & G_TRAVERSE_NON_LEAFS) &&
+ func (current, data))
+ return TRUE;
+ }
+ else if ((flags & G_TRAVERSE_LEAFS) &&
+ func (current, data))
+ return TRUE;
+ }
+
+ child = node->children;
+
+ while (child)
+ {
+ register GNode *current;
+
+ current = child;
+ child = current->next;
+
+ if (current->children &&
+ g_node_traverse_children (current, flags, func, data))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+g_node_depth_traverse_children (GNode *node,
+ GTraverseFlags flags,
+ guint depth,
+ GNodeTraverseFunc func,
+ gpointer data)
+{
+ GNode *child;
+
+ child = node->children;
+
+ while (child)
+ {
+ register GNode *current;
+
+ current = child;
+ child = current->next;
+
+ if (current->children)
+ {
+ if ((flags & G_TRAVERSE_NON_LEAFS) &&
+ func (current, data))
+ return TRUE;
+ }
+ else if ((flags & G_TRAVERSE_LEAFS) &&
+ func (current, data))
+ return TRUE;
+ }
+
+ depth--;
+ if (!depth)
+ return FALSE;
+
+ child = node->children;
+
+ while (child)
+ {
+ register GNode *current;
+
+ current = child;
+ child = current->next;
+
+ if (current->children &&
+ g_node_depth_traverse_children (current, flags, depth, func, data))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+void
+g_node_traverse (GNode *root,
+ GTraverseType order,
+ GTraverseFlags flags,
+ gint depth,
+ GNodeTraverseFunc func,
+ gpointer data)
+{
+ g_return_if_fail (root != NULL);
+ g_return_if_fail (func != NULL);
+ g_return_if_fail (order <= G_LEVEL_ORDER);
+ g_return_if_fail (flags <= G_TRAVERSE_MASK);
+ g_return_if_fail (depth == -1 || depth > 0);
+
+ switch (order)
+ {
+ case G_PRE_ORDER:
+ if (depth < 0)
+ g_node_traverse_pre_order (root, flags, func, data);
+ else
+ g_node_depth_traverse_pre_order (root, flags, depth, func, data);
+ break;
+ case G_POST_ORDER:
+ if (depth < 0)
+ g_node_traverse_post_order (root, flags, func, data);
+ else
+ g_node_depth_traverse_post_order (root, flags, depth, func, data);
+ break;
+ case G_IN_ORDER:
+ if (depth < 0)
+ g_node_traverse_in_order (root, flags, func, data);
+ else
+ g_node_depth_traverse_in_order (root, flags, depth, func, data);
+ break;
+ case G_LEVEL_ORDER:
+ if (root->children)
+ {
+ if (!((flags & G_TRAVERSE_NON_LEAFS) &&
+ func (root, data)))
+ {
+ if (depth < 0)
+ g_node_traverse_children (root, flags, func, data);
+ else
+ {
+ depth--;
+ if (depth)
+ g_node_depth_traverse_children (root, flags, depth, func, data);
+ }
+ }
+ }
+ else if (flags & G_TRAVERSE_LEAFS)
+ func (root, data);
+ break;
+ }
+}
+
+static gboolean
+g_node_find_func (GNode *node,
+ gpointer data)
+{
+ register gpointer *d = data;
+
+ if (*d != node->data)
+ return FALSE;
+
+ *(++d) = node;
+
+ return TRUE;
+}
+
+GNode*
+g_node_find (GNode *root,
+ GTraverseType order,
+ GTraverseFlags flags,
+ gpointer data)
+{
+ gpointer d[2];
+
+ g_return_val_if_fail (root != NULL, NULL);
+ g_return_val_if_fail (order <= G_LEVEL_ORDER, NULL);
+ g_return_val_if_fail (flags <= G_TRAVERSE_MASK, NULL);
+
+ d[0] = data;
+ d[1] = NULL;
+
+ g_node_traverse (root, order, flags, -1, g_node_find_func, d);
+
+ return d[1];
+}
+
+static void
+g_node_count_func (GNode *node,
+ GTraverseFlags flags,
+ guint *n)
+{
+ if (node->children)
+ {
+ GNode *child;
+
+ if (flags & G_TRAVERSE_NON_LEAFS)
+ (*n)++;
+
+ child = node->children;
+ while (child)
+ {
+ g_node_count_func (child, flags, n);
+ child = child->next;
+ }
+ }
+ else if (flags & G_TRAVERSE_LEAFS)
+ (*n)++;
+}
+
+guint
+g_node_n_nodes (GNode *root,
+ GTraverseFlags flags)
+{
+ guint n = 0;
+
+ g_return_val_if_fail (root != NULL, 0);
+ g_return_val_if_fail (flags <= G_TRAVERSE_MASK, 0);
+
+ g_node_count_func (root, flags, &n);
+
+ return n;
+}
+
+GNode*
+g_node_last_child (GNode *node)
+{
+ g_return_val_if_fail (node != NULL, NULL);
+
+ node = node->children;
+ if (node)
+ while (node->next)
+ node = node->next;
+
+ return node;
+}
+
+GNode*
+g_node_nth_child (GNode *node,
+ guint n)
+{
+ g_return_val_if_fail (node != NULL, NULL);
+
+ node = node->children;
+ if (node)
+ while ((n-- > 0) && node)
+ node = node->next;
+
+ return node;
+}
+
+guint
+g_node_n_children (GNode *node)
+{
+ guint n = 0;
+
+ g_return_val_if_fail (node != NULL, 0);
+
+ node = node->children;
+ while (node)
+ {
+ n++;
+ node = node->next;
+ }
+
+ return n;
+}
+
+GNode*
+g_node_find_child (GNode *node,
+ GTraverseFlags flags,
+ gpointer data)
+{
+ g_return_val_if_fail (node != NULL, NULL);
+ g_return_val_if_fail (flags <= G_TRAVERSE_MASK, NULL);
+
+ node = node->children;
+ while (node)
+ {
+ if (node->data == data)
+ {
+ if (G_NODE_IS_LEAF (node))
+ {
+ if (flags & G_TRAVERSE_LEAFS)
+ return node;
+ }
+ else
+ {
+ if (flags & G_TRAVERSE_NON_LEAFS)
+ return node;
+ }
+ }
+ node = node->next;
+ }
+
+ return NULL;
+}
+
+gint
+g_node_child_position (GNode *node,
+ GNode *child)
+{
+ register guint n = 0;
+
+ g_return_val_if_fail (node != NULL, -1);
+ g_return_val_if_fail (child != NULL, -1);
+ g_return_val_if_fail (child->parent == node, -1);
+
+ node = node->children;
+ while (node)
+ {
+ if (node == child)
+ return n;
+ n++;
+ node = node->next;
+ }
+
+ return -1;
+}
+
+gint
+g_node_child_index (GNode *node,
+ gpointer data)
+{
+ register guint n = 0;
+
+ g_return_val_if_fail (node != NULL, -1);
+
+ node = node->children;
+ while (node)
+ {
+ if (node->data == data)
+ return n;
+ n++;
+ node = node->next;
+ }
+
+ return -1;
+}
+
+GNode*
+g_node_first_sibling (GNode *node)
+{
+ g_return_val_if_fail (node != NULL, NULL);
+
+ while (node->prev)
+ node = node->prev;
+
+ return node;
+}
+
+GNode*
+g_node_last_sibling (GNode *node)
+{
+ g_return_val_if_fail (node != NULL, NULL);
+
+ while (node->next)
+ node = node->next;
+
+ return node;
+}
+
+void
+g_node_children_foreach (GNode *node,
+ GTraverseFlags flags,
+ GNodeForeachFunc func,
+ gpointer data)
+{
+ g_return_if_fail (node != NULL);
+ g_return_if_fail (flags <= G_TRAVERSE_MASK);
+ g_return_if_fail (func != NULL);
+
+ node = node->children;
+ while (node)
+ {
+ register GNode *current;
+
+ current = node;
+ node = current->next;
+ if (G_NODE_IS_LEAF (node))
+ {
+ if (flags & G_TRAVERSE_LEAFS)
+ func (current, data);
+ }
+ else
+ {
+ if (flags & G_TRAVERSE_NON_LEAFS)
+ func (current, data);
+ }
+ }
+}
diff --git a/glib/gtree.c b/glib/gtree.c
index 981ff396f..2a3dd8fa4 100644
--- a/glib/gtree.c
+++ b/glib/gtree.c
@@ -177,6 +177,10 @@ g_tree_traverse (GTree *tree,
case G_POST_ORDER:
g_tree_node_post_order (rtree->root, traverse_func, data);
break;
+
+ case G_LEVEL_ORDER:
+ g_warning ("g_tree_traverse(): traverse type G_LEVEL_ORDER isn't implemented.");
+ break;
}
}
diff --git a/gnode.c b/gnode.c
new file mode 100644
index 000000000..2279de212
--- /dev/null
+++ b/gnode.c
@@ -0,0 +1,887 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * GNode: N-way tree implementation.
+ * Copyright (C) 1998 Tim Janik
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#include "glib.h"
+
+
+#define KEEP_NODES (1024)
+
+
+/* --- variables --- */
+static GMemChunk *g_tree_node_chunk = NULL;
+static GNode *free_nodes = NULL;
+static guint n_free_nodes = 0;
+
+
+/* --- functions --- */
+GNode*
+g_node_new (gpointer data)
+{
+ register GNode *node;
+
+ if (!g_tree_node_chunk)
+ g_tree_node_chunk = g_mem_chunk_create (GNode, 1024, G_ALLOC_AND_FREE);
+
+ if (n_free_nodes)
+ {
+ node = free_nodes;
+ free_nodes = free_nodes->next;
+ n_free_nodes--;
+ }
+ else
+ node = g_chunk_new (GNode, g_tree_node_chunk);
+
+ node->prev = NULL;
+ node->next = NULL;
+ node->parent = NULL;
+ node->children = NULL;
+ node->data = data;
+
+ return node;
+}
+
+static void
+g_node_free (GNode *parent)
+{
+ GNode *node;
+
+ node = parent->children;
+
+ while (node)
+ {
+ register GNode *free_node;
+
+ free_node = node;
+ node = free_node->next;
+ g_node_free (free_node);
+ }
+
+ if (n_free_nodes < KEEP_NODES)
+ {
+ parent->next = free_nodes;
+ free_nodes = parent;
+ n_free_nodes++;
+ }
+ else
+ g_chunk_free (parent, g_tree_node_chunk);
+}
+
+void
+g_node_destroy (GNode *root)
+{
+ g_return_if_fail (root != NULL);
+
+ if (!G_NODE_IS_ROOT (root))
+ g_node_unlink (root);
+
+ g_node_free (root);
+}
+
+void
+g_node_unlink (GNode *node)
+{
+ g_return_if_fail (node != NULL);
+
+ if (node->prev)
+ node->prev->next = node->next;
+ else if (node->parent)
+ node->parent->children = node->next;
+ node->parent = NULL;
+ if (node->next)
+ {
+ node->next->prev = node->prev;
+ node->next = NULL;
+ }
+ node->prev = NULL;
+}
+
+void
+g_node_insert (GNode *parent,
+ gint position,
+ GNode *node)
+{
+ g_return_if_fail (parent != NULL);
+ g_return_if_fail (node != NULL);
+ g_return_if_fail (G_NODE_IS_ROOT (node));
+
+ if (position > 0)
+ g_node_insert_before (parent,
+ g_node_nth_child (parent, position),
+ node);
+ else if (position == 0)
+ g_node_prepend (parent, node);
+ else if (position < 0)
+ g_node_append (parent, node);
+}
+
+void
+g_node_insert_before (GNode *parent,
+ GNode *sibling,
+ GNode *node)
+{
+ g_return_if_fail (parent != NULL);
+ g_return_if_fail (node != NULL);
+ g_return_if_fail (G_NODE_IS_ROOT (node));
+ if (sibling)
+ g_return_if_fail (sibling->parent == parent);
+
+ node->parent = parent;
+
+ if (sibling)
+ {
+ if (sibling->prev)
+ {
+ node->prev = sibling->prev;
+ node->prev->next = node;
+ node->next = sibling;
+ sibling->prev = node;
+ }
+ else
+ {
+ node->parent->children = node;
+ node->next = sibling;
+ sibling->prev = node;
+ }
+ }
+ else
+ {
+ if (parent->children)
+ {
+ sibling = parent->children;
+ while (sibling->next)
+ sibling = sibling->next;
+ node->prev = sibling;
+ sibling->next = node;
+ }
+ else
+ node->parent->children = node;
+ }
+}
+
+void
+g_node_prepend (GNode *parent,
+ GNode *node)
+{
+ g_return_if_fail (parent != NULL);
+
+ g_node_insert_before (parent, parent->children, node);
+}
+
+GNode*
+g_node_get_root (GNode *node)
+{
+ g_return_val_if_fail (node != NULL, NULL);
+
+ while (node->parent)
+ node = node->parent;
+
+ return node;
+}
+
+gboolean
+g_node_is_ancestor (GNode *node,
+ GNode *descendant)
+{
+ g_return_val_if_fail (node != NULL, FALSE);
+ g_return_val_if_fail (descendant != NULL, FALSE);
+
+ while (descendant)
+ {
+ if (descendant->parent == node)
+ return TRUE;
+
+ descendant = descendant->parent;
+ }
+
+ return FALSE;
+}
+
+/* returns 1 for root, 2 for first level children,
+ * 3 for children's children...
+ */
+guint
+g_node_depth (GNode *node)
+{
+ register guint depth = 0;
+
+ while (node)
+ {
+ depth++;
+ node = node->parent;
+ }
+
+ return depth;
+}
+
+void
+g_node_reverse_children (GNode *node)
+{
+ GNode *child;
+ GNode *last;
+
+ g_return_if_fail (node != NULL);
+
+ child = node->children;
+ last = NULL;
+ while (child)
+ {
+ last = child;
+ child = last->next;
+ last->next = last->prev;
+ last->prev = child;
+ }
+ node->children = last;
+}
+
+guint
+g_node_max_height (GNode *root)
+{
+ register GNode *child;
+ register guint max_height = 0;
+
+ if (!root)
+ return 0;
+
+ child = root->children;
+ while (child)
+ {
+ register guint tmp_height;
+
+ tmp_height = g_node_max_height (child);
+ if (tmp_height > max_height)
+ max_height = tmp_height;
+ child = child->next;
+ }
+
+ return max_height + 1;
+}
+
+static gboolean
+g_node_traverse_pre_order (GNode *node,
+ GTraverseFlags flags,
+ GNodeTraverseFunc func,
+ gpointer data)
+{
+ if (node->children)
+ {
+ GNode *child;
+
+ if ((flags & G_TRAVERSE_NON_LEAFS) &&
+ func (node, data))
+ return TRUE;
+
+ child = node->children;
+ while (child)
+ {
+ register GNode *current;
+
+ current = child;
+ child = current->next;
+ if (g_node_traverse_pre_order (current, flags, func, data))
+ return TRUE;
+ }
+ }
+ else if ((flags & G_TRAVERSE_LEAFS) &&
+ func (node, data))
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean
+g_node_depth_traverse_pre_order (GNode *node,
+ GTraverseFlags flags,
+ guint depth,
+ GNodeTraverseFunc func,
+ gpointer data)
+{
+ if (node->children)
+ {
+ GNode *child;
+
+ if ((flags & G_TRAVERSE_NON_LEAFS) &&
+ func (node, data))
+ return TRUE;
+
+ depth--;
+ if (!depth)
+ return FALSE;
+
+ child = node->children;
+ while (child)
+ {
+ register GNode *current;
+
+ current = child;
+ child = current->next;
+ if (g_node_depth_traverse_pre_order (current, flags, depth, func, data))
+ return TRUE;
+ }
+ }
+ else if ((flags & G_TRAVERSE_LEAFS) &&
+ func (node, data))
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean
+g_node_traverse_post_order (GNode *node,
+ GTraverseFlags flags,
+ GNodeTraverseFunc func,
+ gpointer data)
+{
+ if (node->children)
+ {
+ GNode *child;
+
+ child = node->children;
+ while (child)
+ {
+ register GNode *current;
+
+ current = child;
+ child = current->next;
+ if (g_node_traverse_post_order (current, flags, func, data))
+ return TRUE;
+ }
+
+ if ((flags & G_TRAVERSE_NON_LEAFS) &&
+ func (node, data))
+ return TRUE;
+
+ }
+ else if ((flags & G_TRAVERSE_LEAFS) &&
+ func (node, data))
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean
+g_node_depth_traverse_post_order (GNode *node,
+ GTraverseFlags flags,
+ guint depth,
+ GNodeTraverseFunc func,
+ gpointer data)
+{
+ if (node->children)
+ {
+ depth--;
+ if (depth)
+ {
+ GNode *child;
+
+ child = node->children;
+ while (child)
+ {
+ register GNode *current;
+
+ current = child;
+ child = current->next;
+ if (g_node_depth_traverse_post_order (current, flags, depth, func, data))
+ return TRUE;
+ }
+ }
+
+ if ((flags & G_TRAVERSE_NON_LEAFS) &&
+ func (node, data))
+ return TRUE;
+
+ }
+ else if ((flags & G_TRAVERSE_LEAFS) &&
+ func (node, data))
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean
+g_node_traverse_in_order (GNode *node,
+ GTraverseFlags flags,
+ GNodeTraverseFunc func,
+ gpointer data)
+{
+ if (node->children)
+ {
+ GNode *child;
+ register GNode *current;
+
+ child = node->children;
+ current = child;
+ child = current->next;
+
+ if (g_node_traverse_in_order (current, flags, func, data))
+ return TRUE;
+
+ if ((flags & G_TRAVERSE_NON_LEAFS) &&
+ func (node, data))
+ return TRUE;
+
+ while (child)
+ {
+ current = child;
+ child = current->next;
+ if (g_node_traverse_in_order (current, flags, func, data))
+ return TRUE;
+ }
+ }
+ else if ((flags & G_TRAVERSE_LEAFS) &&
+ func (node, data))
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean
+g_node_depth_traverse_in_order (GNode *node,
+ GTraverseFlags flags,
+ guint depth,
+ GNodeTraverseFunc func,
+ gpointer data)
+{
+ if (node->children)
+ {
+ depth--;
+ if (depth)
+ {
+ GNode *child;
+ register GNode *current;
+
+ child = node->children;
+ current = child;
+ child = current->next;
+
+ if (g_node_depth_traverse_in_order (current, flags, depth, func, data))
+ return TRUE;
+
+ if ((flags & G_TRAVERSE_NON_LEAFS) &&
+ func (node, data))
+ return TRUE;
+
+ while (child)
+ {
+ current = child;
+ child = current->next;
+ if (g_node_depth_traverse_in_order (current, flags, depth, func, data))
+ return TRUE;
+ }
+ }
+ else if ((flags & G_TRAVERSE_NON_LEAFS) &&
+ func (node, data))
+ return TRUE;
+ }
+ else if ((flags & G_TRAVERSE_LEAFS) &&
+ func (node, data))
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean
+g_node_traverse_children (GNode *node,
+ GTraverseFlags flags,
+ GNodeTraverseFunc func,
+ gpointer data)
+{
+ GNode *child;
+
+ child = node->children;
+
+ while (child)
+ {
+ register GNode *current;
+
+ current = child;
+ child = current->next;
+
+ if (current->children)
+ {
+ if ((flags & G_TRAVERSE_NON_LEAFS) &&
+ func (current, data))
+ return TRUE;
+ }
+ else if ((flags & G_TRAVERSE_LEAFS) &&
+ func (current, data))
+ return TRUE;
+ }
+
+ child = node->children;
+
+ while (child)
+ {
+ register GNode *current;
+
+ current = child;
+ child = current->next;
+
+ if (current->children &&
+ g_node_traverse_children (current, flags, func, data))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+g_node_depth_traverse_children (GNode *node,
+ GTraverseFlags flags,
+ guint depth,
+ GNodeTraverseFunc func,
+ gpointer data)
+{
+ GNode *child;
+
+ child = node->children;
+
+ while (child)
+ {
+ register GNode *current;
+
+ current = child;
+ child = current->next;
+
+ if (current->children)
+ {
+ if ((flags & G_TRAVERSE_NON_LEAFS) &&
+ func (current, data))
+ return TRUE;
+ }
+ else if ((flags & G_TRAVERSE_LEAFS) &&
+ func (current, data))
+ return TRUE;
+ }
+
+ depth--;
+ if (!depth)
+ return FALSE;
+
+ child = node->children;
+
+ while (child)
+ {
+ register GNode *current;
+
+ current = child;
+ child = current->next;
+
+ if (current->children &&
+ g_node_depth_traverse_children (current, flags, depth, func, data))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+void
+g_node_traverse (GNode *root,
+ GTraverseType order,
+ GTraverseFlags flags,
+ gint depth,
+ GNodeTraverseFunc func,
+ gpointer data)
+{
+ g_return_if_fail (root != NULL);
+ g_return_if_fail (func != NULL);
+ g_return_if_fail (order <= G_LEVEL_ORDER);
+ g_return_if_fail (flags <= G_TRAVERSE_MASK);
+ g_return_if_fail (depth == -1 || depth > 0);
+
+ switch (order)
+ {
+ case G_PRE_ORDER:
+ if (depth < 0)
+ g_node_traverse_pre_order (root, flags, func, data);
+ else
+ g_node_depth_traverse_pre_order (root, flags, depth, func, data);
+ break;
+ case G_POST_ORDER:
+ if (depth < 0)
+ g_node_traverse_post_order (root, flags, func, data);
+ else
+ g_node_depth_traverse_post_order (root, flags, depth, func, data);
+ break;
+ case G_IN_ORDER:
+ if (depth < 0)
+ g_node_traverse_in_order (root, flags, func, data);
+ else
+ g_node_depth_traverse_in_order (root, flags, depth, func, data);
+ break;
+ case G_LEVEL_ORDER:
+ if (root->children)
+ {
+ if (!((flags & G_TRAVERSE_NON_LEAFS) &&
+ func (root, data)))
+ {
+ if (depth < 0)
+ g_node_traverse_children (root, flags, func, data);
+ else
+ {
+ depth--;
+ if (depth)
+ g_node_depth_traverse_children (root, flags, depth, func, data);
+ }
+ }
+ }
+ else if (flags & G_TRAVERSE_LEAFS)
+ func (root, data);
+ break;
+ }
+}
+
+static gboolean
+g_node_find_func (GNode *node,
+ gpointer data)
+{
+ register gpointer *d = data;
+
+ if (*d != node->data)
+ return FALSE;
+
+ *(++d) = node;
+
+ return TRUE;
+}
+
+GNode*
+g_node_find (GNode *root,
+ GTraverseType order,
+ GTraverseFlags flags,
+ gpointer data)
+{
+ gpointer d[2];
+
+ g_return_val_if_fail (root != NULL, NULL);
+ g_return_val_if_fail (order <= G_LEVEL_ORDER, NULL);
+ g_return_val_if_fail (flags <= G_TRAVERSE_MASK, NULL);
+
+ d[0] = data;
+ d[1] = NULL;
+
+ g_node_traverse (root, order, flags, -1, g_node_find_func, d);
+
+ return d[1];
+}
+
+static void
+g_node_count_func (GNode *node,
+ GTraverseFlags flags,
+ guint *n)
+{
+ if (node->children)
+ {
+ GNode *child;
+
+ if (flags & G_TRAVERSE_NON_LEAFS)
+ (*n)++;
+
+ child = node->children;
+ while (child)
+ {
+ g_node_count_func (child, flags, n);
+ child = child->next;
+ }
+ }
+ else if (flags & G_TRAVERSE_LEAFS)
+ (*n)++;
+}
+
+guint
+g_node_n_nodes (GNode *root,
+ GTraverseFlags flags)
+{
+ guint n = 0;
+
+ g_return_val_if_fail (root != NULL, 0);
+ g_return_val_if_fail (flags <= G_TRAVERSE_MASK, 0);
+
+ g_node_count_func (root, flags, &n);
+
+ return n;
+}
+
+GNode*
+g_node_last_child (GNode *node)
+{
+ g_return_val_if_fail (node != NULL, NULL);
+
+ node = node->children;
+ if (node)
+ while (node->next)
+ node = node->next;
+
+ return node;
+}
+
+GNode*
+g_node_nth_child (GNode *node,
+ guint n)
+{
+ g_return_val_if_fail (node != NULL, NULL);
+
+ node = node->children;
+ if (node)
+ while ((n-- > 0) && node)
+ node = node->next;
+
+ return node;
+}
+
+guint
+g_node_n_children (GNode *node)
+{
+ guint n = 0;
+
+ g_return_val_if_fail (node != NULL, 0);
+
+ node = node->children;
+ while (node)
+ {
+ n++;
+ node = node->next;
+ }
+
+ return n;
+}
+
+GNode*
+g_node_find_child (GNode *node,
+ GTraverseFlags flags,
+ gpointer data)
+{
+ g_return_val_if_fail (node != NULL, NULL);
+ g_return_val_if_fail (flags <= G_TRAVERSE_MASK, NULL);
+
+ node = node->children;
+ while (node)
+ {
+ if (node->data == data)
+ {
+ if (G_NODE_IS_LEAF (node))
+ {
+ if (flags & G_TRAVERSE_LEAFS)
+ return node;
+ }
+ else
+ {
+ if (flags & G_TRAVERSE_NON_LEAFS)
+ return node;
+ }
+ }
+ node = node->next;
+ }
+
+ return NULL;
+}
+
+gint
+g_node_child_position (GNode *node,
+ GNode *child)
+{
+ register guint n = 0;
+
+ g_return_val_if_fail (node != NULL, -1);
+ g_return_val_if_fail (child != NULL, -1);
+ g_return_val_if_fail (child->parent == node, -1);
+
+ node = node->children;
+ while (node)
+ {
+ if (node == child)
+ return n;
+ n++;
+ node = node->next;
+ }
+
+ return -1;
+}
+
+gint
+g_node_child_index (GNode *node,
+ gpointer data)
+{
+ register guint n = 0;
+
+ g_return_val_if_fail (node != NULL, -1);
+
+ node = node->children;
+ while (node)
+ {
+ if (node->data == data)
+ return n;
+ n++;
+ node = node->next;
+ }
+
+ return -1;
+}
+
+GNode*
+g_node_first_sibling (GNode *node)
+{
+ g_return_val_if_fail (node != NULL, NULL);
+
+ while (node->prev)
+ node = node->prev;
+
+ return node;
+}
+
+GNode*
+g_node_last_sibling (GNode *node)
+{
+ g_return_val_if_fail (node != NULL, NULL);
+
+ while (node->next)
+ node = node->next;
+
+ return node;
+}
+
+void
+g_node_children_foreach (GNode *node,
+ GTraverseFlags flags,
+ GNodeForeachFunc func,
+ gpointer data)
+{
+ g_return_if_fail (node != NULL);
+ g_return_if_fail (flags <= G_TRAVERSE_MASK);
+ g_return_if_fail (func != NULL);
+
+ node = node->children;
+ while (node)
+ {
+ register GNode *current;
+
+ current = node;
+ node = current->next;
+ if (G_NODE_IS_LEAF (node))
+ {
+ if (flags & G_TRAVERSE_LEAFS)
+ func (current, data);
+ }
+ else
+ {
+ if (flags & G_TRAVERSE_NON_LEAFS)
+ func (current, data);
+ }
+ }
+}
diff --git a/gtree.c b/gtree.c
index 981ff396f..2a3dd8fa4 100644
--- a/gtree.c
+++ b/gtree.c
@@ -177,6 +177,10 @@ g_tree_traverse (GTree *tree,
case G_POST_ORDER:
g_tree_node_post_order (rtree->root, traverse_func, data);
break;
+
+ case G_LEVEL_ORDER:
+ g_warning ("g_tree_traverse(): traverse type G_LEVEL_ORDER isn't implemented.");
+ break;
}
}
diff --git a/testglib.c b/testglib.c
index d89e76386..4fd5f7bf4 100644
--- a/testglib.c
+++ b/testglib.c
@@ -22,6 +22,159 @@
#include "glib.h"
int array[10000];
+gboolean failed = FALSE;
+
+#define TEST(m,cond) G_STMT_START { failed = !(cond); \
+if (failed) \
+ { if (!m) \
+ g_print ("\n(%s:%d) failed for: %s\n", __FILE__, __LINE__, ( # cond )); \
+ else \
+ g_print ("\n(%s:%d) failed for: %s: (%s)\n", __FILE__, __LINE__, ( # cond ), (gchar*)m); \
+ } \
+else \
+ g_print ("."); fflush (stdout); \
+} G_STMT_END
+
+#define C2P(c) ((gpointer) ((long) (c)))
+#define P2C(p) ((gchar) ((long) (p)))
+
+static gboolean
+node_build_string (GNode *node,
+ gpointer data)
+{
+ gchar **p = data;
+ gchar *string;
+ gchar c[2] = "_";
+
+ c[0] = P2C (node->data);
+
+ string = g_strconcat (*p ? *p : "", c, NULL);
+ g_free (*p);
+ *p = string;
+
+ return FALSE;
+}
+
+static void
+g_node_test (void)
+{
+ GNode *root;
+ GNode *node;
+ GNode *node_B;
+ GNode *node_F;
+ GNode *node_G;
+ GNode *node_J;
+ guint i;
+ gchar *tstring;
+
+ g_print ("checking n-way trees: ");
+ failed = FALSE;
+
+ root = g_node_new (C2P ('A'));
+ TEST (NULL, g_node_depth (root) == 1 && g_node_max_height (root) == 1);
+
+ node_B = g_node_new (C2P ('B'));
+ g_node_append (root, node_B);
+ TEST (NULL, root->children == node_B);
+
+ g_node_append (node_B, g_node_new (C2P ('E')));
+ g_node_prepend (node_B, g_node_new (C2P ('C')));
+ g_node_insert (node_B, 1, g_node_new (C2P ('D')));
+
+ node_F = g_node_new (C2P ('F'));
+ g_node_append (root, node_F);
+ TEST (NULL, root->children->next == node_F);
+
+ node_G = g_node_new (C2P ('G'));
+ g_node_append (node_F, node_G);
+ node_J = g_node_new (C2P ('J'));
+ g_node_insert (node_G, -1, node_J);
+ g_node_insert (node_G, 42, g_node_new (C2P ('K')));
+ g_node_insert (node_G, 0, g_node_new (C2P ('H')));
+ g_node_insert (node_G, 1, g_node_new (C2P ('I')));
+
+ TEST (NULL, g_node_depth (root) == 1);
+ TEST (NULL, g_node_max_height (root) == 4);
+ TEST (NULL, g_node_depth (node_G->children->next) == 4);
+ TEST (NULL, g_node_n_nodes (root, G_TRAVERSE_LEAFS) == 7);
+ TEST (NULL, g_node_n_nodes (root, G_TRAVERSE_NON_LEAFS) == 4);
+ TEST (NULL, g_node_n_nodes (root, G_TRAVERSE_ALL) == 11);
+ TEST (NULL, g_node_max_height (node_F) == 3);
+ TEST (NULL, g_node_n_children (node_G) == 4);
+ TEST (NULL, g_node_find_child (root, G_TRAVERSE_ALL, C2P ('F')) == node_F);
+ TEST (NULL, g_node_find (root, G_LEVEL_ORDER, G_TRAVERSE_NON_LEAFS, C2P ('I')) == NULL);
+ TEST (NULL, g_node_find (root, G_IN_ORDER, G_TRAVERSE_LEAFS, C2P ('J')) == node_J);
+
+ for (i = 0; i < g_node_n_children (node_B); i++)
+ {
+ node = g_node_nth_child (node_B, i);
+ TEST (NULL, P2C (node->data) == ('C' + i));
+ }
+
+ for (i = 0; i < g_node_n_children (node_G); i++)
+ TEST (NULL, g_node_child_position (node_G, g_node_nth_child (node_G, i)) == i);
+
+ /* we have built: A
+ * / \
+ * B F
+ * / | \ \
+ * C D E G
+ * / /\ \
+ * H I J K
+ *
+ * for in-order traversal, 'G' is considered to be the "left"
+ * child of 'F', which will cause 'F' to be the last node visited.
+ */
+
+ tstring = NULL;
+ g_node_traverse (root, G_PRE_ORDER, G_TRAVERSE_ALL, -1, node_build_string, &tstring);
+ TEST (tstring, strcmp (tstring, "ABCDEFGHIJK") == 0);
+ g_free (tstring); tstring = NULL;
+ g_node_traverse (root, G_POST_ORDER, G_TRAVERSE_ALL, -1, node_build_string, &tstring);
+ TEST (tstring, strcmp (tstring, "CDEBHIJKGFA") == 0);
+ g_free (tstring); tstring = NULL;
+ g_node_traverse (root, G_IN_ORDER, G_TRAVERSE_ALL, -1, node_build_string, &tstring);
+ TEST (tstring, strcmp (tstring, "CBDEAHGIJKF") == 0);
+ g_free (tstring); tstring = NULL;
+ g_node_traverse (root, G_LEVEL_ORDER, G_TRAVERSE_ALL, -1, node_build_string, &tstring);
+ TEST (tstring, strcmp (tstring, "ABFCDEGHIJK") == 0);
+ g_free (tstring); tstring = NULL;
+
+ g_node_traverse (root, G_LEVEL_ORDER, G_TRAVERSE_LEAFS, -1, node_build_string, &tstring);
+ TEST (tstring, strcmp (tstring, "CDEHIJK") == 0);
+ g_free (tstring); tstring = NULL;
+ g_node_traverse (root, G_PRE_ORDER, G_TRAVERSE_NON_LEAFS, -1, node_build_string, &tstring);
+ TEST (tstring, strcmp (tstring, "ABFG") == 0);
+ g_free (tstring); tstring = NULL;
+
+ g_node_reverse_children (node_B);
+ g_node_reverse_children (node_G);
+
+ g_node_traverse (root, G_LEVEL_ORDER, G_TRAVERSE_ALL, -1, node_build_string, &tstring);
+ TEST (tstring, strcmp (tstring, "ABFEDCGKJIH") == 0);
+ g_free (tstring); tstring = NULL;
+
+ g_node_destroy (root);
+
+ /* allocation tests */
+
+ root = g_node_new (NULL);
+ node = root;
+
+ for (i = 0; i < 2048; i++)
+ {
+ g_node_append (node, g_node_new (NULL));
+ if ((i%5) == 4)
+ node = node->children->next;
+ }
+ TEST (NULL, g_node_max_height (root) > 100);
+ TEST (NULL, g_node_n_nodes (root, G_TRAVERSE_ALL) == 1 + 2048);
+
+ g_node_destroy (root);
+
+ if (!failed)
+ g_print ("ok\n");
+}
void
my_hash_callback (gpointer key,
@@ -268,7 +421,7 @@ main (int argc,
g_print ("ok\n");
- g_print ("checking trees...\n");
+ g_print ("checking binary trees...\n");
tree = g_tree_new (my_compare);
i = 0;
@@ -308,6 +461,9 @@ main (int argc,
g_print ("ok\n");
+ /* check n-way trees */
+ g_node_test ();
+
g_print ("checking mem chunks...");
mem_chunk = g_mem_chunk_new ("test mem chunk", 50, 100, G_ALLOC_AND_FREE);
diff --git a/tests/testglib.c b/tests/testglib.c
index d89e76386..4fd5f7bf4 100644
--- a/tests/testglib.c
+++ b/tests/testglib.c
@@ -22,6 +22,159 @@
#include "glib.h"
int array[10000];
+gboolean failed = FALSE;
+
+#define TEST(m,cond) G_STMT_START { failed = !(cond); \
+if (failed) \
+ { if (!m) \
+ g_print ("\n(%s:%d) failed for: %s\n", __FILE__, __LINE__, ( # cond )); \
+ else \
+ g_print ("\n(%s:%d) failed for: %s: (%s)\n", __FILE__, __LINE__, ( # cond ), (gchar*)m); \
+ } \
+else \
+ g_print ("."); fflush (stdout); \
+} G_STMT_END
+
+#define C2P(c) ((gpointer) ((long) (c)))
+#define P2C(p) ((gchar) ((long) (p)))
+
+static gboolean
+node_build_string (GNode *node,
+ gpointer data)
+{
+ gchar **p = data;
+ gchar *string;
+ gchar c[2] = "_";
+
+ c[0] = P2C (node->data);
+
+ string = g_strconcat (*p ? *p : "", c, NULL);
+ g_free (*p);
+ *p = string;
+
+ return FALSE;
+}
+
+static void
+g_node_test (void)
+{
+ GNode *root;
+ GNode *node;
+ GNode *node_B;
+ GNode *node_F;
+ GNode *node_G;
+ GNode *node_J;
+ guint i;
+ gchar *tstring;
+
+ g_print ("checking n-way trees: ");
+ failed = FALSE;
+
+ root = g_node_new (C2P ('A'));
+ TEST (NULL, g_node_depth (root) == 1 && g_node_max_height (root) == 1);
+
+ node_B = g_node_new (C2P ('B'));
+ g_node_append (root, node_B);
+ TEST (NULL, root->children == node_B);
+
+ g_node_append (node_B, g_node_new (C2P ('E')));
+ g_node_prepend (node_B, g_node_new (C2P ('C')));
+ g_node_insert (node_B, 1, g_node_new (C2P ('D')));
+
+ node_F = g_node_new (C2P ('F'));
+ g_node_append (root, node_F);
+ TEST (NULL, root->children->next == node_F);
+
+ node_G = g_node_new (C2P ('G'));
+ g_node_append (node_F, node_G);
+ node_J = g_node_new (C2P ('J'));
+ g_node_insert (node_G, -1, node_J);
+ g_node_insert (node_G, 42, g_node_new (C2P ('K')));
+ g_node_insert (node_G, 0, g_node_new (C2P ('H')));
+ g_node_insert (node_G, 1, g_node_new (C2P ('I')));
+
+ TEST (NULL, g_node_depth (root) == 1);
+ TEST (NULL, g_node_max_height (root) == 4);
+ TEST (NULL, g_node_depth (node_G->children->next) == 4);
+ TEST (NULL, g_node_n_nodes (root, G_TRAVERSE_LEAFS) == 7);
+ TEST (NULL, g_node_n_nodes (root, G_TRAVERSE_NON_LEAFS) == 4);
+ TEST (NULL, g_node_n_nodes (root, G_TRAVERSE_ALL) == 11);
+ TEST (NULL, g_node_max_height (node_F) == 3);
+ TEST (NULL, g_node_n_children (node_G) == 4);
+ TEST (NULL, g_node_find_child (root, G_TRAVERSE_ALL, C2P ('F')) == node_F);
+ TEST (NULL, g_node_find (root, G_LEVEL_ORDER, G_TRAVERSE_NON_LEAFS, C2P ('I')) == NULL);
+ TEST (NULL, g_node_find (root, G_IN_ORDER, G_TRAVERSE_LEAFS, C2P ('J')) == node_J);
+
+ for (i = 0; i < g_node_n_children (node_B); i++)
+ {
+ node = g_node_nth_child (node_B, i);
+ TEST (NULL, P2C (node->data) == ('C' + i));
+ }
+
+ for (i = 0; i < g_node_n_children (node_G); i++)
+ TEST (NULL, g_node_child_position (node_G, g_node_nth_child (node_G, i)) == i);
+
+ /* we have built: A
+ * / \
+ * B F
+ * / | \ \
+ * C D E G
+ * / /\ \
+ * H I J K
+ *
+ * for in-order traversal, 'G' is considered to be the "left"
+ * child of 'F', which will cause 'F' to be the last node visited.
+ */
+
+ tstring = NULL;
+ g_node_traverse (root, G_PRE_ORDER, G_TRAVERSE_ALL, -1, node_build_string, &tstring);
+ TEST (tstring, strcmp (tstring, "ABCDEFGHIJK") == 0);
+ g_free (tstring); tstring = NULL;
+ g_node_traverse (root, G_POST_ORDER, G_TRAVERSE_ALL, -1, node_build_string, &tstring);
+ TEST (tstring, strcmp (tstring, "CDEBHIJKGFA") == 0);
+ g_free (tstring); tstring = NULL;
+ g_node_traverse (root, G_IN_ORDER, G_TRAVERSE_ALL, -1, node_build_string, &tstring);
+ TEST (tstring, strcmp (tstring, "CBDEAHGIJKF") == 0);
+ g_free (tstring); tstring = NULL;
+ g_node_traverse (root, G_LEVEL_ORDER, G_TRAVERSE_ALL, -1, node_build_string, &tstring);
+ TEST (tstring, strcmp (tstring, "ABFCDEGHIJK") == 0);
+ g_free (tstring); tstring = NULL;
+
+ g_node_traverse (root, G_LEVEL_ORDER, G_TRAVERSE_LEAFS, -1, node_build_string, &tstring);
+ TEST (tstring, strcmp (tstring, "CDEHIJK") == 0);
+ g_free (tstring); tstring = NULL;
+ g_node_traverse (root, G_PRE_ORDER, G_TRAVERSE_NON_LEAFS, -1, node_build_string, &tstring);
+ TEST (tstring, strcmp (tstring, "ABFG") == 0);
+ g_free (tstring); tstring = NULL;
+
+ g_node_reverse_children (node_B);
+ g_node_reverse_children (node_G);
+
+ g_node_traverse (root, G_LEVEL_ORDER, G_TRAVERSE_ALL, -1, node_build_string, &tstring);
+ TEST (tstring, strcmp (tstring, "ABFEDCGKJIH") == 0);
+ g_free (tstring); tstring = NULL;
+
+ g_node_destroy (root);
+
+ /* allocation tests */
+
+ root = g_node_new (NULL);
+ node = root;
+
+ for (i = 0; i < 2048; i++)
+ {
+ g_node_append (node, g_node_new (NULL));
+ if ((i%5) == 4)
+ node = node->children->next;
+ }
+ TEST (NULL, g_node_max_height (root) > 100);
+ TEST (NULL, g_node_n_nodes (root, G_TRAVERSE_ALL) == 1 + 2048);
+
+ g_node_destroy (root);
+
+ if (!failed)
+ g_print ("ok\n");
+}
void
my_hash_callback (gpointer key,
@@ -268,7 +421,7 @@ main (int argc,
g_print ("ok\n");
- g_print ("checking trees...\n");
+ g_print ("checking binary trees...\n");
tree = g_tree_new (my_compare);
i = 0;
@@ -308,6 +461,9 @@ main (int argc,
g_print ("ok\n");
+ /* check n-way trees */
+ g_node_test ();
+
g_print ("checking mem chunks...");
mem_chunk = g_mem_chunk_new ("test mem chunk", 50, 100, G_ALLOC_AND_FREE);