summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Walters <walters@verbum.org>2010-10-18 12:04:08 -0400
committerColin Walters <walters@verbum.org>2010-10-18 12:04:08 -0400
commitf97cc8687469f25752f7927545ad4daecef8ab44 (patch)
treec1c792e80f9c24ad5990e2dd7fd7acc4a2d31dcb
parent80a42c6eb38b4b8fd68b5d4e8780a834ad8bdda5 (diff)
downloadgobject-introspection-f97cc8687469f25752f7927545ad4daecef8ab44.tar.gz
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.
-rw-r--r--girepository/girepository.c215
-rw-r--r--girepository/gitypelib-internal.h7
-rw-r--r--girepository/gitypelib.c74
3 files changed, 150 insertions, 146 deletions
diff --git a/girepository/girepository.c b/girepository/girepository.c
index 712118dc..18ecafbe 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 87a18170..26fd6bfb 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 cab697a2..4f851702 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)
{