mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-02-12 13:49:22 +01:00
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.
This commit is contained in:
parent
e502a2345c
commit
5272119ce9
14
ChangeLog
14
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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -20,6 +20,7 @@ libglib_1_1_la_SOURCES = \
|
||||
glist.c \
|
||||
gmem.c \
|
||||
gmessages.c \
|
||||
gnode.c \
|
||||
gprimes.c \
|
||||
gslist.c \
|
||||
gtimer.c \
|
||||
|
111
glib.h
111
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
|
||||
*/
|
||||
|
||||
|
@ -20,6 +20,7 @@ libglib_1_1_la_SOURCES = \
|
||||
glist.c \
|
||||
gmem.c \
|
||||
gmessages.c \
|
||||
gnode.c \
|
||||
gprimes.c \
|
||||
gslist.c \
|
||||
gtimer.c \
|
||||
|
111
glib/glib.h
111
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
|
||||
*/
|
||||
|
||||
|
887
glib/gnode.c
Normal file
887
glib/gnode.c
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
887
gnode.c
Normal file
887
gnode.c
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
4
gtree.c
4
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
158
testglib.c
158
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);
|
||||
|
158
tests/testglib.c
158
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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user