mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-01-12 15:36:17 +01:00
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.
This commit is contained in:
parent
8d9a983848
commit
54a1a7be49
213
girepository.c
213
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);
|
||||
}
|
||||
|
||||
return data.iface;
|
||||
typedef struct {
|
||||
GIRepository *repository;
|
||||
GType type;
|
||||
|
||||
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));
|
||||
if (data.result != NULL)
|
||||
{
|
||||
cached = _g_info_new_full (data.result->blob_type,
|
||||
repository,
|
||||
NULL, data.result_typelib, data.result->offset);
|
||||
|
||||
return data.iface;
|
||||
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
|
||||
|
@ -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)])
|
||||
|
74
gitypelib.c
74
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)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user