[gtk/wip/otte/css] selector: Rework iterating over subnodes
- From: Benjamin Otte <otte src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip/otte/css] selector: Rework iterating over subnodes
- Date: Tue, 28 Jan 2020 03:34:01 +0000 (UTC)
commit c7dca199ae344dca6914f4a534652a4aa8a99fda
Author: Benjamin Otte <otte redhat com>
Date: Tue Jan 28 03:53:48 2020 +0100
selector: Rework iterating over subnodes
Instead of a foreach() function, introduce an iterator, so that the
caller can drive the iteration.
This allows doing stuff inbetween callbacks and avoids closures when
more than one data object should be passed.
As a side effect I even get a small, but noticeable performance
improvement in the 2-10% range depending on benchmark, I guess that's
because there's no function pointer passing going on anymore.
gtk/gtkcssprovider.c | 2 +-
gtk/gtkcssselector.c | 276 ++++++++++++++++++++------------------------
gtk/gtkcssselectorprivate.h | 2 +-
3 files changed, 126 insertions(+), 154 deletions(-)
---
diff --git a/gtk/gtkcssprovider.c b/gtk/gtkcssprovider.c
index f1eafed695..6db8d88ba6 100644
--- a/gtk/gtkcssprovider.c
+++ b/gtk/gtkcssprovider.c
@@ -415,7 +415,7 @@ verify_tree_match_results (GtkCssProvider *provider,
break;
}
}
- should_match = _gtk_css_selector_matches (ruleset->selector, node);
+ should_match = gtk_css_selector_matches (ruleset->selector, node);
if (found != !!should_match)
{
g_error ("expected rule '%s' to %s, but it %s",
diff --git a/gtk/gtkcssselector.c b/gtk/gtkcssselector.c
index dfb002e32b..b08e3c7a2b 100644
--- a/gtk/gtkcssselector.c
+++ b/gtk/gtkcssselector.c
@@ -48,37 +48,37 @@ typedef enum {
} GtkCssSelectorCategory;
typedef struct _GtkCssSelectorClass GtkCssSelectorClass;
-typedef gboolean (* GtkCssSelectorForeachFunc) (const GtkCssSelector *selector,
- GtkCssNode *node,
- gpointer data);
struct _GtkCssSelectorClass {
const char *name;
GtkCssSelectorCategory category;
- void (* print) (const GtkCssSelector *selector,
- GString *string);
- /* NULL or an iterator that calls func with each subnode of @node.
- * Potentially no subnode exists.
- * If any @invocation of @func returns %TRUE, the function will immediately
- * return %TRUE itself. If @func never returns %TRUE (or isn't called at all),
- * %FALSE will be returned.
+ void (* print) (const GtkCssSelector *selector,
+ GString *string);
+ /* NULL or an iterator that returns the next node or %NULL if there are no
+ * more nodes.
+ * Call it like:
+ * for (iter = gtk_css_selector_iterator (node, NULL);
+ * iter;
+ * iter = gtk_css_selector_iterator (node, iter))
+ * {
+ * do_stuff();
+ * }
*/
- gboolean (* foreach_matcher) (const GtkCssSelector *selector,
- GtkCssNode *node,
- GtkCssSelectorForeachFunc func,
- gpointer data);
- gboolean (* match_one) (const GtkCssSelector *selector,
- GtkCssNode *node);
- GtkCssChange (* get_change) (const GtkCssSelector *selector,
- GtkCssChange previous_change);
- void (* add_specificity) (const GtkCssSelector *selector,
- guint *ids,
- guint *classes,
- guint *elements);
- guint (* hash_one) (const GtkCssSelector *selector);
- int (* compare_one) (const GtkCssSelector *a,
- const GtkCssSelector *b);
+ GtkCssNode * (* iterator) (const GtkCssSelector *selector,
+ GtkCssNode *node,
+ GtkCssNode *current);
+ gboolean (* match_one) (const GtkCssSelector *selector,
+ GtkCssNode *node);
+ GtkCssChange (* get_change) (const GtkCssSelector *selector,
+ GtkCssChange previous_change);
+ void (* add_specificity) (const GtkCssSelector *selector,
+ guint *ids,
+ guint *classes,
+ guint *elements);
+ guint (* hash_one) (const GtkCssSelector *selector);
+ int (* compare_one) (const GtkCssSelector *a,
+ const GtkCssSelector *b);
};
typedef enum {
@@ -169,19 +169,18 @@ g_ptr_array_insert_sorted (GPtrArray *array,
}
static inline gboolean
-gtk_css_selector_match (const GtkCssSelector *selector,
- GtkCssNode *node)
+gtk_css_selector_match_one (const GtkCssSelector *selector,
+ GtkCssNode *node)
{
return selector->class->match_one (selector, node);
}
-static inline gboolean
-gtk_css_selector_foreach (const GtkCssSelector *selector,
- GtkCssNode *node,
- GtkCssSelectorForeachFunc func,
- gpointer data)
+static inline GtkCssNode *
+gtk_css_selector_iterator (const GtkCssSelector *selector,
+ GtkCssNode *node,
+ GtkCssNode *current)
{
- return selector->class->foreach_matcher (selector, node, func, data);
+ return selector->class->iterator (selector, node, current);
}
static int
@@ -240,13 +239,15 @@ gtk_css_selector_default_add_specificity (const GtkCssSelector *selector,
/* no specificity changes */
}
-static gboolean
-gtk_css_selector_default_foreach_matcher (const GtkCssSelector *selector,
- GtkCssNode *node,
- GtkCssSelectorForeachFunc func,
- gpointer data)
+static GtkCssNode *
+gtk_css_selector_default_iterator (const GtkCssSelector *selector,
+ GtkCssNode *node,
+ GtkCssNode *current)
{
- return func (selector, node, data);
+ if (current)
+ return NULL;
+ else
+ return node;
}
static gboolean
@@ -278,23 +279,12 @@ gtk_css_selector_descendant_print (const GtkCssSelector *selector,
g_string_append_c (string, ' ');
}
-static gboolean
-gtk_css_selector_descendant_foreach_matcher (const GtkCssSelector *selector,
- GtkCssNode *node,
- GtkCssSelectorForeachFunc func,
- gpointer data)
+static GtkCssNode *
+gtk_css_selector_descendant_iterator (const GtkCssSelector *selector,
+ GtkCssNode *node,
+ GtkCssNode *current)
{
- GtkCssNode *parent;
-
- for (parent = gtk_css_node_get_parent (node);
- parent;
- parent = gtk_css_node_get_parent (parent))
- {
- if (func (selector, parent, data))
- return TRUE;
- }
-
- return FALSE;
+ return gtk_css_node_get_parent (current ? current : node);
}
static GtkCssChange
@@ -307,7 +297,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_DESCENDANT = {
"descendant",
GTK_CSS_SELECTOR_CATEGORY_PARENT,
gtk_css_selector_descendant_print,
- gtk_css_selector_descendant_foreach_matcher,
+ gtk_css_selector_descendant_iterator,
gtk_css_selector_default_match_one,
gtk_css_selector_descendant_get_change,
gtk_css_selector_default_add_specificity,
@@ -324,19 +314,15 @@ gtk_css_selector_child_print (const GtkCssSelector *selector,
g_string_append (string, " > ");
}
-static gboolean
-gtk_css_selector_child_foreach_matcher (const GtkCssSelector *selector,
- GtkCssNode *node,
- GtkCssSelectorForeachFunc func,
- gpointer data)
+static GtkCssNode *
+gtk_css_selector_child_iterator (const GtkCssSelector *selector,
+ GtkCssNode *node,
+ GtkCssNode *current)
{
- GtkCssNode *parent;
-
- parent = gtk_css_node_get_parent (node);
- if (parent == NULL)
- return FALSE;
+ if (current == NULL)
+ return gtk_css_node_get_parent (node);
- return func (selector, parent, data);
+ return NULL;
}
static GtkCssChange
@@ -349,7 +335,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_CHILD = {
"child",
GTK_CSS_SELECTOR_CATEGORY_PARENT,
gtk_css_selector_child_print,
- gtk_css_selector_child_foreach_matcher,
+ gtk_css_selector_child_iterator,
gtk_css_selector_default_match_one,
gtk_css_selector_child_get_change,
gtk_css_selector_default_add_specificity,
@@ -386,23 +372,12 @@ get_next_visible_sibling (GtkCssNode *node)
return node;
}
-static gboolean
-gtk_css_selector_sibling_foreach_matcher (const GtkCssSelector *selector,
- GtkCssNode *node,
- GtkCssSelectorForeachFunc func,
- gpointer data)
+static GtkCssNode *
+gtk_css_selector_sibling_iterator (const GtkCssSelector *selector,
+ GtkCssNode *node,
+ GtkCssNode *current)
{
- GtkCssNode *prev;
-
- for (prev = get_previous_visible_sibling (node);
- prev;
- prev = get_previous_visible_sibling (prev))
- {
- if (func (selector, prev, data))
- return TRUE;
- }
-
- return FALSE;
+ return get_previous_visible_sibling (current ? current : node);
}
static GtkCssChange
@@ -415,7 +390,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_SIBLING = {
"sibling",
GTK_CSS_SELECTOR_CATEGORY_SIBLING,
gtk_css_selector_sibling_print,
- gtk_css_selector_sibling_foreach_matcher,
+ gtk_css_selector_sibling_iterator,
gtk_css_selector_default_match_one,
gtk_css_selector_sibling_get_change,
gtk_css_selector_default_add_specificity,
@@ -432,19 +407,15 @@ gtk_css_selector_adjacent_print (const GtkCssSelector *selector,
g_string_append (string, " + ");
}
-static gboolean
-gtk_css_selector_adjacent_foreach_matcher (const GtkCssSelector *selector,
- GtkCssNode *node,
- GtkCssSelectorForeachFunc func,
- gpointer data)
+static GtkCssNode *
+gtk_css_selector_adjacent_iterator (const GtkCssSelector *selector,
+ GtkCssNode *node,
+ GtkCssNode *current)
{
- GtkCssNode *prev;
-
- prev = get_previous_visible_sibling (node);
- if (prev == NULL)
- return FALSE;
+ if (current == NULL)
+ return get_previous_visible_sibling (node);
- return func (selector, prev, data);
+ return NULL;
}
static GtkCssChange
@@ -457,7 +428,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_ADJACENT = {
"adjacent",
GTK_CSS_SELECTOR_CATEGORY_SIBLING,
gtk_css_selector_adjacent_print,
- gtk_css_selector_adjacent_foreach_matcher,
+ gtk_css_selector_adjacent_iterator,
gtk_css_selector_default_match_one,
gtk_css_selector_adjacent_get_change,
gtk_css_selector_default_add_specificity,
@@ -530,7 +501,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_ ## c = { \
G_STRINGIFY(n), \
ignore_for_change ? GTK_CSS_SELECTOR_CATEGORY_SIMPLE : GTK_CSS_SELECTOR_CATEGORY_SIMPLE_RADICAL, \
gtk_css_selector_ ## n ## _print, \
- gtk_css_selector_default_foreach_matcher, \
+ gtk_css_selector_default_iterator, \
match_func, \
gtk_css_selector_ ## n ## _get_change, \
gtk_css_selector_ ## n ## _add_specificity, \
@@ -542,7 +513,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_NOT_ ## c = { \
"not_" G_STRINGIFY(n), \
GTK_CSS_SELECTOR_CATEGORY_SIMPLE, \
gtk_css_selector_not_ ## n ## _print, \
- gtk_css_selector_default_foreach_matcher, \
+ gtk_css_selector_default_iterator, \
gtk_css_selector_not_ ## n ## _match_one, \
gtk_css_selector_ ## n ## _get_change, \
gtk_css_selector_ ## n ## _add_specificity, \
@@ -1675,24 +1646,8 @@ _gtk_css_selector_to_string (const GtkCssSelector *selector)
return g_string_free (string, FALSE);
}
-static gboolean
-gtk_css_selector_foreach_match (const GtkCssSelector *selector,
- GtkCssNode *node,
- gpointer unused)
-{
- selector = gtk_css_selector_previous (selector);
-
- if (selector == NULL)
- return TRUE;
-
- if (!gtk_css_selector_match (selector, node))
- return FALSE;
-
- return gtk_css_selector_foreach (selector, node, gtk_css_selector_foreach_match, NULL);
-}
-
/**
- * _gtk_css_selector_matches:
+ * gtk_css_selector_matches:
* @selector: the selector
* @node: The node to match
*
@@ -1701,17 +1656,31 @@ gtk_css_selector_foreach_match (const GtkCssSelector *selector,
* Returns: %TRUE if the selector matches @node
**/
gboolean
-_gtk_css_selector_matches (const GtkCssSelector *selector,
- GtkCssNode *node)
+gtk_css_selector_matches (const GtkCssSelector *selector,
+ GtkCssNode *node)
{
+ GtkCssNode *child;
+ const GtkCssSelector *prev;
g_return_val_if_fail (selector != NULL, FALSE);
g_return_val_if_fail (node != NULL, FALSE);
- if (!gtk_css_selector_match (selector, node))
+ if (!gtk_css_selector_match_one (selector, node))
return FALSE;
- return gtk_css_selector_foreach (selector, node, gtk_css_selector_foreach_match, NULL);
+ prev = gtk_css_selector_previous (selector);
+ if (prev == NULL)
+ return TRUE;
+
+ for (child = gtk_css_selector_iterator (selector, node, NULL);
+ child;
+ child = gtk_css_selector_iterator (selector, node, child))
+ {
+ if (gtk_css_selector_matches (prev, child))
+ return TRUE;
+ }
+
+ return FALSE;
}
/* Computes specificity according to CSS 2.1.
@@ -1889,58 +1858,59 @@ gtk_css_selector_tree_match_bloom (const GtkCssSelectorTree *tree,
return FALSE;
}
-typedef struct
-{
- const GtkCountingBloomFilter *filter;
- GPtrArray *results;
-} TreeMatchData;
-
static void
-gtk_css_selector_tree_found_match (const GtkCssSelectorTree *tree,
- TreeMatchData *tm)
+gtk_css_selector_tree_found_match (const GtkCssSelectorTree *tree,
+ GPtrArray **results)
{
int i;
gpointer *matches;
matches = gtk_css_selector_tree_get_matches (tree);
- if (matches)
- {
- if (tm->results == NULL)
- tm->results = g_ptr_array_sized_new (16);
+ if (!matches)
+ return;
- for (i = 0; matches[i] != NULL; i++)
- g_ptr_array_insert_sorted (tm->results, matches[i]);
- }
+ if (*results == NULL)
+ *results = g_ptr_array_sized_new (16);
+
+ for (i = 0; matches[i] != NULL; i++)
+ g_ptr_array_insert_sorted (*results, matches[i]);
}
-static gboolean
-gtk_css_selector_tree_match_foreach (const GtkCssSelector *selector,
- GtkCssNode *node,
- gpointer data)
+static void
+gtk_css_selector_tree_match (const GtkCssSelectorTree *tree,
+ const GtkCountingBloomFilter *filter,
+ GtkCssNode *node,
+ GPtrArray **results)
{
- TreeMatchData *tm = data;
- const GtkCssSelectorTree *tree = (const GtkCssSelectorTree *) selector;
const GtkCssSelectorTree *prev;
+ GtkCssNode *child;
- if (!gtk_css_selector_match (selector, node))
- return FALSE;
+ if (!gtk_css_selector_match_one (&tree->selector, node))
+ return;
- gtk_css_selector_tree_found_match (tree, tm);
+ gtk_css_selector_tree_found_match (tree, results);
- if (tm->filter && !gtk_css_selector_is_simple (&tree->selector))
+ if (filter && !gtk_css_selector_is_simple (&tree->selector))
{
/* We can pass both TRUE or FALSE for skipping here, because the
* function will immediately update it. */
- if (!gtk_css_selector_tree_match_bloom (tree, tm->filter, FALSE))
- return FALSE;
+ if (!gtk_css_selector_tree_match_bloom (tree, filter, FALSE))
+ return;
}
for (prev = gtk_css_selector_tree_get_previous (tree);
prev != NULL;
prev = gtk_css_selector_tree_get_sibling (prev))
- gtk_css_selector_foreach (&prev->selector, node, gtk_css_selector_tree_match_foreach, tm);
+ {
+ for (child = gtk_css_selector_iterator (&tree->selector, node, NULL);
+ child;
+ child = gtk_css_selector_iterator (&tree->selector, node, child))
+ {
+ gtk_css_selector_tree_match (prev, filter, child, results);
+ }
+ }
- return FALSE;
+ return;
}
GPtrArray *
@@ -1948,13 +1918,15 @@ _gtk_css_selector_tree_match_all (const GtkCssSelectorTree *tree,
const GtkCountingBloomFilter *filter,
GtkCssNode *node)
{
- TreeMatchData tm = { filter, NULL };
+ GPtrArray *results = NULL;
for (; tree != NULL;
tree = gtk_css_selector_tree_get_sibling (tree))
- gtk_css_selector_foreach (&tree->selector, node, gtk_css_selector_tree_match_foreach, &tm);
+ {
+ gtk_css_selector_tree_match (tree, filter, node, &results);
+ }
- return tm.results;
+ return results;
}
/* When checking for changes via the tree we need to know if a rule further
diff --git a/gtk/gtkcssselectorprivate.h b/gtk/gtkcssselectorprivate.h
index 4d8e39f376..e351beb915 100644
--- a/gtk/gtkcssselectorprivate.h
+++ b/gtk/gtkcssselectorprivate.h
@@ -35,7 +35,7 @@ char * _gtk_css_selector_to_string (const GtkCssSelector *sel
void _gtk_css_selector_print (const GtkCssSelector *selector,
GString *str);
-gboolean _gtk_css_selector_matches (const GtkCssSelector *selector,
+gboolean gtk_css_selector_matches (const GtkCssSelector *selector,
GtkCssNode *node);
GtkCssChange _gtk_css_selector_get_change (const GtkCssSelector *selector);
int _gtk_css_selector_compare (const GtkCssSelector *a,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]