summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGarrett Regier <garrett.regier@riftio.com>2015-06-03 04:59:11 -0700
committerGarrett Regier <garrett.regier@riftio.com>2015-06-21 13:01:25 -0700
commitcf6ea68018b94529aeb02aaa8b430c8d061e55c1 (patch)
treeb0850de8d9d62557d1613e1cac46c828bb6e6a3d
parentec91f9d11b40de198b2faf8a80b49dbd71107750 (diff)
downloadgobject-introspection-cf6ea68018b94529aeb02aaa8b430c8d061e55c1.tar.gz
girepository: Add g_struct_info_find_field()
Add find_field utility function for finding a field info by name. Beyond convenience, this should be faster than manually using the get_n_fields and get_field functions because get_field does an additional iteration for each field to calculate offsets O(n^2). Thus find_field combines the offset and comparison computations into a single loop O(n). Based on a patch by Simon Feltman.
-rw-r--r--.gitignore1
-rw-r--r--girepository/gistructinfo.c43
-rw-r--r--girepository/gistructinfo.h4
-rw-r--r--tests/repository/Makefile.am8
-rw-r--r--tests/repository/giteststructinfo.c58
5 files changed, 112 insertions, 2 deletions
diff --git a/.gitignore b/.gitignore
index 7551c4a2..beadb6a8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -71,6 +71,7 @@ tests/everything.c
tests/everything.h
tests/offsets/gitestoffsets.c
tests/repository/gitestrepo
+tests/repository/giteststructinfo
tests/repository/gitestthrows
tests/repository/gitypelibtest
tests/scanner/Bar-1.0.gir
diff --git a/girepository/gistructinfo.c b/girepository/gistructinfo.c
index 0fbaec84..bd777463 100644
--- a/girepository/gistructinfo.c
+++ b/girepository/gistructinfo.c
@@ -22,6 +22,8 @@
#include "config.h"
+#include <string.h>
+
#include <glib.h>
#include <girepository.h>
@@ -115,6 +117,47 @@ g_struct_info_get_field (GIStructInfo *info,
}
/**
+ * g_struct_info_find_field:
+ * @info: a #GIStructInfo
+ * @name: a field name
+ *
+ * Obtain the type information for field named @name.
+ *
+ * Returns: (transfer full): the #GIFieldInfo or %NULL if not found,
+ * free it with g_base_info_unref() when done.
+ */
+GIFieldInfo *
+g_struct_info_find_field (GIStructInfo *info,
+ const gchar *name)
+{
+ GIRealInfo *rinfo = (GIRealInfo *)info;
+ StructBlob *blob = (StructBlob *)&rinfo->typelib->data[rinfo->offset];
+ Header *header = (Header *)rinfo->typelib->data;
+ guint32 offset = rinfo->offset + header->struct_blob_size;
+ gint i;
+
+ for (i = 0; i < blob->n_fields; i++)
+ {
+ FieldBlob *field_blob = (FieldBlob *)&rinfo->typelib->data[offset];
+ const gchar *fname = (const gchar *)&rinfo->typelib->data[field_blob->name];
+
+ if (strcmp (name, fname) == 0)
+ {
+ return (GIFieldInfo *) g_info_new (GI_INFO_TYPE_FIELD,
+ (GIBaseInfo* )info,
+ rinfo->typelib,
+ offset);
+ }
+
+ offset += header->field_blob_size;
+ if (field_blob->has_embedded_type)
+ offset += header->callback_blob_size;
+ }
+
+ return NULL;
+}
+
+/**
* g_struct_info_get_n_methods:
* @info: a #GIStructInfo
*
diff --git a/girepository/gistructinfo.h b/girepository/gistructinfo.h
index 2651311d..4a60d5bb 100644
--- a/girepository/gistructinfo.h
+++ b/girepository/gistructinfo.h
@@ -49,6 +49,10 @@ GIFieldInfo * g_struct_info_get_field (GIStructInfo *info,
gint n);
GI_AVAILABLE_IN_ALL
+GIFieldInfo * g_struct_info_find_field (GIStructInfo *info,
+ const gchar *name);
+
+GI_AVAILABLE_IN_ALL
gint g_struct_info_get_n_methods (GIStructInfo *info);
GI_AVAILABLE_IN_ALL
diff --git a/tests/repository/Makefile.am b/tests/repository/Makefile.am
index c79ba81f..da0337b3 100644
--- a/tests/repository/Makefile.am
+++ b/tests/repository/Makefile.am
@@ -2,13 +2,17 @@ AM_CFLAGS = $(GOBJECT_CFLAGS)
AM_LDFLAGS = -module -avoid-version
LIBS = $(GOBJECT_LIBS)
-EXTRA_PROGRAMS = gitestrepo gitestthrows gitypelibtest
+EXTRA_PROGRAMS = gitestrepo giteststructinfo gitestthrows gitypelibtest
CLEANFILES = $(EXTRA_PROGRAMS)
gitestrepo_SOURCES = $(srcdir)/gitestrepo.c
gitestrepo_CPPFLAGS = $(GIREPO_CFLAGS) -I$(top_srcdir)/girepository
gitestrepo_LDADD = $(top_builddir)/libgirepository-1.0.la $(GIREPO_LIBS)
+giteststructinfo_SOURCES = $(srcdir)/giteststructinfo.c
+giteststructinfo_CPPFLAGS = $(GIREPO_CFLAGS) -I$(top_srcdir)/girepository
+giteststructinfo_LDADD = $(top_builddir)/libgirepository-1.0.la $(GIREPO_LIBS)
+
gitestthrows_SOURCES = $(srcdir)/gitestthrows.c
gitestthrows_CPPFLAGS = $(GIREPO_CFLAGS) -I$(top_srcdir)/girepository
gitestthrows_LDADD = $(top_builddir)/libgirepository-1.0.la $(GIREPO_LIBS)
@@ -17,7 +21,7 @@ gitypelibtest_SOURCES = $(srcdir)/gitypelibtest.c
gitypelibtest_CPPFLAGS = $(GIREPO_CFLAGS) -I$(top_srcdir)/girepository
gitypelibtest_LDADD = $(top_builddir)/libgirepository-1.0.la $(GIREPO_LIBS)
-TESTS = gitestrepo gitestthrows gitypelibtest
+TESTS = gitestrepo giteststructinfo gitestthrows gitypelibtest
TESTS_ENVIRONMENT=env GI_TYPELIB_PATH="$(top_builddir):$(top_builddir)/gir:$(top_builddir)/tests:$(top_builddir)/tests/scanner" \
XDG_DATA_DIRS="$(top_srcdir)/gir:$(XDG_DATA_DIRS)" \
PATH="$(top_builddir)/tests/scanner/.libs:$(PATH)" \
diff --git a/tests/repository/giteststructinfo.c b/tests/repository/giteststructinfo.c
new file mode 100644
index 00000000..ed1563b2
--- /dev/null
+++ b/tests/repository/giteststructinfo.c
@@ -0,0 +1,58 @@
+
+#include "girepository.h"
+
+
+static void
+test_field_iterators (void)
+{
+ GIRepository *repo;
+ GITypelib *ret;
+ GIStructInfo *class_info;
+ GIFieldInfo *field_info;
+ GError *error = NULL;
+ gint i;
+
+ repo = g_irepository_get_default ();
+
+ ret = g_irepository_require (repo, "GIMarshallingTests", NULL, 0, &error);
+ g_assert_nonnull (ret);
+ g_assert_no_error (error);
+
+ class_info = g_irepository_find_by_name (repo, "GIMarshallingTests", "ObjectClass");
+ g_assert_nonnull (class_info);
+ g_assert (g_base_info_get_type (class_info) == GI_INFO_TYPE_STRUCT);
+
+ for (i = 0; i < g_struct_info_get_n_fields (class_info); i++)
+ {
+ const char *field_name;
+ GIFieldInfo *found;
+
+ field_info = g_struct_info_get_field (class_info, i);
+ g_assert_nonnull (field_info);
+
+ field_name = g_base_info_get_name (field_info);
+ g_assert_nonnull (field_name);
+
+ found = g_struct_info_find_field (class_info, field_name);
+ g_assert_nonnull (found);
+ g_assert_cmpstr (g_base_info_get_name (found), ==, field_name);
+
+ g_base_info_unref (found);
+ g_base_info_unref (field_info);
+ }
+
+ field_info = g_struct_info_find_field (class_info, "not_a_real_field_name");
+ g_assert_null (field_info);
+
+ g_base_info_unref (class_info);
+}
+
+int
+main(int argc, char **argv)
+{
+ g_test_init (&argc, &argv, NULL);
+
+ g_test_add_func ("/girepository/structinfo/field-iterators", test_field_iterators);
+
+ return g_test_run ();
+}