[json-glib] object: Add JsonObjectIter to ease iteration over JsonObject members



commit d231976e240f2244c60df26a1a6600ecb325506a
Author: Philip Withnall <philip withnall collabora co uk>
Date:   Thu Sep 24 11:06:34 2015 +0100

    object: Add JsonObjectIter to ease iteration over JsonObject members
    
    This is a stack-allocated iterator object similar to GHashTableIter
    which allows allocation-free iteration over the members in a JsonObject.
    
    It differs from json_object_foreach_member() in the order in which it
    iterates — for JsonObjectIter the order is undefined.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=755509

 doc/reference/json-glib-sections.txt |    3 +
 json-glib/json-object.c              |   71 ++++++++++++++++++++++++++++++++++
 json-glib/json-types-private.h       |    9 ++++
 json-glib/json-types.h               |   26 ++++++++++++
 json-glib/tests/object.c             |   28 +++++++++++++
 5 files changed, 137 insertions(+), 0 deletions(-)
---
diff --git a/doc/reference/json-glib-sections.txt b/doc/reference/json-glib-sections.txt
index ab5e579..015a442 100644
--- a/doc/reference/json-glib-sections.txt
+++ b/doc/reference/json-glib-sections.txt
@@ -18,6 +18,9 @@ json_object_get_size
 json_object_remove_member
 JsonObjectForeach
 json_object_foreach_member
+JsonObjectIter
+json_object_iter_init
+json_object_iter_next
 
 <SUBSECTION>
 json_object_set_array_member
diff --git a/json-glib/json-object.c b/json-glib/json-object.c
index c71d8f9..cc32148 100644
--- a/json-glib/json-object.c
+++ b/json-glib/json-object.c
@@ -851,3 +851,74 @@ json_object_foreach_member (JsonObject        *object,
       func (object, member_name, member_node, data);
     }
 }
+
+/**
+ * json_object_iter_init:
+ * @iter: an uninitialised #JsonObjectIter
+ * @object: the #JsonObject to iterate over
+ *
+ * Initialise the @iter and associate it with @object.
+ *
+ * |[<!-- language="C" -->
+ * JsonObjectIter iter;
+ * const gchar *member_name;
+ * JsonNode *member_node;
+ *
+ * json_object_iter_init (&iter, some_object);
+ * while (json_object_iter_next (&iter, &member_name, &member_node))
+ *   {
+ *     // Do something with @member_name and @member_node.
+ *   }
+ * ]|
+ *
+ * Since: UNRELEASED
+ */
+void
+json_object_iter_init (JsonObjectIter  *iter,
+                       JsonObject      *object)
+{
+  JsonObjectIterReal *iter_real = (JsonObjectIterReal *) iter;;
+
+  g_return_if_fail (iter != NULL);
+  g_return_if_fail (object != NULL);
+  g_return_if_fail (object->ref_count > 0);
+
+  iter_real->object = object;
+  g_hash_table_iter_init (&iter_real->members_iter, object->members);
+}
+
+/**
+ * json_object_iter_next:
+ * @iter: a #JsonObjectIter
+ * @member_name: (out callee-allocates) (transfer none) (optional): return
+ *    location for the member name, or %NULL to ignore
+ * @member_node: (out callee-allocates) (transfer none) (optional): return
+ *    location for the member value, or %NULL to ignore
+ *
+ * Advance @iter and retrieve the next member in the object. If the end of the
+ * object is reached, %FALSE is returned and @member_name and @member_node are
+ * set to invalid values. After that point, the @iter is invalid.
+ *
+ * The order in which members are returned by the iterator is undefined. The
+ * iterator is invalidated if its #JsonObject is modified during iteration.
+ *
+ * Returns: %TRUE if @member_name and @member_node are valid; %FALSE if the end
+ *    of the object has been reached
+ *
+ * Since: UNRELEASED
+ */
+gboolean
+json_object_iter_next (JsonObjectIter  *iter,
+                       const gchar    **member_name,
+                       JsonNode       **member_node)
+{
+  JsonObjectIterReal *iter_real = (JsonObjectIterReal *) iter;
+
+  g_return_val_if_fail (iter != NULL, FALSE);
+  g_return_val_if_fail (iter_real->object != NULL, FALSE);
+  g_return_val_if_fail (iter_real->object->ref_count > 0, FALSE);
+
+  return g_hash_table_iter_next (&iter_real->members_iter,
+                                 (gpointer *) member_name,
+                                 (gpointer *) member_node);
+}
diff --git a/json-glib/json-types-private.h b/json-glib/json-types-private.h
index efce6a9..f9ac064 100644
--- a/json-glib/json-types-private.h
+++ b/json-glib/json-types-private.h
@@ -95,6 +95,15 @@ struct _JsonObject
   volatile gint ref_count;
 };
 
+typedef struct
+{
+  JsonObject *object;  /* unowned */
+  GHashTableIter members_iter;  /* iterator over @members */
+  gpointer padding[2];  /* for future expansion */
+} JsonObjectIterReal;
+
+G_STATIC_ASSERT (sizeof (JsonObjectIterReal) == sizeof (JsonObjectIter));
+
 G_GNUC_INTERNAL
 const gchar *   json_node_type_get_name         (JsonNodeType     node_type);
 G_GNUC_INTERNAL
diff --git a/json-glib/json-types.h b/json-glib/json-types.h
index 9acc23b..36519c3 100644
--- a/json-glib/json-types.h
+++ b/json-glib/json-types.h
@@ -368,6 +368,32 @@ void                  json_object_foreach_member     (JsonObject  *object,
                                                       JsonObjectForeach func,
                                                       gpointer     data);
 
+/**
+ * JsonObjectIter:
+ *
+ * An iterator used to iterate over the members of a #JsonObject. This must
+ * be allocated on the stack and initialised using json_object_iter_init().
+ * The order in which members are returned by the iterator is undefined. The
+ * iterator is invalidated if its #JsonObject is modified during iteration.
+ *
+ * All the fields in the #JsonObjectIter structure are private and should
+ * never be accessed directly.
+ *
+ * Since: UNRELEASED
+ */
+typedef struct {
+       /*< private >*/
+       gpointer priv[8];
+} JsonObjectIter;
+
+JSON_AVAILABLE_IN_1_2
+void                  json_object_iter_init          (JsonObjectIter  *iter,
+                                                      JsonObject      *object);
+JSON_AVAILABLE_IN_1_2
+gboolean              json_object_iter_next          (JsonObjectIter  *iter,
+                                                      const gchar    **member_name,
+                                                      JsonNode       **member_node);
+
 JSON_AVAILABLE_IN_1_0
 GType                 json_array_get_type            (void) G_GNUC_CONST;
 JSON_AVAILABLE_IN_1_0
diff --git a/json-glib/tests/object.c b/json-glib/tests/object.c
index f109464..54b5934 100644
--- a/json-glib/tests/object.c
+++ b/json-glib/tests/object.c
@@ -140,6 +140,33 @@ test_foreach_member (void)
 }
 
 static void
+test_iter (void)
+{
+  JsonObject *object = NULL;
+  TestForeachFixture fixture = { 0, };
+  JsonObjectIter iter;
+  const gchar *member_name;
+  JsonNode *member_node;
+
+  object = json_object_new ();
+
+  json_object_set_int_member (object, "integer", 42);
+  json_object_set_boolean_member (object, "boolean", TRUE);
+  json_object_set_string_member (object, "string", "hello");
+  json_object_set_double_member (object, "double", 3.14159);
+  json_object_set_null_member (object, "null");
+
+  json_object_iter_init (&iter, object);
+
+  while (json_object_iter_next (&iter, &member_name, &member_node))
+    verify_foreach (object, member_name, member_node, &fixture);
+
+  g_assert_cmpint (fixture.n_members, ==, json_object_get_size (object));
+
+  json_object_unref (object);
+}
+
+static void
 test_empty_member (void)
 {
   JsonObject *object = json_object_new ();
@@ -173,6 +200,7 @@ main (int   argc,
   g_test_add_func ("/object/set-member", test_set_member);
   g_test_add_func ("/object/remove-member", test_remove_member);
   g_test_add_func ("/object/foreach-member", test_foreach_member);
+  g_test_add_func ("/object/iter", test_iter);
   g_test_add_func ("/object/empty-member", test_empty_member);
 
   return g_test_run ();


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