[gtk+] Don't use hashtables for storing css rule properties



commit 85b1b9b77816198040d9437ea2e1231c47e41e68
Author: Alexander Larsson <alexl redhat com>
Date:   Wed Feb 15 17:06:30 2012 +0100

    Don't use hashtables for storing css rule properties
    
    This saves a lot of memory

 gtk/gtkcssprovider.c |  291 ++++++++++++++++++++++++++++++++++----------------
 1 files changed, 201 insertions(+), 90 deletions(-)
---
diff --git a/gtk/gtkcssprovider.c b/gtk/gtkcssprovider.c
index 32bdd3a..26182e0 100644
--- a/gtk/gtkcssprovider.c
+++ b/gtk/gtkcssprovider.c
@@ -962,15 +962,19 @@
 
 typedef struct GtkCssRuleset GtkCssRuleset;
 typedef struct _GtkCssScanner GtkCssScanner;
+typedef struct _PropertyValue PropertyValue;
+typedef struct _WidgetPropertyValue WidgetPropertyValue;
 typedef enum ParserScope ParserScope;
 typedef enum ParserSymbol ParserSymbol;
 
 struct GtkCssRuleset
 {
   GtkCssSelector *selector;
-  GHashTable *widget_style;
-  GHashTable *style;
+  WidgetPropertyValue *widget_style;
+  PropertyValue *style;
   GtkBitmask *set_styles;
+  guint owns_style : 1;
+  guint owns_widget_style : 1;
 };
 
 struct _GtkCssScanner
@@ -1004,6 +1008,8 @@ static guint css_provider_signals[LAST_SIGNAL] = { 0 };
 static void gtk_css_provider_finalize (GObject *object);
 static void gtk_css_style_provider_iface_init (GtkStyleProviderIface *iface);
 static void gtk_css_style_provider_private_iface_init (GtkStyleProviderPrivateInterface *iface);
+static void property_value_list_free (PropertyValue *head);
+static void widget_property_value_list_free (WidgetPropertyValue *head);
 
 static gboolean
 gtk_css_provider_load_internal (GtkCssProvider *css_provider,
@@ -1112,16 +1118,17 @@ gtk_css_provider_class_init (GtkCssProviderClass *klass)
 
 static void
 gtk_css_ruleset_init_copy (GtkCssRuleset       *new,
-                           const GtkCssRuleset *ruleset,
+                           GtkCssRuleset       *ruleset,
                            GtkCssSelector      *selector)
 {
   memcpy (new, ruleset, sizeof (GtkCssRuleset));
 
   new->selector = selector;
-  if (new->widget_style)
-    g_hash_table_ref (new->widget_style);
-  if (new->style)
-    g_hash_table_ref (new->style);
+  /* First copy takes over ownership */
+  if (ruleset->owns_style)
+    ruleset->owns_style = FALSE;
+  if (ruleset->owns_widget_style)
+    ruleset->owns_widget_style = FALSE;
   if (new->set_styles)
     new->set_styles = _gtk_bitmask_copy (new->set_styles);
 }
@@ -1129,31 +1136,34 @@ gtk_css_ruleset_init_copy (GtkCssRuleset       *new,
 static void
 gtk_css_ruleset_clear (GtkCssRuleset *ruleset)
 {
-  if (ruleset->style)
-    g_hash_table_unref (ruleset->style);
+  if (ruleset->owns_style)
+    property_value_list_free (ruleset->style);
   if (ruleset->set_styles)
     _gtk_bitmask_free (ruleset->set_styles);
-  if (ruleset->widget_style)
-    g_hash_table_unref (ruleset->widget_style);
+  if (ruleset->owns_widget_style)
+    widget_property_value_list_free (ruleset->widget_style);
   if (ruleset->selector)
     _gtk_css_selector_free (ruleset->selector);
 
   memset (ruleset, 0, sizeof (GtkCssRuleset));
 }
 
-typedef struct _PropertyValue PropertyValue;
 struct _PropertyValue {
-  GtkCssSection *section;
+  GtkStyleProperty *property;
+  PropertyValue *next;
   GValue         value;
+
+  GtkCssSection *section;
 };
 
 static PropertyValue *
-property_value_new (GtkCssSection *section)
+property_value_new (GtkStyleProperty *property, GtkCssSection *section)
 {
   PropertyValue *value;
 
   value = g_slice_new0 (PropertyValue);
 
+  value->property = property;
   value->section = gtk_css_section_ref (section);
 
   return value;
@@ -1171,17 +1181,112 @@ property_value_free (PropertyValue *value)
 }
 
 static void
+property_value_list_free (PropertyValue *head)
+{
+  PropertyValue *l, *next;
+  for (l = head; l != NULL; l = next)
+    {
+      next = l->next;
+      property_value_free (l);
+    }
+}
+
+static PropertyValue *
+property_value_list_remove_property (PropertyValue *head, GtkStyleProperty *property)
+{
+  PropertyValue *l, **last;
+
+  last = &head;
+
+  for (l = head; l != NULL; l = l->next)
+    {
+      if (l->property == property)
+	{
+	  *last = l->next;
+	  property_value_free (l);
+	  break;
+	}
+
+      last = &l->next;
+    }
+
+  return head;
+}
+
+struct _WidgetPropertyValue {
+  char *name;
+  WidgetPropertyValue *next;
+  GValue         value;
+
+  GtkCssSection *section;
+};
+
+static WidgetPropertyValue *
+widget_property_value_new (char *name, GtkCssSection *section)
+{
+  WidgetPropertyValue *value;
+
+  value = g_slice_new0 (WidgetPropertyValue);
+
+  value->name = name;
+  value->section = gtk_css_section_ref (section);
+
+  return value;
+}
+
+static void
+widget_property_value_free (WidgetPropertyValue *value)
+{
+  if (G_IS_VALUE (&value->value))
+    g_value_unset (&value->value);
+
+  g_free (value->name);
+  gtk_css_section_unref (value->section);
+
+  g_slice_free (WidgetPropertyValue, value);
+}
+
+static void
+widget_property_value_list_free (WidgetPropertyValue *head)
+{
+  WidgetPropertyValue *l, *next;
+  for (l = head; l != NULL; l = next)
+    {
+      next = l->next;
+      widget_property_value_free (l);
+    }
+}
+
+static WidgetPropertyValue *
+widget_property_value_list_remove_name (WidgetPropertyValue *head, const char *name)
+{
+  WidgetPropertyValue *l, **last;
+
+  last = &head;
+
+  for (l = head; l != NULL; l = l->next)
+    {
+      if (strcmp (l->name, name) == 0)
+	{
+	  *last = l->next;
+	  widget_property_value_free (l);
+	  break;
+	}
+
+      last = &l->next;
+    }
+
+  return head;
+}
+
+static void
 gtk_css_ruleset_add_style (GtkCssRuleset *ruleset,
                            char          *name,
-                           PropertyValue *value)
+                           WidgetPropertyValue *value)
 {
-  if (ruleset->widget_style == NULL)
-    ruleset->widget_style = g_hash_table_new_full (g_str_hash,
-                                                   g_str_equal,
-                                                   (GDestroyNotify) g_free,
-                                                   (GDestroyNotify) property_value_free);
-
-  g_hash_table_insert (ruleset->widget_style, name, value);
+  value->next = widget_property_value_list_remove_name (ruleset->widget_style, name);
+  ruleset->widget_style = value;
+  ruleset->owns_widget_style = TRUE;
 }
 
 static void
@@ -1189,14 +1294,8 @@ gtk_css_ruleset_add (GtkCssRuleset    *ruleset,
                      GtkStyleProperty *prop,
                      PropertyValue    *value)
 {
-  if (ruleset->style == NULL)
-    {
-      ruleset->style = g_hash_table_new_full (g_direct_hash,
-                                              g_direct_equal,
-                                              NULL,
-                                              (GDestroyNotify) property_value_free);
-      ruleset->set_styles = _gtk_bitmask_new ();
-    }
+  if (ruleset->set_styles == NULL)
+    ruleset->set_styles = _gtk_bitmask_new ();
 
   if (GTK_IS_CSS_SHORTHAND_PROPERTY (prop))
     {
@@ -1210,7 +1309,7 @@ gtk_css_ruleset_add (GtkCssRuleset    *ruleset,
           const GValue *sub = &g_array_index (array, GValue, i);
           PropertyValue *val;
           
-          val = property_value_new (value->section);
+          val = property_value_new (child, value->section);
           g_value_init (&val->value, G_VALUE_TYPE (sub));
           g_value_copy (sub, &val->value);
           gtk_css_ruleset_add (ruleset, GTK_STYLE_PROPERTY (child), val);
@@ -1225,7 +1324,10 @@ gtk_css_ruleset_add (GtkCssRuleset    *ruleset,
       _gtk_bitmask_set (ruleset->set_styles,
                         _gtk_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (prop)),
                         TRUE);
-      g_hash_table_insert (ruleset->style, prop, value);
+
+      value->next = property_value_list_remove_property (ruleset->style, prop);
+      ruleset->style = value;
+      ruleset->owns_style = TRUE;
     }
   else
     {
@@ -1424,8 +1526,7 @@ gtk_css_provider_get_style (GtkStyleProvider *provider,
   for (i = 0; i < priv->rulesets->len; i++)
     {
       GtkCssRuleset *ruleset;
-      GHashTableIter iter;
-      gpointer key, val;
+      PropertyValue *value;
 
       ruleset = &g_array_index (priv->rulesets, GtkCssRuleset, i);
 
@@ -1435,18 +1536,11 @@ gtk_css_provider_get_style (GtkStyleProvider *provider,
       if (!gtk_css_ruleset_matches (ruleset, path, 0))
         continue;
 
-      g_hash_table_iter_init (&iter, ruleset->style);
-
-      while (g_hash_table_iter_next (&iter, &key, &val))
-        {
-          GtkCssStyleProperty *prop = key;
-          PropertyValue *value = val;
-
-          _gtk_style_properties_set_property_by_property (props,
-                                                          prop,
-                                                          _gtk_css_selector_get_state_flags (ruleset->selector),
-                                                          &value->value);
-        }
+      for (value = ruleset->style; value != NULL; value = value->next)
+	_gtk_style_properties_set_property_by_property (props,
+							GTK_CSS_STYLE_PROPERTY (value->property),
+							_gtk_css_selector_get_state_flags (ruleset->selector),
+							&value->value);
     }
 
   return props;
@@ -1461,7 +1555,7 @@ gtk_css_provider_get_style_property (GtkStyleProvider *provider,
 {
   GtkCssProvider *css_provider = GTK_CSS_PROVIDER (provider);
   GtkCssProviderPrivate *priv = css_provider->priv;
-  PropertyValue *val;
+  WidgetPropertyValue *val;
   gboolean found = FALSE;
   gchar *prop_name;
   gint i;
@@ -1482,27 +1576,30 @@ gtk_css_provider_get_style_property (GtkStyleProvider *provider,
       if (!gtk_css_ruleset_matches (ruleset, path, state))
         continue;
 
-      val = g_hash_table_lookup (ruleset->widget_style, prop_name);
+      for (val = ruleset->widget_style; val != NULL; val = val->next)
+	{
+	  if (strcmp (val->name, prop_name) == 0)
+	    {
+	      GtkCssScanner *scanner;
 
-      if (val)
-        {
-          GtkCssScanner *scanner;
+	      scanner = gtk_css_scanner_new (css_provider,
+					     NULL,
+					     val->section,
+					     gtk_css_section_get_file (val->section),
+					     g_value_get_string (&val->value));
 
-          scanner = gtk_css_scanner_new (css_provider,
-                                         NULL,
-                                         val->section,
-                                         gtk_css_section_get_file (val->section),
-                                         g_value_get_string (&val->value));
+	      found = _gtk_css_style_parse_value (value,
+						  scanner->parser,
+						  NULL);
 
-          found = _gtk_css_style_parse_value (value,
-                                              scanner->parser,
-                                              NULL);
+	      gtk_css_scanner_destroy (scanner);
 
-          gtk_css_scanner_destroy (scanner);
+	      break;
+	    }
+	}
 
-          if (found)
-            break;
-        }
+      if (found)
+	break;
     }
 
   g_free (prop_name);
@@ -1542,8 +1639,7 @@ gtk_css_style_provider_lookup (GtkStyleProviderPrivate *provider,
   for (i = priv->rulesets->len - 1; i >= 0; i--)
     {
       GtkCssRuleset *ruleset;
-      GHashTableIter iter;
-      gpointer key, val;
+      PropertyValue *value;
 
       ruleset = &g_array_index (priv->rulesets, GtkCssRuleset, i);
 
@@ -1557,12 +1653,9 @@ gtk_css_style_provider_lookup (GtkStyleProviderPrivate *provider,
       if (!gtk_css_ruleset_matches (ruleset, path, state))
         continue;
 
-      g_hash_table_iter_init (&iter, ruleset->style);
-
-      while (g_hash_table_iter_next (&iter, &key, &val))
+      for (value = ruleset->style; value != NULL; value = value->next)
         {
-          GtkCssStyleProperty *prop = key;
-          PropertyValue *value = val;
+          GtkCssStyleProperty *prop = GTK_CSS_STYLE_PROPERTY (value->property);
           guint id = _gtk_css_style_property_get_id (prop);
 
           if (!_gtk_css_lookup_is_missing (lookup, id))
@@ -2383,7 +2476,7 @@ parse_declaration (GtkCssScanner *scanner,
 
       gtk_css_scanner_push_section (scanner, GTK_CSS_SECTION_VALUE);
 
-      val = property_value_new (scanner->section);
+      val = property_value_new (property, scanner->section);
 
       if (_gtk_style_property_parse_value (property,
                                            &val->value,
@@ -2429,9 +2522,9 @@ parse_declaration (GtkCssScanner *scanner,
       value_str = _gtk_css_parser_read_value (scanner->parser);
       if (value_str)
         {
-          PropertyValue *val;
+          WidgetPropertyValue *val;
 
-          val = property_value_new (scanner->section);
+          val = widget_property_value_new (name, scanner->section);
           g_value_init (&val->value, G_TYPE_STRING);
           g_value_take_string (&val->value, value_str);
 
@@ -2970,15 +3063,27 @@ gtk_css_provider_get_named (const gchar *name,
 static int
 compare_properties (gconstpointer a, gconstpointer b)
 {
-  return strcmp (_gtk_style_property_get_name ((GtkStyleProperty *) a),
-                 _gtk_style_property_get_name ((GtkStyleProperty *) b));
+  const PropertyValue *aa = a;
+  const PropertyValue *bb = b;
+  return strcmp (_gtk_style_property_get_name ((GtkStyleProperty *)aa->property),
+                 _gtk_style_property_get_name ((GtkStyleProperty *)bb->property));
+}
+
+static int
+compare_names (gconstpointer a, gconstpointer b)
+{
+  const WidgetPropertyValue *aa = a;
+  const WidgetPropertyValue *bb = b;
+  return strcmp (aa->name, bb->name);
 }
 
 static void
 gtk_css_ruleset_print (const GtkCssRuleset *ruleset,
                        GString             *str)
 {
-  GList *keys, *walk;
+  GList *values, *walk;
+  PropertyValue *value;
+  WidgetPropertyValue *widget_value;
 
   _gtk_css_selector_print (ruleset->selector, str);
 
@@ -2986,14 +3091,18 @@ gtk_css_ruleset_print (const GtkCssRuleset *ruleset,
 
   if (ruleset->style)
     {
-      keys = g_hash_table_get_keys (ruleset->style);
+      values = NULL;
+      for (value = ruleset->style; value != NULL; value = value->next)
+	values = g_list_prepend (values, value);
+
       /* so the output is identical for identical selector styles */
-      keys = g_list_sort (keys, compare_properties);
+      values = g_list_sort (values, compare_properties);
 
-      for (walk = keys; walk; walk = walk->next)
+      for (walk = values; walk; walk = walk->next)
         {
-          GtkCssStyleProperty *prop = walk->data;
-          const PropertyValue *value = g_hash_table_lookup (ruleset->style, prop);
+          GtkCssStyleProperty *prop;
+	  value = walk->data;
+	  prop = GTK_CSS_STYLE_PROPERTY (value->property);
 
           g_string_append (str, "  ");
           g_string_append (str, _gtk_style_property_get_name (GTK_STYLE_PROPERTY (prop)));
@@ -3002,28 +3111,30 @@ gtk_css_ruleset_print (const GtkCssRuleset *ruleset,
           g_string_append (str, ";\n");
         }
 
-      g_list_free (keys);
+      g_list_free (values);
     }
 
   if (ruleset->widget_style)
     {
-      keys = g_hash_table_get_keys (ruleset->widget_style);
+      values = NULL;
+      for (widget_value = ruleset->widget_style; widget_value != NULL; widget_value = widget_value->next)
+	values = g_list_prepend (values, widget_value);
+
       /* so the output is identical for identical selector styles */
-      keys = g_list_sort (keys, (GCompareFunc) strcmp);
+      values = g_list_sort (values, compare_names);
 
-      for (walk = keys; walk; walk = walk->next)
+      for (walk = values; walk; walk = walk->next)
         {
-          const char *name = walk->data;
-          const PropertyValue *value = g_hash_table_lookup (ruleset->widget_style, (gpointer) name);
+	  widget_value = walk->data;
 
           g_string_append (str, "  ");
-          g_string_append (str, name);
+          g_string_append (str, widget_value->name);
           g_string_append (str, ": ");
-          g_string_append (str, g_value_get_string (&value->value));
+          g_string_append (str, g_value_get_string (&widget_value->value));
           g_string_append (str, ";\n");
         }
 
-      g_list_free (keys);
+      g_list_free (values);
     }
 
   g_string_append (str, "}\n");



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]