[gnome-builder/wip/libide] libide: use GPtrArray instead of GList for results



commit 42c0be6693d844bc5dab1e2a85c3b72c9d9ba9ba
Author: Christian Hergert <christian hergert me>
Date:   Sun Mar 15 16:33:06 2015 -0700

    libide: use GPtrArray instead of GList for results
    
    We should only fallback to GList at the very last moment before passing
    data to GtkSourceCompletionContext. Everything else causes incredibly
    poor performance.

 libide/clang/ide-clang-completion-provider.c |  107 ++++++++++++++++++++++++-
 libide/clang/ide-clang-translation-unit.c    |   20 ++---
 libide/clang/ide-clang-translation-unit.h    |    2 +-
 3 files changed, 110 insertions(+), 19 deletions(-)
---
diff --git a/libide/clang/ide-clang-completion-provider.c b/libide/clang/ide-clang-completion-provider.c
index 1b46bdc..2d8ff77 100644
--- a/libide/clang/ide-clang-completion-provider.c
+++ b/libide/clang/ide-clang-completion-provider.c
@@ -16,9 +16,12 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#define G_LOG_DOMAIN "ide-clang-completion"
+
 #include <glib/gi18n.h>
 
 #include "ide-buffer.h"
+#include "ide-clang-completion-item.h"
 #include "ide-clang-completion-provider.h"
 #include "ide-clang-service.h"
 #include "ide-clang-translation-unit.h"
@@ -34,6 +37,8 @@ struct _IdeClangCompletionProviderClass
 struct _IdeClangCompletionProvider
 {
   GObject parent_instance;
+
+  GPtrArray *last_results;
 };
 
 typedef struct
@@ -67,6 +72,78 @@ add_proposals_state_free (AddProposalsState *state)
   g_free (state);
 }
 
+static gboolean
+stop_on_predicate (gunichar ch,
+                   gpointer data)
+{
+  switch (ch)
+    {
+    case '_':
+      return FALSE;
+
+    case ')':
+    case '(':
+    case '&':
+    case '*':
+    case '{':
+    case '}':
+    case ' ':
+    case '\t':
+    case '[':
+    case ']':
+    case '=':
+    case '"':
+    case '\'':
+      return TRUE;
+
+    default:
+      return !g_unichar_isalnum (ch);
+    }
+}
+
+static gchar *
+get_word (const GtkTextIter *location)
+{
+  GtkTextIter iter = *location;
+  GtkTextBuffer *buffer;
+  GtkTextIter end;
+
+  end = iter;
+  buffer = gtk_text_iter_get_buffer (&iter);
+
+  if (!gtk_text_iter_backward_find_char (&iter, stop_on_predicate, NULL, NULL))
+    return gtk_text_buffer_get_text (buffer, &iter, &end, TRUE);
+
+  gtk_text_iter_forward_char (&iter);
+
+  return gtk_text_iter_get_text (&iter, &end);
+}
+
+static GList *
+filter_list (GPtrArray   *ar,
+             const gchar *word)
+{
+  g_autoptr(GPtrArray) matched = NULL;
+  GList *ret = NULL;
+  gsize i;
+
+  matched = g_ptr_array_new ();
+
+  for (i = 0; i < ar->len; i++)
+    {
+      IdeClangCompletionItem *item;
+
+      item = g_ptr_array_index (ar, i);
+      if (ide_clang_completion_item_matches (item, word))
+        g_ptr_array_add (matched, item);
+    }
+
+  for (i = 0; i < matched->len; i++)
+    ret = g_list_prepend (ret, g_ptr_array_index (matched, i));
+
+  return ret;
+}
+
 static void
 ide_clang_completion_provider_class_init (IdeClangCompletionProviderClass *klass)
 {
@@ -89,21 +166,41 @@ ide_clang_completion_provider_complete_cb (GObject      *object,
                                            gpointer      user_data)
 {
   IdeClangTranslationUnit *tu = (IdeClangTranslationUnit *)object;
+  IdeClangCompletionProvider *self;
   AddProposalsState *state = user_data;
+  g_autofree gchar *word = NULL;
+  g_autoptr(GPtrArray) ar = NULL;
+  GtkTextIter iter;
   GError *error = NULL;
-  GList *list;
+  GList *filtered = NULL;
+
+  self = (IdeClangCompletionProvider *)state->provider;
 
-  list = ide_clang_translation_unit_code_complete_finish (tu, result, &error);
+  ar = ide_clang_translation_unit_code_complete_finish (tu, result, &error);
 
-  if (!list && error)
+  if (!ar)
     {
       g_warning ("%s", error->message);
       g_clear_error (&error);
+      goto failure;
     }
 
+  g_clear_pointer (&self->last_results, g_ptr_array_free);
+  self->last_results = g_ptr_array_ref (ar);
+
+  gtk_source_completion_context_get_iter (state->context, &iter);
+  word = get_word (&iter);
+
+  IDE_TRACE_MSG ("Current word: %s", word ?: "(null)");
+
+  if (word)
+    filtered = filter_list (ar, word);
+
+failure:
   if (!g_cancellable_is_cancelled (state->cancellable))
-    gtk_source_completion_context_add_proposals (state->context, state->provider, list, TRUE);
-  g_list_free_full (list, g_object_unref);
+    gtk_source_completion_context_add_proposals (state->context, state->provider, filtered, TRUE);
+
+  g_list_free (filtered);
   add_proposals_state_free (state);
 }
 
diff --git a/libide/clang/ide-clang-translation-unit.c b/libide/clang/ide-clang-translation-unit.c
index 9770d9a..3188afe 100644
--- a/libide/clang/ide-clang-translation-unit.c
+++ b/libide/clang/ide-clang-translation-unit.c
@@ -466,12 +466,6 @@ ide_clang_translation_unit_init (IdeClangTranslationUnit *self)
 }
 
 static void
-cleanup_list (gpointer data)
-{
-  g_list_free_full (data, g_object_unref);
-}
-
-static void
 ide_clang_translation_unit_code_complete_worker (GTask        *task,
                                                  gpointer      source_object,
                                                  gpointer      task_data,
@@ -482,7 +476,7 @@ ide_clang_translation_unit_code_complete_worker (GTask        *task,
   CXCodeCompleteResults *results;
   g_autoptr(IdeRefPtr) refptr = NULL;
   struct CXUnsavedFile *ufs;
-  GList *list = NULL;
+  g_autoptr(GPtrArray) ar = NULL;
   gsize i;
   gsize j = 0;
 
@@ -546,6 +540,7 @@ ide_clang_translation_unit_code_complete_worker (GTask        *task,
    * we will inflate result strings as necessary.
    */
   refptr = ide_ref_ptr_new (results, (GDestroyNotify)clang_disposeCodeCompleteResults);
+  ar = g_ptr_array_new ();
 
   for (i = 0; i < results->NumResults; i++)
     {
@@ -555,10 +550,10 @@ ide_clang_translation_unit_code_complete_worker (GTask        *task,
                                "results", ide_ref_ptr_ref (refptr),
                                "index", (guint)i,
                                NULL);
-      list = g_list_prepend (list, proposal);
+      g_ptr_array_add (ar, proposal);
     }
 
-  g_task_return_pointer (task, g_list_reverse (list), cleanup_list);
+  g_task_return_pointer (task, g_ptr_array_ref (ar), (GDestroyNotify)g_ptr_array_unref);
 
   /* cleanup malloc'd state */
   for (i = 0; i < j; i++)
@@ -614,11 +609,10 @@ ide_clang_translation_unit_code_complete_async (IdeClangTranslationUnit *self,
  *
  * Completes a call to ide_clang_translation_unit_code_complete_async().
  *
- * Returns: (transfer full) (element-type GtkSourceCompletionProposal*): A list of
- *   #GtkSourceCompletionProposal. If this is %NULL, check @error to determine if
- *   there was an error.
+ * Returns: (transfer container) (element-type GtkSourceCompletionProposal*): An array of
+ *   #GtkSourceCompletionProposal. Upon failure, %NULL is returned.
  */
-GList *
+GPtrArray *
 ide_clang_translation_unit_code_complete_finish (IdeClangTranslationUnit  *self,
                                                  GAsyncResult             *result,
                                                  GError                  **error)
diff --git a/libide/clang/ide-clang-translation-unit.h b/libide/clang/ide-clang-translation-unit.h
index 60e5539..4d59c9c 100644
--- a/libide/clang/ide-clang-translation-unit.h
+++ b/libide/clang/ide-clang-translation-unit.h
@@ -37,7 +37,7 @@ void            ide_clang_translation_unit_code_complete_async  (IdeClangTransla
                                                                  GCancellable             *cancellable,
                                                                  GAsyncReadyCallback       callback,
                                                                  gpointer                  user_data);
-GList          *ide_clang_translation_unit_code_complete_finish (IdeClangTranslationUnit  *self,
+GPtrArray      *ide_clang_translation_unit_code_complete_finish (IdeClangTranslationUnit  *self,
                                                                  GAsyncResult             *result,
                                                                  GError                  **error);
 


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