diff options
author | Garrett Regier <garrett.regier@riftio.com> | 2015-06-03 04:59:11 -0700 |
---|---|---|
committer | Garrett Regier <garrett.regier@riftio.com> | 2015-06-21 13:01:25 -0700 |
commit | cf6ea68018b94529aeb02aaa8b430c8d061e55c1 (patch) | |
tree | b0850de8d9d62557d1613e1cac46c828bb6e6a3d | |
parent | ec91f9d11b40de198b2faf8a80b49dbd71107750 (diff) | |
download | gobject-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-- | .gitignore | 1 | ||||
-rw-r--r-- | girepository/gistructinfo.c | 43 | ||||
-rw-r--r-- | girepository/gistructinfo.h | 4 | ||||
-rw-r--r-- | tests/repository/Makefile.am | 8 | ||||
-rw-r--r-- | tests/repository/giteststructinfo.c | 58 |
5 files changed, 112 insertions, 2 deletions
@@ -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 (); +} |