[gtk+] Avoid O(n²) walking of string arrays



commit e259b2f30d86fdde7dab27a25e8088d36421acc7
Author: Emmanuele Bassi <ebassi gnome org>
Date:   Thu Jul 16 16:12:35 2015 +0100

    Avoid O(n²) walking of string arrays
    
    "Yo, we heard you like traversing NULL-terminated arrays to operate on
    them, so we called g_strv_length() as the for condition, so you can
    iterate the array while iterating the array."
    
    Instead of making famed rapper and television producer Xzibit proud, we
    should avoid calling g_strv_length() on an array while looping on the
    array, to avoid quadratic complexity.
    
    We do this in various places that deal with arrays of strings that we
    cannot really guess are short enough not to matter — e.g. the list of
    CSS selectors in the inspector, or the required authentication
    information for printing.

 gtk/gtkprintbackend.c                            |   25 ++++++++++++---------
 gtk/inspector/selector.c                         |    5 ++-
 modules/printbackends/cups/gtkcupssecretsutils.c |    5 ++-
 testsuite/a11y/state/state-record.c              |    7 +++--
 4 files changed, 24 insertions(+), 18 deletions(-)
---
diff --git a/gtk/gtkprintbackend.c b/gtk/gtkprintbackend.c
index cda9376..8ec6dbc 100644
--- a/gtk/gtkprintbackend.c
+++ b/gtk/gtkprintbackend.c
@@ -706,24 +706,27 @@ password_dialog_response (GtkWidget       *dialog,
                           GtkPrintBackend *backend)
 {
   GtkPrintBackendPrivate *priv = backend->priv;
-  gint i;
+  gint i, auth_info_len;
 
   if (response_id == GTK_RESPONSE_OK)
     gtk_print_backend_set_password (backend, priv->auth_info_required, priv->auth_info, 
priv->store_auth_info);
   else
     gtk_print_backend_set_password (backend, priv->auth_info_required, NULL, FALSE);
 
-  for (i = 0; i < g_strv_length (priv->auth_info_required); i++)
-    if (priv->auth_info[i] != NULL)
-      {
-        memset (priv->auth_info[i], 0, strlen (priv->auth_info[i]));
-        g_free (priv->auth_info[i]);
-        priv->auth_info[i] = NULL;
-      }
-  g_free (priv->auth_info);
-  priv->auth_info = NULL;
+  /* We want to clear the data before freeing it */
+  auth_info_len = g_strv_length (priv->auth_info_required);
+  for (i = 0; i < auth_info_len; i++)
+    {
+      if (priv->auth_info[i] != NULL)
+        {
+          memset (priv->auth_info[i], 0, strlen (priv->auth_info[i]));
+          g_free (priv->auth_info[i]);
+          priv->auth_info[i] = NULL;
+        }
+    }
 
-  g_strfreev (priv->auth_info_required);
+  g_clear_pointer (&priv->auth_info, g_free);
+  g_clear_pointer (&priv->auth_info_required, g_strfreev);
 
   gtk_widget_destroy (dialog);
 
diff --git a/gtk/inspector/selector.c b/gtk/inspector/selector.c
index e19f74c..c820d3b 100644
--- a/gtk/inspector/selector.c
+++ b/gtk/inspector/selector.c
@@ -64,7 +64,7 @@ gtk_inspector_selector_set_object (GtkInspectorSelector *oh,
                                    GObject              *object)
 {
   GtkTreeIter iter, parent;
-  gint i;
+  gint i, words_len;
   GtkWidget *widget;
   gchar *path, **words;
   const gchar *title;
@@ -85,7 +85,8 @@ gtk_inspector_selector_set_object (GtkInspectorSelector *oh,
   path = gtk_widget_path_to_string (gtk_widget_get_path (widget));
   words = g_strsplit (path, " ", 0);
 
-  for (i = 0; i < g_strv_length (words); i++)
+  words_len = g_strv_length (words);
+  for (i = 0; i < words_len; i++)
     {
       gtk_tree_store_append (oh->priv->model, &iter, i ? &parent : NULL);
       gtk_tree_store_set (oh->priv->model, &iter,
diff --git a/modules/printbackends/cups/gtkcupssecretsutils.c 
b/modules/printbackends/cups/gtkcupssecretsutils.c
index d5df4a7..925f7d5 100644
--- a/modules/printbackends/cups/gtkcupssecretsutils.c
+++ b/modules/printbackends/cups/gtkcupssecretsutils.c
@@ -109,7 +109,7 @@ get_secret_cb (GObject      *source_object,
                      *key = NULL,
                      *value = NULL;
   GVariantIter       *iter = NULL;
-  guint               i;
+  guint               i, required_len;
   gint                pw_field = -1;
 
   task = user_data;
@@ -228,7 +228,8 @@ get_secret_cb (GObject      *source_object,
 fail:
   /* Error out */
   GTK_NOTE (PRINTING, g_print ("Failed to lookup secret.\n"));
-  for (i = 0; i < g_strv_length (task_data->auth_info_required); i++)
+  required_len = g_strv_length (task_data->auth_info_required);
+  for (i = 0; i < required_len; i++)
     {
       /* Not all fields of auth_info are neccessarily written so we can not
          use strfreev here */
diff --git a/testsuite/a11y/state/state-record.c b/testsuite/a11y/state/state-record.c
index cf9313b..dd37c62 100644
--- a/testsuite/a11y/state/state-record.c
+++ b/testsuite/a11y/state/state-record.c
@@ -142,7 +142,7 @@ record_events (const gchar *ui_file,
   GError *error;
   gchar *contents;
   gchar **actions;
-  gint i;
+  gint i, len;
 
   builder = gtk_builder_new ();
   error = NULL;
@@ -152,8 +152,9 @@ record_events (const gchar *ui_file,
   g_file_get_contents (in_file, &contents, NULL, &error);
   g_assert_no_error (error);
   actions = g_strsplit (contents, "\n", 0);
- 
-  for (i = 0; i < g_strv_length (actions); i++)
+
+  len = g_strv_length (actions);
+  for (i = 0; i < len; i++)
     do_action (builder, actions[i], string);
 
   g_object_unref (builder);


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