[devhelp] SearchContext: improve performances of match_link()



commit 2275259df343706545bf0a57dbaf50f16a662a58
Author: Sébastien Wilmet <swilmet gnome org>
Date:   Sun Jan 21 15:15:33 2018 +0100

    SearchContext: improve performances of match_link()
    
    The execution time of dh_keyword_model_filter():
    before: ~25ms
    after: ~21ms
    a bit better.

 src/dh-search-context.c |   99 +++++++++++++++++++++++++++++++----------------
 1 files changed, 65 insertions(+), 34 deletions(-)
---
diff --git a/src/dh-search-context.c b/src/dh-search-context.c
index ad0b26a..9fe970f 100644
--- a/src/dh-search-context.c
+++ b/src/dh-search-context.c
@@ -43,12 +43,17 @@ struct _DhSearchContext {
 };
 
 typedef struct _KeywordData {
-        /* Created only for the first keyword. */
+        gchar *keyword;
+
+        /* Created only if has_glob and is_first. */
         GPatternSpec *pattern_spec_prefix;
         GPatternSpec *pattern_spec_nonprefix;
 
-        /* Created only for the remaining keywords. */
+        /* Created only if has_glob and !is_first. */
         GPatternSpec *pattern_spec_anywhere;
+
+        guint is_first : 1;
+        guint has_glob : 1;
 } KeywordData;
 
 /* Process the input search string and extract:
@@ -217,25 +222,35 @@ set_case_sensitive (DhSearchContext *search)
 
 static KeywordData *
 keyword_data_new (const gchar *keyword,
-                  gboolean     first_keyword)
+                  gboolean     is_first)
 {
         KeywordData *data;
-        gchar *pattern;
 
-        data = g_new0 (KeywordData, 1);
+        g_return_val_if_fail (keyword != NULL, NULL);
 
-        if (first_keyword) {
-                pattern = g_strdup_printf ("%s*", keyword);
-                data->pattern_spec_prefix = g_pattern_spec_new (pattern);
-                g_free (pattern);
+        data = g_new0 (KeywordData, 1);
 
-                pattern = g_strdup_printf ("?*%s*", keyword);
-                data->pattern_spec_nonprefix = g_pattern_spec_new (pattern);
-                g_free (pattern);
-        } else {
-                pattern = g_strdup_printf ("*%s*", keyword);
-                data->pattern_spec_anywhere = g_pattern_spec_new (pattern);
-                g_free (pattern);
+        data->keyword = g_strdup (keyword);
+        data->is_first = is_first != FALSE;
+        data->has_glob = (strchr (keyword, '*') != NULL ||
+                          strchr (keyword, '?') != NULL);
+
+        if (data->has_glob) {
+                gchar *pattern;
+
+                if (is_first) {
+                        pattern = g_strdup_printf ("%s*", keyword);
+                        data->pattern_spec_prefix = g_pattern_spec_new (pattern);
+                        g_free (pattern);
+
+                        pattern = g_strdup_printf ("?*%s*", keyword);
+                        data->pattern_spec_nonprefix = g_pattern_spec_new (pattern);
+                        g_free (pattern);
+                } else {
+                        pattern = g_strdup_printf ("*%s*", keyword);
+                        data->pattern_spec_anywhere = g_pattern_spec_new (pattern);
+                        g_free (pattern);
+                }
         }
 
         return data;
@@ -249,6 +264,8 @@ keyword_data_free (gpointer _data)
         if (data == NULL)
                 return;
 
+        g_free (data->keyword);
+
         if (data->pattern_spec_prefix != NULL)
                 g_pattern_spec_free (data->pattern_spec_prefix);
 
@@ -276,7 +293,8 @@ create_keywords_data (DhSearchContext *search)
                 KeywordData *data;
 
                 data = keyword_data_new (cur_keyword, keyword_num == 0);
-                search->keywords_data = g_slist_prepend (search->keywords_data, data);
+                if (data != NULL)
+                        search->keywords_data = g_slist_prepend (search->keywords_data, data);
         }
 
         search->keywords_data = g_slist_reverse (search->keywords_data);
@@ -389,7 +407,7 @@ _dh_search_context_match_link (DhSearchContext *search,
                                gboolean         prefix)
 {
         gchar *str_to_free = NULL;
-        const gchar *name;
+        const gchar *link_name;
         gboolean match = FALSE;
         GSList *l;
 
@@ -412,12 +430,14 @@ _dh_search_context_match_link (DhSearchContext *search,
                 return FALSE;
 
         if (search->case_sensitive) {
-                name = dh_link_get_name (link);
+                link_name = dh_link_get_name (link);
         } else {
                 str_to_free = g_ascii_strdown (dh_link_get_name (link), -1);
-                name = str_to_free;
+                link_name = str_to_free;
         }
 
+        g_return_val_if_fail (link_name != NULL, FALSE);
+
         /* Why isn't there only one GPatternSpec (or two variants:
          * prefix/nonprefix) for all the keywords? For example searching
          * "dh_link_ book" (two keywords) would create the GPatternSpec
@@ -451,25 +471,36 @@ _dh_search_context_match_link (DhSearchContext *search,
          *   namespace.
          */
 
-        /* Possible performance optimization (if it appears that there is a
-         * performance problem):
-         *
-         * If a keyword doesn't contain globs ('*' or '?'), use simple string
-         * functions like g_str_has_prefix() and strstr().
+        /* Use simple string functions when the keyword doesn't contain globs,
+         * to improve performances (this function can be called on *every*
+         * DhLink).
          */
 
         for (l = search->keywords_data; l != NULL; l = l->next) {
                 KeywordData *data = l->data;
 
-                /* For all keywords except the first. */
-                if (data->pattern_spec_anywhere != NULL)
-                        match = g_pattern_match_string (data->pattern_spec_anywhere, name);
-
-                /* For the first keyword. */
-                else if (prefix)
-                        match = g_pattern_match_string (data->pattern_spec_prefix, name);
-                else
-                        match = g_pattern_match_string (data->pattern_spec_nonprefix, name);
+                if (data->is_first) {
+                        if (data->has_glob) {
+                                if (prefix) {
+                                        match = g_pattern_match_string (data->pattern_spec_prefix, 
link_name);
+                                } else {
+                                        match = g_pattern_match_string (data->pattern_spec_nonprefix, 
link_name);
+                                }
+                        } else {
+                                if (prefix) {
+                                        match = g_str_has_prefix (link_name, data->keyword);
+                                } else {
+                                        match = (!g_str_has_prefix (link_name, data->keyword) &&
+                                                 strstr (link_name, data->keyword) != NULL);
+                                }
+                        }
+                } else {
+                        if (data->has_glob) {
+                                match = g_pattern_match_string (data->pattern_spec_anywhere, link_name);
+                        } else {
+                                match = strstr (link_name, data->keyword) != NULL;
+                        }
+                }
 
                 if (!match)
                         break;


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