diff options
author | Colin Walters <walters@verbum.org> | 2010-10-18 12:04:08 -0400 |
---|---|---|
committer | Colin Walters <walters@verbum.org> | 2010-10-18 12:04:08 -0400 |
commit | f97cc8687469f25752f7927545ad4daecef8ab44 (patch) | |
tree | c1c792e80f9c24ad5990e2dd7fd7acc4a2d31dcb /girepository | |
parent | 80a42c6eb38b4b8fd68b5d4e8780a834ad8bdda5 (diff) | |
download | gobject-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.
Diffstat (limited to 'girepository')
-rw-r--r-- | girepository/girepository.c | 215 | ||||
-rw-r--r-- | girepository/gitypelib-internal.h | 7 | ||||
-rw-r--r-- | girepository/gitypelib.c | 74 |
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) { |