[gobject-introspection] girepository: Add g_struct_info_find_field()



commit cf6ea68018b94529aeb02aaa8b430c8d061e55c1
Author: Garrett Regier <garrett regier riftio com>
Date:   Wed Jun 3 04:59:11 2015 -0700

    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.

 .gitignore                          |    1 +
 girepository/gistructinfo.c         |   43 ++++++++++++++++++++++++++
 girepository/gistructinfo.h         |    4 ++
 tests/repository/Makefile.am        |    8 +++-
 tests/repository/giteststructinfo.c |   58 +++++++++++++++++++++++++++++++++++
 5 files changed, 112 insertions(+), 2 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index 7551c4a..beadb6a 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 0fbaec8..bd77746 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 2651311..4a60d5b 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 c79ba81..da0337b 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 0000000..ed1563b
--- /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 ();
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]