[gobject-introspection] girepository: Refactor lookup code



commit f97cc8687469f25752f7927545ad4daecef8ab44
Author: Colin Walters <walters verbum org>
Date:   Mon Oct 18 12:04:08 2010 -0400

    girepository: Refactor lookup code
    
    This is a cleanup patch in preparation for future indexing
    patches.
    
    The lookup code was a mess trying to mash in the 3 different
    cases of name, GType, and index into one mega-function.
    
    Split it up properly, and move the core typelib internal-scanning
    bits into gitypelib.c where it belongs.

 girepository/girepository.c       |  215 ++++++++++++-------------------------
 girepository/gitypelib-internal.h |    7 ++
 girepository/gitypelib.c          |   74 +++++++++++++
 3 files changed, 150 insertions(+), 146 deletions(-)
---
diff --git a/girepository/girepository.c b/girepository/girepository.c
index 712118d..18ecafb 100644
--- a/girepository/girepository.c
+++ b/girepository/girepository.c
@@ -515,108 +515,6 @@ g_irepository_get_n_infos (GIRepository *repository,
   return n_interfaces;
 }
 
-typedef struct
-{
-  GIRepository *repo;
-  gint index;
-  const gchar *name;
-  gboolean type_firstpass;
-  const gchar *type;
-  GIBaseInfo *iface;
-} IfaceData;
-
-static void
-find_interface (gpointer key,
-		gpointer value,
-		gpointer data)
-{
-  gint i;
-  GITypelib *typelib = (GITypelib *)value;
-  Header *header = (Header *) typelib->data;
-  IfaceData *iface_data = (IfaceData *)data;
-  gint index;
-  gint n_entries;
-  const gchar *name;
-  const gchar *type;
-  DirEntry *entry;
-
-  index = 0;
-  n_entries = ((Header *)typelib->data)->n_local_entries;
-
-  if (iface_data->name)
-    {
-      for (i = 1; i <= n_entries; i++)
-	{
-	  entry = g_typelib_get_dir_entry (typelib, i);
-	  name = g_typelib_get_string (typelib, entry->name);
-	  if (strcmp (name, iface_data->name) == 0)
-	    {
-	      index = i;
-	      break;
-	    }
-	}
-    }
-  else if (iface_data->type)
-    {
-      const char *c_prefix;
-      /* Inside each typelib, we include the "C prefix" which acts as
-       * a namespace mechanism.  For GtkTreeView, the C prefix is Gtk.
-       * Given the assumption that GTypes for a library also use the
-       * C prefix, we know we can skip examining a typelib if our
-       * target type does not have this typelib's C prefix.
-       *
-       * However, not every class library necessarily conforms to this,
-       * e.g. Clutter has Cogl inside it.  So, we split this into two
-       * passes.  First we try a lookup, skipping things which don't
-       * have the prefix.  If that fails then we try a global lookup,
-       * ignoring the prefix.
-       *
-       * See http://bugzilla.gnome.org/show_bug.cgi?id=564016
-       */
-      c_prefix = g_typelib_get_string (typelib, header->c_prefix);
-      if (iface_data->type_firstpass && c_prefix != NULL)
-        {
-          if (g_ascii_strncasecmp (c_prefix, iface_data->type, strlen (c_prefix)) != 0)
-            return;
-        }
-
-      for (i = 1; i <= n_entries; i++)
-	{
-	  RegisteredTypeBlob *blob;
-
-	  entry = g_typelib_get_dir_entry (typelib, i);
-	  if (!BLOB_IS_REGISTERED_TYPE (entry))
-	    continue;
-
-	  blob = (RegisteredTypeBlob *)(&typelib->data[entry->offset]);
-	  if (!blob->gtype_name)
-	    continue;
-
-	  type = g_typelib_get_string (typelib, blob->gtype_name);
-	  if (strcmp (type, iface_data->type) == 0)
-	    {
-	      index = i;
-	      break;
-	    }
-	}
-    }
-  else if (iface_data->index > n_entries)
-    iface_data->index -= n_entries;
-  else if (iface_data->index > 0)
-    {
-      index = iface_data->index;
-      iface_data->index = 0;
-    }
-
-  if (index != 0)
-    {
-      entry = g_typelib_get_dir_entry (typelib, index);
-      iface_data->iface = _g_info_new_full (entry->blob_type,
-				 	    iface_data->repo,
-					    NULL, typelib, entry->offset);
-    }
-}
-
 /**
  * g_irepository_get_info:
  * @repository: (allow-none): A #GIRepository, may be %NULL for the default
@@ -634,26 +532,48 @@ g_irepository_get_info (GIRepository *repository,
 			const gchar  *namespace,
 			gint          index)
 {
-  IfaceData data;
   GITypelib *typelib;
+  DirEntry *entry;
 
   g_return_val_if_fail (namespace != NULL, NULL);
 
   repository = get_repository (repository);
 
-  data.repo = repository;
-  data.name = NULL;
-  data.type = NULL;
-  data.index = index + 1;
-  data.iface = NULL;
-
   typelib = get_registered (repository, namespace, NULL);
 
   g_return_val_if_fail (typelib != NULL, NULL);
 
-  find_interface ((void *)namespace, typelib, &data);
+  entry = g_typelib_get_dir_entry (typelib, index);
+  if (entry == NULL)
+    return NULL;
+  return _g_info_new_full (entry->blob_type,
+			   repository,
+			   NULL, typelib, entry->offset);
+}
+
+typedef struct {
+  GIRepository *repository;
+  GType type;
 
-  return data.iface;
+  gboolean fastpass;
+  GITypelib *result_typelib;
+  DirEntry *result;
+} FindByGTypeData;
+
+static void
+find_by_gtype_foreach (gpointer key,
+		       gpointer value,
+		       gpointer datap)
+{
+  GITypelib *typelib = (GITypelib*)value;
+  FindByGTypeData *data = datap;
+
+  if (data->result != NULL)
+    return;
+
+  data->result = g_typelib_get_dir_entry_by_gtype (typelib, data->fastpass, data->type);
+  if (data->result)
+    data->result_typelib = typelib;
 }
 
 /**
@@ -674,40 +594,48 @@ GIBaseInfo *
 g_irepository_find_by_gtype (GIRepository *repository,
 			     GType         gtype)
 {
-  IfaceData data;
+  FindByGTypeData data;
+  GIBaseInfo *cached;
 
   repository = get_repository (repository);
 
-  data.iface = g_hash_table_lookup (repository->priv->info_by_gtype,
-                                    (gpointer)gtype);
+  cached = g_hash_table_lookup (repository->priv->info_by_gtype,
+				(gpointer)gtype);
 
-  if (data.iface)
-    return g_base_info_ref (data.iface);
+  if (cached != NULL)
+    return g_base_info_ref (cached);
 
-  data.repo = repository;
-  data.name = NULL;
-  data.type_firstpass = TRUE;
-  data.type = g_type_name (gtype);
-  data.index = -1;
-  data.iface = NULL;
+  data.repository = repository;
+  data.fastpass = TRUE;
+  data.type = gtype;
+  data.result_typelib = NULL;
+  data.result = NULL;
 
-  g_hash_table_foreach (repository->priv->typelibs, find_interface, &data);
-  g_hash_table_foreach (repository->priv->lazy_typelibs, find_interface, &data);
+  g_hash_table_foreach (repository->priv->typelibs, find_by_gtype_foreach, &data);
+  if (data.result == NULL)
+    g_hash_table_foreach (repository->priv->lazy_typelibs, find_by_gtype_foreach, &data);
 
   /* We do two passes; see comment in find_interface */
-  if (!data.iface)
+  if (data.result == NULL)
     {
-      data.type_firstpass = FALSE;
-      g_hash_table_foreach (repository->priv->typelibs, find_interface, &data);
-      g_hash_table_foreach (repository->priv->lazy_typelibs, find_interface, &data);
+      data.fastpass = FALSE;
+      g_hash_table_foreach (repository->priv->typelibs, find_by_gtype_foreach, &data);
     }
+  if (data.result == NULL)
+    g_hash_table_foreach (repository->priv->lazy_typelibs, find_by_gtype_foreach, &data);
 
-  if (data.iface)
-    g_hash_table_insert (repository->priv->info_by_gtype,
-                         (gpointer) gtype,
-                         g_base_info_ref (data.iface));
-
-  return data.iface;
+  if (data.result != NULL)
+    {
+      cached = _g_info_new_full (data.result->blob_type,
+				 repository,
+				 NULL, data.result_typelib, data.result->offset);
+
+      g_hash_table_insert (repository->priv->info_by_gtype,
+			   (gpointer) gtype,
+			   g_base_info_ref (cached));
+      return cached;
+    }
+  return NULL;
 }
 
 /**
@@ -728,26 +656,21 @@ g_irepository_find_by_name (GIRepository *repository,
 			    const gchar  *namespace,
 			    const gchar  *name)
 {
-  IfaceData data;
   GITypelib *typelib;
+  DirEntry *entry;
 
   g_return_val_if_fail (namespace != NULL, NULL);
 
   repository = get_repository (repository);
-
-  data.repo = repository;
-  data.name = name;
-  data.type = NULL;
-  data.index = -1;
-  data.iface = NULL;
-
   typelib = get_registered (repository, namespace, NULL);
-
   g_return_val_if_fail (typelib != NULL, NULL);
 
-  find_interface ((void *)namespace, typelib, &data);
-
-  return data.iface;
+  entry = g_typelib_get_dir_entry_by_name (typelib, name);
+  if (entry == NULL)
+    return NULL;
+  return _g_info_new_full (entry->blob_type,
+			   repository,
+			   NULL, typelib, entry->offset);
 }
 
 static void
diff --git a/girepository/gitypelib-internal.h b/girepository/gitypelib-internal.h
index 87a1817..26fd6bf 100644
--- a/girepository/gitypelib-internal.h
+++ b/girepository/gitypelib-internal.h
@@ -1100,6 +1100,13 @@ struct _GITypelib {
 DirEntry *g_typelib_get_dir_entry (GITypelib *typelib,
 				   guint16   index);
 
+DirEntry *g_typelib_get_dir_entry_by_name (GITypelib *typelib,
+					   const char *name);
+
+DirEntry *g_typelib_get_dir_entry_by_gtype (GITypelib *typelib,
+					    gboolean   fastpass,
+					    GType      gtype);
+
 void      g_typelib_check_sanity (void);
 
 #define   g_typelib_get_string(typelib,offset) ((const gchar*)&(typelib->data)[(offset)])
diff --git a/girepository/gitypelib.c b/girepository/gitypelib.c
index cab697a..4f85170 100644
--- a/girepository/gitypelib.c
+++ b/girepository/gitypelib.c
@@ -139,6 +139,80 @@ g_typelib_get_dir_entry (GITypelib *typelib,
   return (DirEntry *)&typelib->data[header->directory + (index - 1) * header->entry_blob_size];
 }
 
+DirEntry *
+g_typelib_get_dir_entry_by_name (GITypelib  *typelib,
+				 const char *name)
+{
+  Header *header = (Header *)typelib->data;
+  guint n_entries = header->n_local_entries;
+  DirEntry *entry;
+  guint i;
+
+  for (i = 1; i <= n_entries; i++)
+    {
+      const char *entry_name;
+
+      entry = g_typelib_get_dir_entry (typelib, i);
+      entry_name = g_typelib_get_string (typelib, entry->name);
+      if (strcmp (name, entry_name) == 0)
+	return entry;
+    }
+  return NULL;
+}
+
+DirEntry *
+g_typelib_get_dir_entry_by_gtype (GITypelib *typelib,
+				  gboolean   fastpass,
+				  GType      gtype)
+{
+  Header *header = (Header *)typelib->data;
+  guint n_entries = header->n_local_entries;
+  const char *gtype_name = g_type_name (gtype);
+  DirEntry *entry;
+  guint i;
+  const char *c_prefix;
+
+  /* Inside each typelib, we include the "C prefix" which acts as
+   * a namespace mechanism.  For GtkTreeView, the C prefix is Gtk.
+   * Given the assumption that GTypes for a library also use the
+   * C prefix, we know we can skip examining a typelib if our
+   * target type does not have this typelib's C prefix.
+   *
+   * However, not every class library necessarily conforms to this,
+   * e.g. Clutter has Cogl inside it.  So, we split this into two
+   * passes.  First we try a lookup, skipping things which don't
+   * have the prefix.  If that fails then we try a global lookup,
+   * ignoring the prefix.
+   *
+   * See http://bugzilla.gnome.org/show_bug.cgi?id=564016
+   */
+  c_prefix = g_typelib_get_string (typelib, header->c_prefix);
+  if (fastpass && c_prefix != NULL)
+    {
+      if (g_ascii_strncasecmp (c_prefix, gtype_name, strlen (c_prefix)) != 0)
+	return NULL;
+    }
+
+  for (i = 1; i <= n_entries; i++)
+    {
+      RegisteredTypeBlob *blob;
+      const char *type;
+
+      entry = g_typelib_get_dir_entry (typelib, i);
+      if (!BLOB_IS_REGISTERED_TYPE (entry))
+	continue;
+
+      blob = (RegisteredTypeBlob *)(&typelib->data[entry->offset]);
+      if (!blob->gtype_name)
+	continue;
+
+      type = g_typelib_get_string (typelib, blob->gtype_name);
+      if (strcmp (type, gtype_name) == 0)
+	return entry;
+    }
+  return NULL;
+}
+
 void
 g_typelib_check_sanity (void)
 {



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