diff options
| author | Philip Withnall <philip.withnall@collabora.co.uk> | 2015-09-24 11:06:34 +0100 |
|---|---|---|
| committer | Philip Withnall <philip.withnall@collabora.co.uk> | 2015-10-06 08:31:25 +0100 |
| commit | d231976e240f2244c60df26a1a6600ecb325506a (patch) | |
| tree | c0b3b15dfc4d0bdec97277fd27b2857654a21d36 | |
| parent | 5185a8f8a58e5b455116eaa8c99c4b4c38a45929 (diff) | |
| download | json-glib-d231976e240f2244c60df26a1a6600ecb325506a.tar.gz | |
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
| -rw-r--r-- | doc/reference/json-glib-sections.txt | 3 | ||||
| -rw-r--r-- | json-glib/json-object.c | 71 | ||||
| -rw-r--r-- | json-glib/json-types-private.h | 9 | ||||
| -rw-r--r-- | json-glib/json-types.h | 26 | ||||
| -rw-r--r-- | 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 (); |
