From 194ec5c3ebc36bfbde2ab91dcbfd708f7e3afb3e Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 29 Jun 2019 04:59:49 +0000 Subject: [PATCH] constraints: Use better data structures Use a GSequence for GtkVariableSet, to avoid quadratic behavior. --- gtk/gtkconstraintexpression.c | 61 ++++++++++++++++------------------- 1 file changed, 28 insertions(+), 33 deletions(-) diff --git a/gtk/gtkconstraintexpression.c b/gtk/gtkconstraintexpression.c index 6cd7dfcbaf..fda944d801 100644 --- a/gtk/gtkconstraintexpression.c +++ b/gtk/gtkconstraintexpression.c @@ -384,11 +384,8 @@ gtk_constraint_variable_is_dummy (const GtkConstraintVariable *variable) * A set of variables. */ struct _GtkConstraintVariableSet { - /* HashSet, owns a reference */ - GHashTable *set; - - /* List, used for iterating */ - GList *ordered_set; + /* List, owns a reference */ + GSequence *set; /* Age of the set, to guard against mutations while iterating */ gint64 age; @@ -405,8 +402,7 @@ gtk_constraint_variable_set_free (GtkConstraintVariableSet *set) { g_return_if_fail (set != NULL); - g_list_free (set->ordered_set); - g_hash_table_unref (set->set); + g_sequence_free (set->set); g_free (set); } @@ -423,10 +419,7 @@ gtk_constraint_variable_set_new (void) { GtkConstraintVariableSet *res = g_new (GtkConstraintVariableSet, 1); - res->set = g_hash_table_new_full (NULL, NULL, - (GDestroyNotify) gtk_constraint_variable_unref, - NULL); - res->ordered_set = NULL; + res->set = g_sequence_new ((GDestroyNotify) gtk_constraint_variable_unref); res->age = 0; @@ -435,7 +428,8 @@ gtk_constraint_variable_set_new (void) static int sort_by_variable_id (gconstpointer a, - gconstpointer b) + gconstpointer b, + gpointer data) { const GtkConstraintVariable *va = a, *vb = b; @@ -463,16 +457,17 @@ gboolean gtk_constraint_variable_set_add (GtkConstraintVariableSet *set, GtkConstraintVariable *variable) { - if (g_hash_table_contains (set->set, variable)) - return FALSE; + GSequenceIter *iter; - g_hash_table_add (set->set, gtk_constraint_variable_ref (variable)); + iter = g_sequence_search (set->set, variable, sort_by_variable_id, NULL); + if (!g_sequence_iter_is_end (iter)) + { + GtkConstraintVariable *v = g_sequence_get (iter); + if (v->_id == variable->_id) + return FALSE; + } - /* This is a tricky bit; the variables in the set must be ordered - * not by insertion, but by the incremental id of each variable, - * as that's the expected iteration order - */ - set->ordered_set = g_list_insert_sorted (set->ordered_set, variable, sort_by_variable_id); + g_sequence_insert_before (iter, gtk_constraint_variable_ref (variable)); set->age += 1; @@ -495,10 +490,12 @@ gboolean gtk_constraint_variable_set_remove (GtkConstraintVariableSet *set, GtkConstraintVariable *variable) { - if (g_hash_table_contains (set->set, variable)) + GSequenceIter *iter; + + iter = g_sequence_lookup (set->set, variable, sort_by_variable_id, NULL); + if (iter != NULL) { - set->ordered_set = g_list_remove (set->ordered_set, variable); - g_hash_table_remove (set->set, variable); + g_sequence_remove (iter); set->age += 1; return TRUE; @@ -518,7 +515,7 @@ gtk_constraint_variable_set_remove (GtkConstraintVariableSet *set, int gtk_constraint_variable_set_size (GtkConstraintVariableSet *set) { - return g_hash_table_size (set->set); + return g_sequence_get_length (set->set); } /*< private > @@ -529,7 +526,7 @@ gtk_constraint_variable_set_size (GtkConstraintVariableSet *set) /* Keep in sync with GtkConstraintVariableSetIter */ typedef struct { GtkConstraintVariableSet *set; - GList *current; + GSequenceIter *iter; gint64 age; } RealVariableSetIter; @@ -552,7 +549,7 @@ gtk_constraint_variable_set_iter_init (GtkConstraintVariableSetIter *iter, g_return_if_fail (set != NULL); riter->set = set; - riter->current = NULL; + riter->iter = g_sequence_get_begin_iter (set->set); riter->age = set->age; } @@ -576,15 +573,13 @@ gtk_constraint_variable_set_iter_next (GtkConstraintVariableSetIter *iter, g_assert (riter->age == riter->set->age); - if (riter->current == NULL) - riter->current = riter->set->ordered_set; - else - riter->current = riter->current->next; + if (g_sequence_iter_is_end (riter->iter)) + return FALSE; - if (riter->current != NULL) - *variable_p = riter->current->data; + *variable_p = g_sequence_get (riter->iter); + riter->iter = g_sequence_iter_next (riter->iter); - return riter->current != NULL; + return TRUE; } /*< private >