[gtk+/wip/otte/tokenizer: 5/42] gtk: Add an RB tree implementation for use in CSS code
- From: Benjamin Otte <otte src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/wip/otte/tokenizer: 5/42] gtk: Add an RB tree implementation for use in CSS code
- Date: Sun, 20 Mar 2016 05:01:27 +0000 (UTC)
commit c0261412ba791ef9ca1b856b8b999430e89f8ecd
Author: Benjamin Otte <otte redhat com>
Date: Sun Mar 6 13:11:26 2016 +0100
gtk: Add an RB tree implementation for use in CSS code
Some tests included
gtk/Makefile.am | 2 +
gtk/gtkcssrbtree.c | 750 +++++++++++++++++++++++++++++++++++++++++++++
gtk/gtkcssrbtreeprivate.h | 89 ++++++
testsuite/gtk/Makefile.am | 9 +
testsuite/gtk/cssrbtree.c | 253 +++++++++++++++
5 files changed, 1103 insertions(+), 0 deletions(-)
---
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index fe245f2..a73ffa7 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -431,6 +431,7 @@ gtk_private_h_sources = \
gtkcsspathnodeprivate.h \
gtkcsspositionvalueprivate.h \
gtkcssproviderprivate.h \
+ gtkcssrbtreeprivate.h \
gtkcssrepeatvalueprivate.h \
gtkcssrgbavalueprivate.h \
gtkcsssectionprivate.h \
@@ -700,6 +701,7 @@ gtk_base_c_sources = \
gtkcsspathnode.c \
gtkcsspositionvalue.c \
gtkcssprovider.c \
+ gtkcssrbtree.c \
gtkcssrepeatvalue.c \
gtkcssrgbavalue.c \
gtkcsssection.c \
diff --git a/gtk/gtkcssrbtree.c b/gtk/gtkcssrbtree.c
new file mode 100644
index 0000000..7d37e09
--- /dev/null
+++ b/gtk/gtkcssrbtree.c
@@ -0,0 +1,750 @@
+/* gtkrbtree.c
+ * Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford <jrb redhat com>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "gtkcssrbtreeprivate.h"
+
+#include "gtkdebug.h"
+
+typedef struct _GtkCssRbNode GtkCssRbNode;
+
+struct _GtkCssRbTree
+{
+ guint ref_count;
+
+ gsize element_size;
+ gsize augment_size;
+ GtkCssRbTreeAugmentFunc augment_func;
+ GDestroyNotify clear_func;
+ GDestroyNotify clear_augment_func;
+
+ GtkCssRbNode *root;
+};
+
+struct _GtkCssRbNode
+{
+ guint red :1;
+ guint dirty :1;
+
+ GtkCssRbNode *left;
+ GtkCssRbNode *right;
+ GtkCssRbNode *parent;
+};
+
+#define NODE_FROM_POINTER(ptr) ((GtkCssRbNode *) ((ptr) ? (((guchar *) (ptr)) - sizeof (GtkCssRbNode)) :
NULL))
+#define NODE_TO_POINTER(node) ((gpointer) ((node) ? (((guchar *) (node)) + sizeof (GtkCssRbNode)) : NULL))
+#define NODE_TO_AUG_POINTER(tree, node) ((gpointer) ((node) ? (((guchar *) (node)) + sizeof (GtkCssRbNode) +
(tree)->element_size) : NULL))
+
+static inline gsize
+gtk_css_rb_node_get_size (GtkCssRbTree *tree)
+{
+ return sizeof (GtkCssRbNode) + tree->element_size + tree->augment_size;
+}
+
+static GtkCssRbNode *
+gtk_css_rb_node_new (GtkCssRbTree *tree)
+{
+ GtkCssRbNode *result;
+
+ result = g_slice_alloc0 (gtk_css_rb_node_get_size (tree));
+
+ result->red = TRUE;
+ result->dirty = TRUE;
+
+ return result;
+}
+
+static void
+gtk_css_rb_node_free (GtkCssRbTree *tree,
+ GtkCssRbNode *node)
+{
+ if (tree->clear_func)
+ tree->clear_func (NODE_TO_POINTER (node));
+ if (tree->clear_augment_func)
+ tree->clear_augment_func (NODE_TO_AUG_POINTER (tree, node));
+
+ g_slice_free1 (gtk_css_rb_node_get_size (tree), node);
+}
+
+static void
+gtk_css_rb_node_free_deep (GtkCssRbTree *tree,
+ GtkCssRbNode *node)
+{
+ GtkCssRbNode *right = node->right;
+
+ if (node->left)
+ gtk_css_rb_node_free_deep (tree, node->left);
+
+ gtk_css_rb_node_free (tree, node);
+
+ if (right)
+ gtk_css_rb_node_free_deep (tree, right);
+}
+
+static void
+gtk_css_rb_node_mark_dirty (GtkCssRbNode *node,
+ gboolean mark_parent)
+{
+ if (node->dirty)
+ return;
+
+ node->dirty = TRUE;
+
+ if (mark_parent && node->parent)
+ gtk_css_rb_node_mark_dirty (node->parent, TRUE);
+}
+
+static void
+gtk_css_rb_node_clean (GtkCssRbTree *tree,
+ GtkCssRbNode *node)
+{
+ if (!node->dirty)
+ return;
+
+ node->dirty = FALSE;
+ if (tree->augment_func)
+ tree->augment_func (tree,
+ NODE_TO_AUG_POINTER (tree, node),
+ NODE_TO_POINTER (node),
+ NODE_TO_POINTER (node->left),
+ NODE_TO_POINTER (node->right));
+}
+
+static GtkCssRbNode *
+gtk_css_rb_node_get_first (GtkCssRbNode *node)
+{
+ while (node->left)
+ node = node->left;
+
+ return node;
+}
+
+static GtkCssRbNode *
+gtk_css_rb_node_get_last (GtkCssRbNode *node)
+{
+ while (node->right)
+ node = node->right;
+
+ return node;
+}
+
+static GtkCssRbNode *
+gtk_css_rb_node_get_previous (GtkCssRbNode *node)
+{
+ GtkCssRbNode *parent;
+
+ if (node->left)
+ return gtk_css_rb_node_get_last (node->left);
+
+ for (parent = node->parent; parent != NULL; parent = node->parent)
+ {
+ if (parent->right == node)
+ return parent;
+
+ node = parent;
+ }
+
+ return NULL;
+}
+
+static GtkCssRbNode *
+gtk_css_rb_node_get_next (GtkCssRbNode *node)
+{
+ GtkCssRbNode *parent;
+
+ if (node->right)
+ return gtk_css_rb_node_get_first (node->right);
+
+ for (parent = node->parent; parent != NULL; parent = node->parent)
+ {
+ if (parent->left == node)
+ return parent;
+
+ node = parent;
+ }
+
+ return NULL;
+}
+
+static void
+gtk_css_rb_node_rotate_left (GtkCssRbTree *tree,
+ GtkCssRbNode *node)
+{
+ GtkCssRbNode *right;
+
+ right = node->right;
+
+ node->right = right->left;
+ if (right->left)
+ right->left->parent = node;
+
+ right->parent = node->parent;
+ if (node->parent)
+ {
+ if (node == node->parent->left)
+ node->parent->left = right;
+ else
+ node->parent->right = right;
+ }
+ else
+ {
+ tree->root = right;
+ }
+
+ right->left = node;
+ node->parent = right;
+
+ gtk_css_rb_node_mark_dirty (node, FALSE);
+ gtk_css_rb_node_mark_dirty (right, FALSE);
+}
+
+static void
+gtk_css_rb_node_rotate_right (GtkCssRbTree *tree,
+ GtkCssRbNode *node)
+{
+ GtkCssRbNode *left;
+
+ left = node->left;
+
+ node->left = left->right;
+ if (left->right)
+ left->right->parent = node;
+
+ left->parent = node->parent;
+ if (node->parent)
+ {
+ if (node == node->parent->right)
+ node->parent->right = left;
+ else
+ node->parent->left = left;
+ }
+ else
+ {
+ tree->root = left;
+ }
+
+ /* link node and left */
+ left->right = node;
+ node->parent = left;
+
+ gtk_css_rb_node_mark_dirty (node, FALSE);
+ gtk_css_rb_node_mark_dirty (left, FALSE);
+}
+
+static gboolean
+is_red (GtkCssRbNode *node_or_null)
+{
+ if (node_or_null == NULL)
+ return FALSE;
+ else
+ return node_or_null->red;
+}
+
+static inline gboolean
+is_black (GtkCssRbNode *node_or_null)
+{
+ return !is_red (node_or_null);
+}
+
+static void
+set_black (GtkCssRbNode *node_or_null)
+{
+ if (node_or_null == NULL)
+ return;
+
+ node_or_null->red = FALSE;
+}
+
+static void
+set_red (GtkCssRbNode *node_or_null)
+{
+ if (node_or_null == NULL)
+ return;
+
+ node_or_null->red = TRUE;
+}
+
+static void
+gtk_css_rb_tree_insert_fixup (GtkCssRbTree *tree,
+ GtkCssRbNode *node)
+{
+
+ /* check Red-Black properties */
+ while (node->parent && is_red (node->parent))
+ {
+ /* we have a violation */
+ g_assert (node->parent->parent);
+
+ if (node->parent == node->parent->parent->left)
+ {
+ GtkCssRbNode *uncle = node->parent->parent->right;
+
+ if (is_red (uncle))
+ {
+ /* uncle is red */
+ set_black (node->parent);
+ set_black (uncle);
+ set_red (node->parent->parent);
+ node = node->parent->parent;
+ }
+ else
+ {
+ /* uncle is black */
+ if (node == node->parent->right)
+ {
+ /* make node a left child */
+ node = node->parent;
+ gtk_css_rb_node_rotate_left (tree, node);
+ }
+ /* recolor and rotate */
+ set_black (node->parent);
+ set_red (node->parent->parent);
+ gtk_css_rb_node_rotate_right (tree, node->parent->parent);
+ }
+ }
+ else
+ {
+ /* mirror image of above code */
+ GtkCssRbNode *uncle = node->parent->parent->left;
+
+ if (is_red (uncle))
+ {
+ /* uncle is red */
+ set_black (node->parent);
+ set_black (uncle);
+ set_red (node->parent->parent);
+ node = node->parent->parent;
+ }
+ else
+ {
+ /* uncle is black */
+ if (node == node->parent->left)
+ {
+ node = node->parent;
+ gtk_css_rb_node_rotate_right (tree, node);
+ }
+ set_black (node->parent);
+ set_red (node->parent->parent);
+ gtk_css_rb_node_rotate_left (tree, node->parent->parent);
+ }
+ }
+ }
+
+ set_black (tree->root);
+}
+
+static void
+gtk_css_rb_tree_remove_node_fixup (GtkCssRbTree *tree,
+ GtkCssRbNode *node,
+ GtkCssRbNode *parent)
+{
+ while (node->parent && is_black (node))
+ {
+ if (node == parent->left)
+ {
+ GtkCssRbNode *w = parent->right;
+
+ if (is_red (w))
+ {
+ set_black (w);
+ set_red (parent);
+ gtk_css_rb_node_rotate_left (tree, parent);
+ w = parent->right;
+ }
+ if (is_black (w->left) && is_black (w->right))
+ {
+ set_red (w);
+ node = parent;
+ }
+ else
+ {
+ if (is_black (w->right))
+ {
+ set_black (w->left);
+ set_red (w);
+ gtk_css_rb_node_rotate_right (tree, w);
+ w = parent->right;
+ }
+ w->red = parent->red;
+ set_black (parent);
+ set_black (w->right);
+ gtk_css_rb_node_rotate_left (tree, parent);
+ node = tree->root;
+ }
+ }
+ else
+ {
+ GtkCssRbNode *w = parent->left;
+ if (is_red (w))
+ {
+ set_black (w);
+ set_red (parent);
+ gtk_css_rb_node_rotate_right (tree, parent);
+ w = parent->left;
+ }
+ if (is_black (w->right) && is_black (w->left))
+ {
+ set_red (w);
+ node = parent;
+ }
+ else
+ {
+ if (is_black (w->left))
+ {
+ set_black (w->right);
+ set_red (w);
+ gtk_css_rb_node_rotate_left (tree, w);
+ w = parent->left;
+ }
+ w->red = parent->red;
+ set_black (parent);
+ set_black (w->left);
+ gtk_css_rb_node_rotate_right (tree, parent);
+ node = tree->root;
+ }
+ }
+
+ parent = node->parent;
+ }
+
+ set_black (node);
+}
+
+GtkCssRbTree *
+gtk_css_rb_tree_new_for_size (gsize element_size,
+ gsize augment_size,
+ GtkCssRbTreeAugmentFunc augment_func,
+ GDestroyNotify clear_func,
+ GDestroyNotify clear_augment_func)
+{
+ GtkCssRbTree *tree;
+
+ tree = g_slice_new0 (GtkCssRbTree);
+ tree->ref_count = 1;
+
+ tree->element_size = element_size;
+ tree->augment_size = augment_size;
+ tree->augment_func = augment_func;
+ tree->clear_func = clear_func;
+ tree->clear_augment_func = clear_augment_func;
+
+ return tree;
+}
+
+GtkCssRbTree *
+gtk_css_rb_tree_ref (GtkCssRbTree *tree)
+{
+ tree->ref_count++;
+
+ return tree;
+}
+
+void
+gtk_css_rb_tree_unref (GtkCssRbTree *tree)
+{
+ tree->ref_count--;
+ if (tree->ref_count > 0)
+ return;
+
+ if (tree->root)
+ gtk_css_rb_node_free_deep (tree, tree->root);
+
+ g_slice_free (GtkCssRbTree, tree);
+}
+
+gpointer
+gtk_css_rb_tree_get_first (GtkCssRbTree *tree)
+{
+ if (tree->root == NULL)
+ return NULL;
+
+ return NODE_TO_POINTER (gtk_css_rb_node_get_first (tree->root));
+}
+
+gpointer
+gtk_css_rb_tree_get_last (GtkCssRbTree *tree)
+{
+ if (tree->root == NULL)
+ return NULL;
+
+ return NODE_TO_POINTER (gtk_css_rb_node_get_last (tree->root));
+}
+
+gpointer
+gtk_css_rb_tree_get_previous (GtkCssRbTree *tree,
+ gpointer node)
+{
+ return NODE_TO_POINTER (gtk_css_rb_node_get_previous (NODE_FROM_POINTER (node)));
+}
+
+gpointer
+gtk_css_rb_tree_get_next (GtkCssRbTree *tree,
+ gpointer node)
+{
+ return NODE_TO_POINTER (gtk_css_rb_node_get_next (NODE_FROM_POINTER (node)));
+}
+
+gpointer
+gtk_css_rb_tree_get_root (GtkCssRbTree *tree)
+{
+ return NODE_TO_POINTER (tree->root);
+}
+
+gpointer
+gtk_css_rb_tree_get_parent (GtkCssRbTree *tree,
+ gpointer node)
+{
+ return NODE_TO_POINTER (NODE_FROM_POINTER (node)->parent);
+}
+
+gpointer
+gtk_css_rb_tree_get_left (GtkCssRbTree *tree,
+ gpointer node)
+{
+ return NODE_TO_POINTER (NODE_FROM_POINTER (node)->left);
+}
+
+gpointer
+gtk_css_rb_tree_get_right (GtkCssRbTree *tree,
+ gpointer node)
+{
+ return NODE_TO_POINTER (NODE_FROM_POINTER (node)->right);
+}
+
+gpointer
+gtk_css_rb_tree_get_augment (GtkCssRbTree *tree,
+ gpointer node)
+{
+ GtkCssRbNode *rbnode = NODE_FROM_POINTER (node);
+
+ gtk_css_rb_node_clean (tree, rbnode);
+
+ return NODE_TO_AUG_POINTER (tree, rbnode);
+}
+
+void
+gtk_css_rb_tree_mark_dirty (GtkCssRbTree *tree,
+ gpointer node)
+{
+ gtk_css_rb_node_mark_dirty (NODE_FROM_POINTER (node), TRUE);
+}
+
+gpointer
+gtk_css_rb_tree_insert_before (GtkCssRbTree *tree,
+ gpointer node)
+{
+ GtkCssRbNode *result;
+
+ /* setup new node */
+ result = gtk_css_rb_node_new (tree);
+
+ if (tree->root == NULL)
+ {
+ g_assert (node == NULL);
+ tree->root = result;
+ }
+ else if (node == NULL)
+ {
+ return gtk_css_rb_tree_insert_after (tree, gtk_css_rb_tree_get_last (tree));
+ }
+ else
+ {
+ GtkCssRbNode *current = NODE_FROM_POINTER (node);
+
+ if (current->left)
+ {
+ current = gtk_css_rb_node_get_last (current);
+ current->right = result;
+ }
+ else
+ {
+ current->left = result;
+ }
+ result->parent = current;
+ gtk_css_rb_node_mark_dirty (current, TRUE);
+ }
+
+ gtk_css_rb_tree_insert_fixup (tree, result);
+
+ return NODE_TO_POINTER (result);
+}
+
+gpointer
+gtk_css_rb_tree_insert_after (GtkCssRbTree *tree,
+ gpointer node)
+{
+ GtkCssRbNode *result;
+
+ /* setup new node */
+ result = gtk_css_rb_node_new (tree);
+
+ if (tree->root == NULL)
+ {
+ g_assert (node == NULL);
+ tree->root = result;
+ }
+ else if (node == NULL)
+ {
+ return gtk_css_rb_tree_insert_before (tree, gtk_css_rb_tree_get_first (tree));
+ }
+ else
+ {
+ GtkCssRbNode *current = NODE_FROM_POINTER (node);
+
+ if (current->right )
+ {
+ current = gtk_css_rb_node_get_first (current);
+ current->left = result;
+ }
+ else
+ {
+ current->right = result;
+ }
+ result->parent = current;
+ gtk_css_rb_node_mark_dirty (current, TRUE);
+ }
+
+ gtk_css_rb_tree_insert_fixup (tree, result);
+
+ return NODE_TO_POINTER (result);
+}
+
+void
+gtk_css_rb_tree_remove (GtkCssRbTree *tree,
+ gpointer node)
+{
+ GtkCssRbNode *x, *y, *real_node;
+
+ real_node = NODE_FROM_POINTER (node);
+ y = real_node;
+ if (y->left && y->right)
+ {
+ y = y->right;
+
+ while (y->left)
+ y = y->left;
+ }
+
+ /* x is y's only child, or nil */
+ if (y->left)
+ x = y->left;
+ else
+ x = y->right;
+
+ /* remove y from the parent chain */
+ if (x != NULL)
+ x->parent = y->parent;
+ if (y->parent)
+ {
+ if (y == y->parent->left)
+ y->parent->left = x;
+ else
+ y->parent->right = x;
+ }
+ else
+ {
+ tree->root = x;
+ }
+
+ /* We need to clean up the validity of the tree.
+ */
+ if (x && is_black (y))
+ gtk_css_rb_tree_remove_node_fixup (tree, x, y->parent);
+
+ if (y != real_node)
+ {
+ /* Move the node over */
+ if (is_red (real_node) != is_red (y))
+ y->red = !y->red;
+
+ y->left = real_node->left;
+ if (y->left)
+ y->left->parent = y;
+ y->right = real_node->right;
+ if (y->right)
+ y->right->parent = y;
+ y->parent = real_node->parent;
+ if (y->parent)
+ {
+ if (y->parent->left == real_node)
+ y->parent->left = y;
+ else
+ y->parent->right = y;
+ }
+ else
+ {
+ tree->root = y;
+ }
+ }
+
+ gtk_css_rb_node_free (tree, real_node);
+}
+
+
+gpointer
+gtk_css_rb_tree_find (GtkCssRbTree *tree,
+ gpointer *out_before,
+ gpointer *out_after,
+ GtkCssRbTreeFindFunc find_func,
+ gpointer user_data)
+{
+ GtkCssRbNode *node, *before = NULL, *after = NULL;
+ int cmp;
+
+ if (tree->root == NULL)
+ {
+ if (out_before)
+ *out_before = NULL;
+ if (out_after)
+ *out_after = NULL;
+
+ return NULL;
+ }
+
+ node = tree->root;
+ for (cmp = find_func (tree, NODE_TO_POINTER (node), user_data);
+ cmp != 0;
+ cmp = find_func (tree, NODE_TO_POINTER (node), user_data))
+ {
+ if (cmp < 0)
+ {
+ before = node;
+ node = node->right;
+ }
+ else /* cmp > 0 */
+ {
+ after = node;
+ node = node->left;
+ }
+ if (node == NULL)
+ {
+ if (out_before)
+ *out_before = NODE_TO_POINTER (before);
+ if (out_after)
+ *out_after = NODE_TO_POINTER (after);
+ return NULL;;
+ }
+ }
+
+ if (out_before)
+ *out_before = NODE_TO_POINTER (gtk_css_rb_node_get_previous (node));
+ if (out_after)
+ *out_after = NODE_TO_POINTER (gtk_css_rb_node_get_next (node));
+
+ return NODE_TO_POINTER (node);
+}
diff --git a/gtk/gtkcssrbtreeprivate.h b/gtk/gtkcssrbtreeprivate.h
new file mode 100644
index 0000000..fd7dfbd
--- /dev/null
+++ b/gtk/gtkcssrbtreeprivate.h
@@ -0,0 +1,89 @@
+/* gtkrb_tree.h
+ * Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford <jrb redhat com>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/* A Red-Black Tree implementation used specifically by GtkTreeView.
+ */
+#ifndef __GTK_CSS_RB_TREE_H__
+#define __GTK_CSS_RB_TREE_H__
+
+#include <glib.h>
+
+
+G_BEGIN_DECLS
+
+
+typedef struct _GtkCssRbTree GtkCssRbTree;
+
+typedef void (* GtkCssRbTreeAugmentFunc) (GtkCssRbTree *tree,
+ gpointer node_augment,
+ gpointer node,
+ gpointer left,
+ gpointer right);
+typedef int (* GtkCssRbTreeFindFunc) (GtkCssRbTree *tree,
+ gpointer node,
+ gpointer user_data);
+
+GtkCssRbTree * gtk_css_rb_tree_new_for_size (gsize element_size,
+ gsize augment_size,
+ GtkCssRbTreeAugmentFunc augment_func,
+ GDestroyNotify clear_func,
+ GDestroyNotify clear_augment_func);
+#define gtk_css_rb_tree_new(type, augment_type, augment_func, clear_func, clear_augment_func) \
+ gtk_css_rb_tree_new_for_size (sizeof (type), sizeof (augment_type), (augment_func), (clear_func),
(clear_augment_func))
+
+GtkCssRbTree * gtk_css_rb_tree_ref (GtkCssRbTree *tree);
+void gtk_css_rb_tree_unref (GtkCssRbTree *tree);
+
+gpointer gtk_css_rb_tree_get_first (GtkCssRbTree *tree);
+gpointer gtk_css_rb_tree_get_last (GtkCssRbTree *tree);
+gpointer gtk_css_rb_tree_get_previous (GtkCssRbTree *tree,
+ gpointer node);
+gpointer gtk_css_rb_tree_get_next (GtkCssRbTree *tree,
+ gpointer node);
+
+gpointer gtk_css_rb_tree_get_root (GtkCssRbTree *tree);
+gpointer gtk_css_rb_tree_get_parent (GtkCssRbTree *tree,
+ gpointer node);
+gpointer gtk_css_rb_tree_get_left (GtkCssRbTree *tree,
+ gpointer node);
+gpointer gtk_css_rb_tree_get_right (GtkCssRbTree *tree,
+ gpointer node);
+gpointer gtk_css_rb_tree_get_augment (GtkCssRbTree *tree,
+ gpointer node);
+
+void gtk_css_rb_tree_mark_dirty (GtkCssRbTree *tree,
+ gpointer node);
+
+gpointer gtk_css_rb_tree_insert_before (GtkCssRbTree *tree,
+ gpointer node);
+gpointer gtk_css_rb_tree_insert_after (GtkCssRbTree *tree,
+ gpointer node);
+void gtk_css_rb_tree_remove (GtkCssRbTree *tree,
+ gpointer node);
+
+gpointer gtk_css_rb_tree_find (GtkCssRbTree *tree,
+ gpointer *out_before,
+ gpointer *out_after,
+ GtkCssRbTreeFindFunc find_func,
+ gpointer user_data);
+
+
+
+G_END_DECLS
+
+
+#endif /* __GTK_CSS_RB_TREE_H__ */
diff --git a/testsuite/gtk/Makefile.am b/testsuite/gtk/Makefile.am
index 5fc1cf1..044e8c0 100644
--- a/testsuite/gtk/Makefile.am
+++ b/testsuite/gtk/Makefile.am
@@ -43,6 +43,7 @@ TEST_PROGS += \
check-cursor-names \
clipboard \
cssprovider \
+ cssrbtree \
defaultvalue \
entry \
firefox-stylecontext \
@@ -94,6 +95,14 @@ treemodel_SOURCES = \
builder_LDFLAGS = -export-dynamic
+cssrbtree_CFLAGS = -DGTK_COMPILATION -UG_ENABLE_DEBUG
+cssrbtree_LDADD = $(GTK_DEP_LIBS)
+cssrbtree_SOURCES = \
+ cssrbtree.c \
+ $(top_srcdir)/gtk/gtkcssrbtreeprivate.h \
+ $(top_srcdir)/gtk/gtkcssrbtree.c \
+ $(NULL)
+
rbtree_CFLAGS = -DGTK_COMPILATION -UG_ENABLE_DEBUG
rbtree_LDADD = $(GTK_DEP_LIBS)
rbtree_SOURCES = \
diff --git a/testsuite/gtk/cssrbtree.c b/testsuite/gtk/cssrbtree.c
new file mode 100644
index 0000000..7f5b3e9
--- /dev/null
+++ b/testsuite/gtk/cssrbtree.c
@@ -0,0 +1,253 @@
+/* GtkCssRbTree tests.
+ *
+ * Copyright (C) 2016, Red Hat, Inc.
+ * Authors: Benjamin Otte <otte gnome org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <locale.h>
+
+#include "../../gtk/gtkcssrbtreeprivate.h"
+
+#include <string.h>
+
+typedef struct _Element Element;
+struct _Element {
+ char *value;
+};
+
+static void
+clear_element (gpointer data)
+{
+ Element *e = data;
+
+ g_free (e->value);
+};
+
+static void
+augment (GtkCssRbTree *tree,
+ gpointer aug_data,
+ gpointer data,
+ gpointer ldata,
+ gpointer rdata)
+{
+ Element *aug = aug_data;
+ Element *e = data;
+ GString *str = g_string_new (NULL);
+
+ g_free (aug->value);
+
+ if (ldata)
+ {
+ Element *l = gtk_css_rb_tree_get_augment (tree, ldata);
+
+ g_string_append (str, l->value);
+ g_string_append_c (str, ' ');
+ }
+
+ g_string_append (str, e->value);
+
+ if (rdata)
+ {
+ Element *r = gtk_css_rb_tree_get_augment (tree, rdata);
+
+ g_string_append_c (str, ' ');
+ g_string_append (str, r->value);
+ }
+
+ aug->value = g_string_free (str, FALSE);
+}
+
+static GtkCssRbTree *
+create_tree (void)
+{
+ return gtk_css_rb_tree_new (Element,
+ Element,
+ augment,
+ clear_element,
+ clear_element);
+}
+
+static void
+check_tree (GtkCssRbTree *tree,
+ char **elements)
+{
+ Element *e;
+
+ for (e = gtk_css_rb_tree_get_first (tree);
+ e;
+ e = gtk_css_rb_tree_get_next (tree, e))
+ {
+ g_assert_cmpstr (e->value, ==, *elements);
+ elements++;
+ }
+
+ g_assert (*elements == NULL);
+}
+
+static void
+check_augment (GtkCssRbTree *tree,
+ char *expected)
+{
+ Element *e, *aug;
+
+ e = gtk_css_rb_tree_get_root (tree);
+ aug = gtk_css_rb_tree_get_augment (tree, e);
+
+ g_assert_cmpstr (aug->value, ==, expected);
+}
+
+static char *tests[] = {
+ "3 20 100",
+ "1",
+ "1 2",
+ "1 2 3",
+ "1 2 3 4",
+ "1 2 3 4 5",
+ "1 2 3 4 5",
+ "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 "
+ "26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 "
+ "51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 "
+ "76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100"
+};
+
+static void
+test_insert_after (void)
+{
+ GtkCssRbTree *tree;
+ Element *e;
+ guint t, i;
+
+ for (t = 0; t < G_N_ELEMENTS (tests); t++)
+ {
+ gchar **elements = g_strsplit (tests[t], " ", -1);
+
+ tree = create_tree ();
+ e = NULL;
+
+ for (i = 0; i < g_strv_length (elements); i++)
+ {
+ e = gtk_css_rb_tree_insert_after (tree, e);
+ e->value = g_strdup (elements[i]);
+ }
+
+ check_tree (tree, elements);
+ check_augment (tree, tests[t]);
+
+ gtk_css_rb_tree_unref (tree);
+ g_strfreev (elements);
+ }
+}
+
+static void
+test_insert_before (void)
+{
+ GtkCssRbTree *tree;
+ Element *e;
+ guint t, i;
+
+ for (t = 0; t < G_N_ELEMENTS (tests); t++)
+ {
+ gchar **elements = g_strsplit (tests[t], " ", -1);
+
+ tree = create_tree ();
+ e = NULL;
+
+ for (i = g_strv_length (elements); i > 0; i--)
+ {
+ e = gtk_css_rb_tree_insert_before (tree, e);
+ e->value = g_strdup (elements[i - 1]);
+ }
+
+ check_tree (tree, elements);
+ check_augment (tree, tests[t]);
+
+ gtk_css_rb_tree_unref (tree);
+ g_strfreev (elements);
+ }
+}
+
+static int
+compare_number_strings (GtkCssRbTree *tree,
+ gpointer elem,
+ gpointer data)
+{
+ Element *e = elem;
+ int len_diff;
+
+ len_diff = strlen (e->value) - strlen (data);
+ if (len_diff != 0)
+ return len_diff;
+
+ return strcmp (e->value, data);
+}
+
+static void
+test_find (void)
+{
+ GtkCssRbTree *tree;
+ Element *e, *before, *after;
+ guint t, i;
+
+ for (t = 0; t < G_N_ELEMENTS (tests); t++)
+ {
+ gchar **elements = g_strsplit (tests[t], " ", -1);
+
+ tree = create_tree ();
+ e = NULL;
+
+ for (i = 0; i < g_strv_length (elements); i++)
+ {
+ e = gtk_css_rb_tree_insert_after (tree, e);
+ e->value = g_strdup (elements[i]);
+ }
+
+ for (i = 0; i < g_strv_length (elements); i++)
+ {
+ e = gtk_css_rb_tree_find (tree,
+ (gpointer *) &before,
+ (gpointer *) &after,
+ compare_number_strings,
+ elements[i]);
+
+ g_assert_cmpstr (e->value, ==, elements[i]);
+ if (i == 0)
+ g_assert (before == NULL);
+ else
+ g_assert_cmpstr (before->value, ==, elements[i - 1]);
+ if (elements[i + 1] == NULL)
+ g_assert (after == NULL);
+ else
+ g_assert_cmpstr (after->value, ==, elements[i + 1]);
+ }
+
+ gtk_css_rb_tree_unref (tree);
+ g_strfreev (elements);
+ }
+}
+
+int
+main (int argc, char *argv[])
+{
+ g_test_init (&argc, &argv, NULL);
+ setlocale (LC_ALL, "C");
+ g_test_bug_base ("http://bugzilla.gnome.org/show_bug.cgi?id=%s");
+
+ g_test_add_func ("/rbtree/insert_after", test_insert_after);
+ g_test_add_func ("/rbtree/insert_before", test_insert_before);
+ g_test_add_func ("/rbtree/find", test_find);
+
+ return g_test_run ();
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]