mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-02-14 14:27:14 +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>
|
Mon Jul 27 00:17:30 CDT 1998 Shawn T. Amundson <amundson@gtk.org>
|
||||||
|
|
||||||
* Released GLib 1.1.0
|
* 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>
|
Mon Jul 27 00:17:30 CDT 1998 Shawn T. Amundson <amundson@gtk.org>
|
||||||
|
|
||||||
* Released GLib 1.1.0
|
* 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>
|
Mon Jul 27 00:17:30 CDT 1998 Shawn T. Amundson <amundson@gtk.org>
|
||||||
|
|
||||||
* Released GLib 1.1.0
|
* 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>
|
Mon Jul 27 00:17:30 CDT 1998 Shawn T. Amundson <amundson@gtk.org>
|
||||||
|
|
||||||
* Released GLib 1.1.0
|
* 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>
|
Mon Jul 27 00:17:30 CDT 1998 Shawn T. Amundson <amundson@gtk.org>
|
||||||
|
|
||||||
* Released GLib 1.1.0
|
* 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>
|
Mon Jul 27 00:17:30 CDT 1998 Shawn T. Amundson <amundson@gtk.org>
|
||||||
|
|
||||||
* Released GLib 1.1.0
|
* 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>
|
Mon Jul 27 00:17:30 CDT 1998 Shawn T. Amundson <amundson@gtk.org>
|
||||||
|
|
||||||
* Released GLib 1.1.0
|
* 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>
|
Mon Jul 27 00:17:30 CDT 1998 Shawn T. Amundson <amundson@gtk.org>
|
||||||
|
|
||||||
* Released GLib 1.1.0
|
* Released GLib 1.1.0
|
||||||
|
@ -20,6 +20,7 @@ libglib_1_1_la_SOURCES = \
|
|||||||
glist.c \
|
glist.c \
|
||||||
gmem.c \
|
gmem.c \
|
||||||
gmessages.c \
|
gmessages.c \
|
||||||
|
gnode.c \
|
||||||
gprimes.c \
|
gprimes.c \
|
||||||
gslist.c \
|
gslist.c \
|
||||||
gtimer.c \
|
gtimer.c \
|
||||||
|
111
glib.h
111
glib.h
@ -475,6 +475,7 @@ typedef union _GValue GValue;
|
|||||||
typedef struct _GCompletion GCompletion;
|
typedef struct _GCompletion GCompletion;
|
||||||
typedef struct _GRelation GRelation;
|
typedef struct _GRelation GRelation;
|
||||||
typedef struct _GTuples GTuples;
|
typedef struct _GTuples GTuples;
|
||||||
|
typedef struct _GNode GNode;
|
||||||
|
|
||||||
|
|
||||||
typedef void (*GFunc) (gpointer data,
|
typedef void (*GFunc) (gpointer data,
|
||||||
@ -488,6 +489,10 @@ typedef void (*GCacheDestroyFunc) (gpointer value);
|
|||||||
typedef gint (*GTraverseFunc) (gpointer key,
|
typedef gint (*GTraverseFunc) (gpointer key,
|
||||||
gpointer value,
|
gpointer value,
|
||||||
gpointer data);
|
gpointer data);
|
||||||
|
typedef gboolean (*GNodeTraverseFunc) (GNode *node,
|
||||||
|
gpointer data);
|
||||||
|
typedef void (*GNodeForeachFunc) (GNode *node,
|
||||||
|
gpointer data);
|
||||||
typedef gint (*GSearchFunc) (gpointer key,
|
typedef gint (*GSearchFunc) (gpointer key,
|
||||||
gpointer data);
|
gpointer data);
|
||||||
typedef void (*GErrorFunc) (gchar *str);
|
typedef void (*GErrorFunc) (gchar *str);
|
||||||
@ -562,9 +567,18 @@ typedef enum
|
|||||||
{
|
{
|
||||||
G_IN_ORDER,
|
G_IN_ORDER,
|
||||||
G_PRE_ORDER,
|
G_PRE_ORDER,
|
||||||
G_POST_ORDER
|
G_POST_ORDER,
|
||||||
|
G_LEVEL_ORDER
|
||||||
} GTraverseType;
|
} 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
|
/* Doubly linked lists
|
||||||
*/
|
*/
|
||||||
GList* g_list_alloc (void);
|
GList* g_list_alloc (void);
|
||||||
@ -707,7 +721,7 @@ void g_cache_value_foreach (GCache *cache,
|
|||||||
gpointer user_data);
|
gpointer user_data);
|
||||||
|
|
||||||
|
|
||||||
/* Trees
|
/* Balanced binary trees
|
||||||
*/
|
*/
|
||||||
GTree* g_tree_new (GCompareFunc key_compare_func);
|
GTree* g_tree_new (GCompareFunc key_compare_func);
|
||||||
void g_tree_destroy (GTree *tree);
|
void g_tree_destroy (GTree *tree);
|
||||||
@ -729,6 +743,99 @@ gint g_tree_height (GTree *tree);
|
|||||||
gint g_tree_nnodes (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
|
/* Memory
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ libglib_1_1_la_SOURCES = \
|
|||||||
glist.c \
|
glist.c \
|
||||||
gmem.c \
|
gmem.c \
|
||||||
gmessages.c \
|
gmessages.c \
|
||||||
|
gnode.c \
|
||||||
gprimes.c \
|
gprimes.c \
|
||||||
gslist.c \
|
gslist.c \
|
||||||
gtimer.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 _GCompletion GCompletion;
|
||||||
typedef struct _GRelation GRelation;
|
typedef struct _GRelation GRelation;
|
||||||
typedef struct _GTuples GTuples;
|
typedef struct _GTuples GTuples;
|
||||||
|
typedef struct _GNode GNode;
|
||||||
|
|
||||||
|
|
||||||
typedef void (*GFunc) (gpointer data,
|
typedef void (*GFunc) (gpointer data,
|
||||||
@ -488,6 +489,10 @@ typedef void (*GCacheDestroyFunc) (gpointer value);
|
|||||||
typedef gint (*GTraverseFunc) (gpointer key,
|
typedef gint (*GTraverseFunc) (gpointer key,
|
||||||
gpointer value,
|
gpointer value,
|
||||||
gpointer data);
|
gpointer data);
|
||||||
|
typedef gboolean (*GNodeTraverseFunc) (GNode *node,
|
||||||
|
gpointer data);
|
||||||
|
typedef void (*GNodeForeachFunc) (GNode *node,
|
||||||
|
gpointer data);
|
||||||
typedef gint (*GSearchFunc) (gpointer key,
|
typedef gint (*GSearchFunc) (gpointer key,
|
||||||
gpointer data);
|
gpointer data);
|
||||||
typedef void (*GErrorFunc) (gchar *str);
|
typedef void (*GErrorFunc) (gchar *str);
|
||||||
@ -562,9 +567,18 @@ typedef enum
|
|||||||
{
|
{
|
||||||
G_IN_ORDER,
|
G_IN_ORDER,
|
||||||
G_PRE_ORDER,
|
G_PRE_ORDER,
|
||||||
G_POST_ORDER
|
G_POST_ORDER,
|
||||||
|
G_LEVEL_ORDER
|
||||||
} GTraverseType;
|
} 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
|
/* Doubly linked lists
|
||||||
*/
|
*/
|
||||||
GList* g_list_alloc (void);
|
GList* g_list_alloc (void);
|
||||||
@ -707,7 +721,7 @@ void g_cache_value_foreach (GCache *cache,
|
|||||||
gpointer user_data);
|
gpointer user_data);
|
||||||
|
|
||||||
|
|
||||||
/* Trees
|
/* Balanced binary trees
|
||||||
*/
|
*/
|
||||||
GTree* g_tree_new (GCompareFunc key_compare_func);
|
GTree* g_tree_new (GCompareFunc key_compare_func);
|
||||||
void g_tree_destroy (GTree *tree);
|
void g_tree_destroy (GTree *tree);
|
||||||
@ -729,6 +743,99 @@ gint g_tree_height (GTree *tree);
|
|||||||
gint g_tree_nnodes (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
|
/* 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:
|
case G_POST_ORDER:
|
||||||
g_tree_node_post_order (rtree->root, traverse_func, data);
|
g_tree_node_post_order (rtree->root, traverse_func, data);
|
||||||
break;
|
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:
|
case G_POST_ORDER:
|
||||||
g_tree_node_post_order (rtree->root, traverse_func, data);
|
g_tree_node_post_order (rtree->root, traverse_func, data);
|
||||||
break;
|
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"
|
#include "glib.h"
|
||||||
|
|
||||||
int array[10000];
|
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
|
void
|
||||||
my_hash_callback (gpointer key,
|
my_hash_callback (gpointer key,
|
||||||
@ -268,7 +421,7 @@ main (int argc,
|
|||||||
g_print ("ok\n");
|
g_print ("ok\n");
|
||||||
|
|
||||||
|
|
||||||
g_print ("checking trees...\n");
|
g_print ("checking binary trees...\n");
|
||||||
|
|
||||||
tree = g_tree_new (my_compare);
|
tree = g_tree_new (my_compare);
|
||||||
i = 0;
|
i = 0;
|
||||||
@ -308,6 +461,9 @@ main (int argc,
|
|||||||
g_print ("ok\n");
|
g_print ("ok\n");
|
||||||
|
|
||||||
|
|
||||||
|
/* check n-way trees */
|
||||||
|
g_node_test ();
|
||||||
|
|
||||||
g_print ("checking mem chunks...");
|
g_print ("checking mem chunks...");
|
||||||
|
|
||||||
mem_chunk = g_mem_chunk_new ("test mem chunk", 50, 100, G_ALLOC_AND_FREE);
|
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"
|
#include "glib.h"
|
||||||
|
|
||||||
int array[10000];
|
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
|
void
|
||||||
my_hash_callback (gpointer key,
|
my_hash_callback (gpointer key,
|
||||||
@ -268,7 +421,7 @@ main (int argc,
|
|||||||
g_print ("ok\n");
|
g_print ("ok\n");
|
||||||
|
|
||||||
|
|
||||||
g_print ("checking trees...\n");
|
g_print ("checking binary trees...\n");
|
||||||
|
|
||||||
tree = g_tree_new (my_compare);
|
tree = g_tree_new (my_compare);
|
||||||
i = 0;
|
i = 0;
|
||||||
@ -308,6 +461,9 @@ main (int argc,
|
|||||||
g_print ("ok\n");
|
g_print ("ok\n");
|
||||||
|
|
||||||
|
|
||||||
|
/* check n-way trees */
|
||||||
|
g_node_test ();
|
||||||
|
|
||||||
g_print ("checking mem chunks...");
|
g_print ("checking mem chunks...");
|
||||||
|
|
||||||
mem_chunk = g_mem_chunk_new ("test mem chunk", 50, 100, G_ALLOC_AND_FREE);
|
mem_chunk = g_mem_chunk_new ("test mem chunk", 50, 100, G_ALLOC_AND_FREE);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user