summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Walters <walters@verbum.org>2010-10-25 13:33:01 -0400
committerColin Walters <walters@verbum.org>2010-10-25 14:04:15 -0400
commitc928d61b3430ad58862f0f123f4e9a49c91b37cd (patch)
treef9345465527424505c9108a6441ae99915a6b2ea
parent0f543624900e1b4b290afef6a8f5478ad81cc1f7 (diff)
downloadgobject-introspection-wip/cmph.tar.gz
Add directory index sectionwip/cmph
Use the internal perfect hashing API to add an index to the directory. To support this, add the notion of additional "sections" to the typelib. A section index is inserted between the header and the directory.
-rw-r--r--girepository/girmodule.c74
-rw-r--r--girepository/gitypelib-internal.h29
-rw-r--r--girepository/gitypelib.c52
3 files changed, 144 insertions, 11 deletions
diff --git a/girepository/girmodule.c b/girepository/girmodule.c
index 68ee64b3..d236e81f 100644
--- a/girepository/girmodule.c
+++ b/girepository/girmodule.c
@@ -23,11 +23,13 @@
#include <stdlib.h>
#include "girmodule.h"
+#include "gitypelib-internal.h"
#include "girnode.h"
#define ALIGN_VALUE(this, boundary) \
(( ((unsigned long)(this)) + (((unsigned long)(boundary)) -1)) & (~(((unsigned long)(boundary))-1)))
+#define NUM_SECTIONS 2
GIrModule *
g_ir_module_new (const gchar *name,
@@ -220,6 +222,56 @@ node_cmp_offset_func (gconstpointer a,
return na->offset - nb->offset;
}
+static Section*
+get_section (guint8 *data, SectionType section)
+{
+ Header *header = (Header*)data;
+ Section *start = (Section*)&data[header->sections];
+
+ g_assert (section != GI_SECTION_END);
+
+ return start + (section - 1);
+}
+
+static guint8*
+add_directory_index_section (guint8 *data, GIrModule *module, guint32 *offset2)
+{
+ DirEntry *entry;
+ Header *header = (Header*)data;
+ Section *section;
+ GITypelibHashBuilder *dirindex_builder;
+ guint i, n_interfaces;
+ guint16 required_size;
+ guint32 new_offset;
+
+ dirindex_builder = _gi_typelib_hash_builder_new ();
+
+ section = get_section (data, GI_SECTION_DIRECTORY_INDEX);
+ /* Initialize the offset */
+ section->offset = *offset2;
+
+ n_interfaces = ((Header *)data)->n_local_entries;
+
+ for (i = 0; i < n_interfaces; i++)
+ {
+ entry = (DirEntry *)&data[header->directory + (i * header->entry_blob_size)];
+ const char *str = (const char *) (&data[entry->name]);
+ _gi_typelib_hash_builder_add_string (dirindex_builder, str, i);
+ }
+
+ required_size = _gi_typelib_hash_builder_get_buffer_size (dirindex_builder);
+
+ new_offset = *offset2 + ALIGN_VALUE (required_size, 4);
+
+ data = g_realloc (data, new_offset);
+
+ _gi_typelib_hash_builder_pack (dirindex_builder, ((guint8*)data) + *offset2, required_size);
+
+ *offset2 = new_offset;
+
+ _gi_typelib_hash_builder_destroy (dirindex_builder);
+ return data;
+}
GITypelib *
g_ir_module_build_typelib (GIrModule *module)
@@ -241,6 +293,7 @@ g_ir_module_build_typelib (GIrModule *module)
GList *nodes_with_attributes;
char *dependencies;
guchar *data;
+ Section *section;
header_size = ALIGN_VALUE (sizeof (Header), 4);
n_local_entries = g_list_length (module->entries);
@@ -301,6 +354,8 @@ g_ir_module_build_typelib (GIrModule *module)
if (module->c_prefix != NULL)
size += ALIGN_VALUE (strlen (module->c_prefix) + 1, 4);
+ size += sizeof (Section) * NUM_SECTIONS;
+
g_message ("allocating %d bytes (%d header, %d directory, %d entries)\n",
size, header_size, dir_size, size - header_size - dir_size);
@@ -333,7 +388,6 @@ g_ir_module_build_typelib (GIrModule *module)
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);
header->callback_blob_size = sizeof (CallbackBlob);
@@ -353,6 +407,20 @@ g_ir_module_build_typelib (GIrModule *module)
header->interface_blob_size = sizeof (InterfaceBlob);
header->union_blob_size = sizeof (UnionBlob);
+ /* Right now, just the GI_SECTION_DIRECTORY_INDEX */
+ offset2 = ALIGN_VALUE (header_size, 4);
+ header->sections = offset2;
+
+ section = (Section*) &data[offset2];
+ section->id = GI_SECTION_DIRECTORY_INDEX;
+ section->offset = 0; /* Will fill in later */
+ offset2 += sizeof(Section);
+ section = (Section*) &data[offset2];
+ section->id = GI_SECTION_END;
+ section->offset = 0;
+
+ header->directory = offset2;
+
/* fill in directory and content */
entry = (DirEntry *)&data[header->directory];
@@ -452,6 +520,10 @@ g_ir_module_build_typelib (GIrModule *module)
data = g_realloc (data, offset2);
header = (Header*) data;
+
+ data = add_directory_index_section (data, module, &offset2);
+ header = (Header *)data;
+
length = header->size = offset2;
typelib = g_typelib_new_from_memory (data, length, &error);
if (!typelib)
diff --git a/girepository/gitypelib-internal.h b/girepository/gitypelib-internal.h
index 254b8319..57c8ed76 100644
--- a/girepository/gitypelib-internal.h
+++ b/girepository/gitypelib-internal.h
@@ -52,7 +52,7 @@ G_BEGIN_DECLS
*
* The typelib has the following general format.
*
- * typelib ::= header, directory, blobs, attributes, attributedata
+ * typelib ::= header, section-index, directory, blobs, attributes, attributedata
*
* directory ::= list of entries
*
@@ -233,6 +233,7 @@ typedef enum {
* write parser which continue to work if the format is extended by
* adding new fields before the first flexible array member in
* variable-size blobs.
+ * @sections: Offset of section blob array
*
* The header structure appears exactly once at the beginning of a typelib. It is a
* collection of meta-information, such as the number of entries and dependencies.
@@ -278,10 +279,34 @@ typedef struct {
guint16 interface_blob_size;
guint16 union_blob_size;
+ guint32 sections;
+
/* <private> */
- guint16 padding[7];
+ guint16 padding[5];
} Header;
+typedef enum {
+ GI_SECTION_END = 0,
+ GI_SECTION_DIRECTORY_INDEX = 1
+} SectionType;
+
+/**
+ * Section:
+ * @id: A #SectionType
+ * @offset: Integer offset for this section
+ *
+ * A section is a blob of data that's (at least theoretically) optional,
+ * and may or may not be present in the typelib. Presently, just used
+ * for the directory index. This allows a form of dynamic extensibility
+ * with different tradeoffs from the format minor version.
+ *
+ */
+typedef struct {
+ guint32 id;
+ guint32 offset;
+} Section;
+
+
/**
* DirEntry:
* @blob_type: A #GTypelibBlobType
diff --git a/girepository/gitypelib.c b/girepository/gitypelib.c
index 4f851702..d04191f4 100644
--- a/girepository/gitypelib.c
+++ b/girepository/gitypelib.c
@@ -139,25 +139,61 @@ g_typelib_get_dir_entry (GITypelib *typelib,
return (DirEntry *)&typelib->data[header->directory + (index - 1) * header->entry_blob_size];
}
+static Section *
+get_section_by_id (GITypelib *typelib,
+ SectionType section_type)
+{
+ Header *header = (Header *)typelib->data;
+ Section *section;
+
+ if (header->sections == 0)
+ return NULL;
+
+ for (section = (Section*)&typelib->data[header->sections];
+ section->id != GI_SECTION_END;
+ section++)
+ {
+ if (section->id == section_type)
+ return section;
+ }
+ return NULL;
+}
+
DirEntry *
-g_typelib_get_dir_entry_by_name (GITypelib *typelib,
+g_typelib_get_dir_entry_by_name (GITypelib *typelib,
const char *name)
{
- Header *header = (Header *)typelib->data;
- guint n_entries = header->n_local_entries;
+ Section *dirindex;
+ gint i;
+ const char *entry_name;
DirEntry *entry;
- guint i;
- for (i = 1; i <= n_entries; i++)
+ dirindex = get_section_by_id (typelib, GI_SECTION_DIRECTORY_INDEX);
+
+ if (dirindex == NULL)
+ {
+ gint n_entries = ((Header *)typelib->data)->n_local_entries;
+ for (i = 1; i <= n_entries; i++)
+ {
+ 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;
+ }
+ else
{
- const char *entry_name;
+ guint8 *hash = (guint8*) &typelib->data[dirindex->offset];
+ guint16 index;
- entry = g_typelib_get_dir_entry (typelib, i);
+ index = _gi_typelib_hash_search (hash, name);
+ entry = g_typelib_get_dir_entry (typelib, index + 1);
entry_name = g_typelib_get_string (typelib, entry->name);
if (strcmp (name, entry_name) == 0)
return entry;
+ return NULL;
}
- return NULL;
}
DirEntry *