[glib/filechooserentry: 2/10] fileinfo: Change the way attribute matchers are created



commit d77e0064c0f9adfe22c16730118c587c658f1db3
Author: Benjamin Otte <otte redhat com>
Date:   Tue Nov 1 13:58:09 2011 +0100

    fileinfo: Change the way attribute matchers are created
    
    We now sort the matchers and remove unnecessary duplicates (like
    removing standard:type when we already match standard:*), so that we can
    do more complex operations on them easily in later commits.

 gio/gfileinfo.c |  102 ++++++++++++++++++++++++++++++++++++++++---------------
 1 files changed, 74 insertions(+), 28 deletions(-)
---
diff --git a/gio/gfileinfo.c b/gio/gfileinfo.c
index f3f92c3..ec08b0d 100644
--- a/gio/gfileinfo.c
+++ b/gio/gfileinfo.c
@@ -2102,36 +2102,79 @@ struct _GFileAttributeMatcher {
   gint iterator_pos;
 };
 
-static void
-matcher_add (GFileAttributeMatcher *matcher,
-	     guint                  id,
-             guint                  mask)
+G_DEFINE_BOXED_TYPE (GFileAttributeMatcher, g_file_attribute_matcher,
+                     g_file_attribute_matcher_ref,
+                     g_file_attribute_matcher_unref)
+
+static gint
+compare_sub_matchers (gconstpointer a,
+                      gconstpointer b)
 {
-  SubMatcher *sub_matchers;
-  int i;
-  SubMatcher s;
+  const SubMatcher *suba = a;
+  const SubMatcher *subb = b;
+  int diff;
+
+  diff = suba->id - subb->id;
+
+  if (diff)
+    return diff;
+
+  return suba->mask - subb->mask;
+}
+
+static gboolean
+sub_matcher_matches (SubMatcher *matcher,
+                     SubMatcher *submatcher)
+{
+  if ((matcher->mask & submatcher->mask) != matcher->mask)
+    return FALSE;
+  
+  return matcher->id == (submatcher->id & matcher->mask);
+}
 
-  if (matcher->sub_matchers == NULL)
-    matcher->sub_matchers = g_array_new (FALSE, FALSE, sizeof (SubMatcher));
+/* Call this function after modifying a matcher.
+ * It will ensure all the invariants other functions rely on.
+ */
+static void
+matcher_optimize (GFileAttributeMatcher *matcher)
+{
+  SubMatcher *submatcher, *compare;
+  guint i, j;
 
-  sub_matchers = (SubMatcher *)matcher->sub_matchers->data;
-  for (i = 0; i < matcher->sub_matchers->len; i++)
+  /* remove sub_matchers if we match everything anyway */
+  if (matcher->all)
     {
-      /* Already added */
-      if (sub_matchers[i].id == id &&
-	  sub_matchers[i].mask == mask)
-	return;
+      if (matcher->sub_matchers)
+        {
+          g_array_free (matcher->sub_matchers, TRUE);
+          matcher->sub_matchers = NULL;
+        }
+      return matcher;
     }
 
-  s.id = id;
-  s.mask = mask;
+  /* sort sub_matchers by id (and then mask), so we can bsearch
+   * and compare matchers in O(N) instead of O(NÂ) */
+  g_array_sort (matcher->sub_matchers, compare_sub_matchers);
 
-  g_array_append_val (matcher->sub_matchers, s);
-}
+  /* remove duplicates and specific matches when we match the whole namespace */
+  j = 0;
+  compare = &g_array_index (matcher->sub_matchers, SubMatcher, j);
 
-G_DEFINE_BOXED_TYPE (GFileAttributeMatcher, g_file_attribute_matcher,
-                     g_file_attribute_matcher_ref,
-                     g_file_attribute_matcher_unref)
+  for (i = 1; i < matcher->sub_matchers->len; i++)
+    {
+      submatcher = &g_array_index (matcher->sub_matchers, SubMatcher, i);
+      if (sub_matcher_matches (compare, submatcher))
+        continue;
+
+      j++;
+      compare++;
+
+      if (j < i)
+        *compare = *submatcher;
+    }
+
+  g_array_set_size (matcher->sub_matchers, j + 1);
+}
 
 /**
  * g_file_attribute_matcher_new:
@@ -2177,6 +2220,7 @@ g_file_attribute_matcher_new (const char *attributes)
 
   matcher = g_malloc0 (sizeof (GFileAttributeMatcher));
   matcher->ref = 1;
+  matcher->sub_matchers = g_array_new (FALSE, FALSE, sizeof (SubMatcher));
 
   split = g_strsplit (attributes, ",", -1);
 
@@ -2186,7 +2230,7 @@ g_file_attribute_matcher_new (const char *attributes)
 	matcher->all = TRUE;
       else
 	{
-	  guint32 id, mask;
+          SubMatcher s;
 
 	  colon = strstr (split[i], "::");
 	  if (colon != NULL &&
@@ -2194,24 +2238,26 @@ g_file_attribute_matcher_new (const char *attributes)
 		(colon[2] == '*' &&
 		 colon[3] == 0)))
 	    {
-	      id = lookup_attribute (split[i]);
-	      mask = 0xffffffff;
+	      s.id = lookup_attribute (split[i]);
+	      s.mask = 0xffffffff;
 	    }
 	  else
 	    {
 	      if (colon)
 		*colon = 0;
 
-	      id = lookup_namespace (split[i]) << NS_POS;
-	      mask = NS_MASK << NS_POS;
+	      s.id = lookup_namespace (split[i]) << NS_POS;
+	      s.mask = NS_MASK << NS_POS;
 	    }
 
-	  matcher_add (matcher, id, mask);
+          g_array_append_val (matcher->sub_matchers, s);
 	}
     }
 
   g_strfreev (split);
 
+  matcher_optimize (matcher);
+
   return matcher;
 }
 



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