Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorColin Walters <walters@verbum.org>2009-02-12 23:42:47 (GMT)
committer Colin Walters <walters@verbum.org>2009-03-17 20:29:08 (GMT)
commit888566c41b4f0d73ec80307d0418ab1d44c7210c (patch)
treed144a6bcf51b7e92868de16797e164b85a5ccca1
parent5dfa997724551ed163fefc11782b7163db3be378 (diff)
Bug 564016 - Include c:prefix in typelib, use it to optimize find_by_gtype
Parse the c:prefix from the .gir, include it in the header. Armed with this information, we can now optimize lookups of GTypes because we have the requirement that GTypes must start with the c:prefix. We do fall back though if a lookup fails.
-rw-r--r--girepository/girepository.c76
-rw-r--r--girepository/girepository.h2
-rw-r--r--girepository/girmodule.c19
-rw-r--r--girepository/girmodule.h4
-rw-r--r--girepository/girparser.c6
-rw-r--r--girepository/gtypelib.c2
-rw-r--r--girepository/gtypelib.h1
-rw-r--r--tests/scanner/BarApp-1.0-expected.tgir2
-rw-r--r--tests/scanner/GtkFrob-1.0-expected.tgir2
-rw-r--r--tests/scanner/annotation-1.0-expected.tgir2
-rw-r--r--tests/scanner/drawable-1.0-expected.tgir2
-rw-r--r--tests/scanner/foo-1.0-expected.tgir2
-rw-r--r--tests/scanner/utility-1.0-expected.tgir2
-rw-r--r--tools/generate.c4
14 files changed, 108 insertions, 18 deletions
diff --git a/girepository/girepository.c b/girepository/girepository.c
index 06ea13c..a2a8504 100644
--- a/girepository/girepository.c
+++ b/girepository/girepository.c
@@ -517,6 +517,7 @@ typedef struct
GIRepository *repo;
gint index;
const gchar *name;
+ gboolean type_firstpass;
const gchar *type;
GIBaseInfo *iface;
} IfaceData;
@@ -528,6 +529,7 @@ find_interface (gpointer key,
{
gint i;
GTypelib *typelib = (GTypelib *)value;
+ Header *header = (Header *) typelib->data;
IfaceData *iface_data = (IfaceData *)data;
gint index;
gint n_entries;
@@ -553,6 +555,28 @@ find_interface (gpointer key,
}
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;
@@ -638,8 +662,8 @@ g_irepository_get_info (GIRepository *repository,
* in order to locate the metadata, the namespace corresponding to
* the type must first have been loaded. There is currently no
* mechanism for determining the namespace which corresponds to an
- * arbitrary GType - thus, this function will function most reliably
- * when you have expect the GType to be from a known namespace.
+ * arbitrary GType - thus, this function will operate most reliably
+ * when you know the GType to originate from be from a loaded namespace.
*
* Returns: #GIBaseInfo representing metadata about @type, or %NULL
*/
@@ -659,6 +683,7 @@ g_irepository_find_by_gtype (GIRepository *repository,
data.repo = repository;
data.name = NULL;
+ data.type_firstpass = TRUE;
data.type = g_type_name (gtype);
data.index = -1;
data.iface = NULL;
@@ -666,12 +691,19 @@ g_irepository_find_by_gtype (GIRepository *repository,
g_hash_table_foreach (repository->priv->typelibs, find_interface, &data);
g_hash_table_foreach (repository->priv->lazy_typelibs, find_interface, &data);
+ /* We do two passes; see comment in find_interface */
+ if (!data.iface)
+ {
+ 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);
+ }
+
if (data.iface)
g_hash_table_insert (repository->priv->info_by_gtype,
(gpointer) gtype,
g_base_info_ref (data.iface));
-
return data.iface;
}
@@ -824,7 +856,43 @@ g_irepository_get_shared_library (GIRepository *repository,
}
/**
- * g_irepository_get_typelib_path:
+ * g_irepository_get_c_prefix
+ * @repository: A #GIRepository, may be %NULL for the default
+ * @namespace: Namespace to inspect
+ *
+ * This function returns the "C prefix", or the C level namespace
+ * associated with the given introspection namespace. Each C symbol
+ * starts with this prefix, as well each #GType in the library.
+ *
+ * Note: The namespace must have already been loaded using a function
+ * such as #g_irepository_require before calling this function.
+ *
+ * Returns: C namespace prefix, or %NULL if none associated
+ */
+const gchar *
+g_irepository_get_c_prefix (GIRepository *repository,
+ const gchar *namespace_)
+{
+ GTypelib *typelib;
+ Header *header;
+
+ g_return_val_if_fail (namespace_ != NULL, NULL);
+
+ repository = get_repository (repository);
+
+ typelib = get_registered (repository, namespace_, NULL);
+
+ g_return_val_if_fail (typelib != NULL, NULL);
+
+ header = (Header *) typelib->data;
+ if (header->shared_library)
+ return g_typelib_get_string (typelib, header->c_prefix);
+ else
+ return NULL;
+}
+
+/**
+ * g_irepository_get_typelib_path
* @repository: Repository, may be %NULL for the default
* @namespace_: GI namespace to use, e.g. "Gtk"
*
diff --git a/girepository/girepository.h b/girepository/girepository.h
index 1058570..efc6aca 100644
--- a/girepository/girepository.h
+++ b/girepository/girepository.h
@@ -108,6 +108,8 @@ const gchar * g_irepository_get_typelib_path (GIRepository *repository,
const gchar *namespace_);
const gchar * g_irepository_get_shared_library (GIRepository *repository,
const gchar *namespace_);
+const gchar * g_irepository_get_c_prefix (GIRepository *repository,
+ const gchar *namespace_);
const gchar * g_irepository_get_version (GIRepository *repository,
const gchar *namespace_);
diff --git a/girepository/girmodule.c b/girepository/girmodule.c
index 96ee9ce..bf1e856 100644
--- a/girepository/girmodule.c
+++ b/girepository/girmodule.c
@@ -31,7 +31,8 @@
GIrModule *
g_ir_module_new (const gchar *name,
const gchar *version,
- const gchar *shared_library)
+ const gchar *shared_library,
+ const gchar *c_prefix)
{
GIrModule *module;
@@ -43,6 +44,7 @@ g_ir_module_new (const gchar *name,
module->shared_library = g_strdup (shared_library);
else
module->shared_library = NULL;
+ module->c_prefix = g_strdup (c_prefix);
module->dependencies = NULL;
module->entries = NULL;
@@ -229,11 +231,13 @@ g_ir_module_build_typelib (GIrModule *module,
}
/* Adjust size for strings allocated in header below specially */
- size += strlen (module->name);
+ size += ALIGN_VALUE (strlen (module->name) + 1, 4);
if (module->shared_library)
- size += strlen (module->shared_library);
+ size += ALIGN_VALUE (strlen (module->shared_library) + 1, 4);
if (dependencies != NULL)
- size += strlen (dependencies);
+ size += ALIGN_VALUE (strlen (dependencies) + 1, 4);
+ if (module->c_prefix != NULL)
+ size += ALIGN_VALUE (strlen (module->c_prefix) + 1, 4);
g_message ("allocating %d bytes (%d header, %d directory, %d entries)\n",
size, header_size, dir_size, size - header_size - dir_size);
@@ -250,6 +254,9 @@ g_ir_module_build_typelib (GIrModule *module,
header->n_local_entries = n_local_entries;
header->n_attributes = 0;
header->attributes = 0; /* filled in later */
+ /* NOTE: When writing strings to the typelib here, you should also update
+ * the size calculations above.
+ */
if (dependencies != NULL)
header->dependencies = write_string (dependencies, strings, data, &header_size);
else
@@ -260,6 +267,10 @@ g_ir_module_build_typelib (GIrModule *module,
header->shared_library = (module->shared_library?
write_string (module->shared_library, strings, data, &header_size)
: 0);
+ if (module->c_prefix != NULL)
+ header->c_prefix = write_string (module->c_prefix, strings, data, &header_size);
+ else
+ header->c_prefix = 0;
header->directory = ALIGN_VALUE (header_size, 4);
header->entry_blob_size = sizeof (DirEntry);
header->function_blob_size = sizeof (FunctionBlob);
diff --git a/girepository/girmodule.h b/girepository/girmodule.h
index c658e17..5a558c3 100644
--- a/girepository/girmodule.h
+++ b/girepository/girmodule.h
@@ -34,6 +34,7 @@ struct _GIrModule
gchar *name;
gchar *version;
gchar *shared_library;
+ gchar *c_prefix;
GList *dependencies;
GList *entries;
@@ -50,7 +51,8 @@ struct _GIrModule
GIrModule *g_ir_module_new (const gchar *name,
const gchar *nsversion,
- const gchar *module_filename);
+ const gchar *module_filename,
+ const gchar *c_prefix);
void g_ir_module_free (GIrModule *module);
void g_ir_module_add_include_module (GIrModule *module,
diff --git a/girepository/girparser.c b/girepository/girparser.c
index 9afd858..7727d23 100644
--- a/girepository/girparser.c
+++ b/girepository/girparser.c
@@ -88,6 +88,7 @@ struct _ParseContext
GHashTable *disguised_structures;
const char *namespace;
+ const char *c_prefix;
GIrModule *current_module;
GSList *node_stack;
GIrNode *current_typed;
@@ -2547,7 +2548,7 @@ start_element_handler (GMarkupParseContext *context,
case 'n':
if (strcmp (element_name, "namespace") == 0 && ctx->state == STATE_REPOSITORY)
{
- const gchar *name, *version, *shared_library;
+ const gchar *name, *version, *shared_library, *cprefix;
if (ctx->current_module != NULL)
{
@@ -2561,6 +2562,7 @@ start_element_handler (GMarkupParseContext *context,
name = find_attribute ("name", attribute_names, attribute_values);
version = find_attribute ("version", attribute_names, attribute_values);
shared_library = find_attribute ("shared-library", attribute_names, attribute_values);
+ cprefix = find_attribute ("c:prefix", attribute_names, attribute_values);
if (name == NULL)
MISSING_ATTRIBUTE (context, error, element_name, "name");
@@ -2577,7 +2579,7 @@ start_element_handler (GMarkupParseContext *context,
"<namespace/> name element '%s' doesn't match file name '%s'",
name, ctx->namespace);
- ctx->current_module = g_ir_module_new (name, version, shared_library);
+ ctx->current_module = g_ir_module_new (name, version, shared_library, cprefix);
ctx->current_module->aliases = ctx->aliases;
ctx->aliases = NULL;
diff --git a/girepository/gtypelib.c b/girepository/gtypelib.c
index a578c67..64138aa 100644
--- a/girepository/gtypelib.c
+++ b/girepository/gtypelib.c
@@ -161,7 +161,7 @@ g_typelib_check_sanity (void)
* Everything else in the code however should be using sizeof().
*/
- CHECK_SIZE (Header, 108);
+ CHECK_SIZE (Header, 112);
CHECK_SIZE (DirEntry, 12);
CHECK_SIZE (SimpleTypeBlob, 4);
CHECK_SIZE (ArgBlob, 16);
diff --git a/girepository/gtypelib.h b/girepository/gtypelib.h
index f6ad8c9..d4afa89 100644
--- a/girepository/gtypelib.h
+++ b/girepository/gtypelib.h
@@ -247,6 +247,7 @@ typedef struct {
guint32 namespace;
guint32 nsversion;
guint32 shared_library;
+ guint32 c_prefix;
guint16 entry_blob_size;
guint16 function_blob_size;
diff --git a/tests/scanner/BarApp-1.0-expected.tgir b/tests/scanner/BarApp-1.0-expected.tgir
index 20173cb..45ceae0 100644
--- a/tests/scanner/BarApp-1.0-expected.tgir
+++ b/tests/scanner/BarApp-1.0-expected.tgir
@@ -5,7 +5,7 @@
xmlns:glib="http://www.gtk.org/introspection/glib/1.0">
<include name="GObject" version="2.0"/>
<include name="GLib" version="2.0"/>
- <namespace name="BarApp" version="1.0" shared-library="">
+ <namespace name="BarApp" version="1.0" shared-library="" c:prefix="Bar">
<class name="Baz" parent="GObject.Object" glib:type-struct="BazClass" glib:type-name="BarBaz" glib:get-type="bar_baz_get_type">
<field name="parent_instance">
<type name="GObject.Object"/>
diff --git a/tests/scanner/GtkFrob-1.0-expected.tgir b/tests/scanner/GtkFrob-1.0-expected.tgir
index 85c527d..0d101be 100644
--- a/tests/scanner/GtkFrob-1.0-expected.tgir
+++ b/tests/scanner/GtkFrob-1.0-expected.tgir
@@ -5,7 +5,7 @@
xmlns:glib="http://www.gtk.org/introspection/glib/1.0">
<include name="GObject" version="2.0"/>
<include name="GLib" version="2.0"/>
- <namespace name="GtkFrob" version="1.0" shared-library="gtkfrob">
+ <namespace name="GtkFrob" version="1.0" shared-library="gtkfrob" c:prefix="Gtk">
<function name="language_manager_get_default" c:identifier="gtk_frob_language_manager_get_default">
<return-value transfer-ownership="none">
<type name="none"/>
diff --git a/tests/scanner/annotation-1.0-expected.tgir b/tests/scanner/annotation-1.0-expected.tgir
index 99c3d26..3629d5f 100644
--- a/tests/scanner/annotation-1.0-expected.tgir
+++ b/tests/scanner/annotation-1.0-expected.tgir
@@ -6,7 +6,7 @@
<include name="utility" version="1.0"/>
<include name="GObject" version="2.0"/>
<include name="GLib" version="2.0"/>
- <namespace name="annotation" version="1.0" shared-library="annotation">
+ <namespace name="annotation" version="1.0" shared-library="annotation" c:prefix="annotation">
<callback name="Callback">
<return-value transfer-ownership="none">
<type name="int"/>
diff --git a/tests/scanner/drawable-1.0-expected.tgir b/tests/scanner/drawable-1.0-expected.tgir
index 2c93961..618cf3a 100644
--- a/tests/scanner/drawable-1.0-expected.tgir
+++ b/tests/scanner/drawable-1.0-expected.tgir
@@ -6,7 +6,7 @@
<include name="utility" version="1.0"/>
<include name="GObject" version="2.0"/>
<include name="GLib" version="2.0"/>
- <namespace name="drawable" version="1.0" shared-library="drawable">
+ <namespace name="drawable" version="1.0" shared-library="drawable" c:prefix="drawable">
<class name="TestDrawable" parent="GObject.Object" glib:type-struct="TestDrawableClass" abstract="1" glib:type-name="TestDrawable" glib:get-type="test_drawable_get_type">
<field name="parent_instance">
<type name="GObject.Object"/>
diff --git a/tests/scanner/foo-1.0-expected.tgir b/tests/scanner/foo-1.0-expected.tgir
index bd94ed3..9a43ecc 100644
--- a/tests/scanner/foo-1.0-expected.tgir
+++ b/tests/scanner/foo-1.0-expected.tgir
@@ -6,7 +6,7 @@
<include name="utility" version="1.0"/>
<include name="GObject" version="2.0"/>
<include name="GLib" version="2.0"/>
- <namespace name="foo" version="1.0" shared-library="foo">
+ <namespace name="foo" version="1.0" shared-library="foo" c:prefix="foo">
<enumeration name="ASingle">
<member name="some_single_enum" value="0"/>
</enumeration>
diff --git a/tests/scanner/utility-1.0-expected.tgir b/tests/scanner/utility-1.0-expected.tgir
index dfd2aa8..2a30f85 100644
--- a/tests/scanner/utility-1.0-expected.tgir
+++ b/tests/scanner/utility-1.0-expected.tgir
@@ -5,7 +5,7 @@
xmlns:glib="http://www.gtk.org/introspection/glib/1.0">
<include name="GObject" version="2.0"/>
<include name="GLib" version="2.0"/>
- <namespace name="utility" version="1.0" shared-library="utility">
+ <namespace name="utility" version="1.0" shared-library="utility" c:prefix="utility">
<union name="Byte">
<field name="value" writable="1">
<type name="uint8"/>
diff --git a/tools/generate.c b/tools/generate.c
index 48d7dfb..f876721 100644
--- a/tools/generate.c
+++ b/tools/generate.c
@@ -1282,16 +1282,20 @@ write_repository (const char *namespace,
if (TRUE)
{
const gchar *shared_library;
+ const gchar *c_prefix;
const char *ns = namespace;
const char *version;
version = g_irepository_get_version (repository, ns);
shared_library = g_irepository_get_shared_library (repository, ns);
+ c_prefix = g_irepository_get_c_prefix (repository, ns);
xml_start_element (xml, "namespace");
xml_printf (xml, " name=\"%s\" version=\"%s\"", ns, version);
if (shared_library)
xml_printf (xml, " shared-library=\"%s\"", shared_library);
+ if (c_prefix)
+ xml_printf (xml, " c:prefix=\"%s\"", c_prefix);
for (j = 0; j < g_irepository_get_n_infos (repository, ns); j++)
{