Implement json_object_foreach()

Also change many places to use it internally to replace hand-crafted
iteration.

Closes #45, #46.
This commit is contained in:
Petri Lehtinen 2012-01-24 20:37:08 +02:00
parent a2381948bb
commit a307974731
6 changed files with 92 additions and 46 deletions

View File

@ -565,6 +565,36 @@ Unicode string and the value is any JSON value.
existing keys. Returns 0 on success or -1 on error.
The following macro can be used to iterate through all key-value pairs
in an object.
.. function:: json_object_foreach(object, key, value)
Iterate over every key-value pair of ``object``, running the block
of code that follows each time with the proper values set to
variables ``key`` and ``value``, of types :type:`const char *` and
:type:`json_t *` respectively. Example::
/* obj is a JSON object */
const char *key;
json_t *value;
json_object_foreach(obj, key, value) {
/* block of code that uses key and value */
}
The items are not returned in any particular order.
This macro expands to an ordinary ``for`` statement upon
preprocessing, so its performance is equivalent to that of
hand-written iteration code using the object iteration protocol
(see below). The main advantage of this macro is that it abstracts
away the complexity behind iteration, and makes for shorter, more
concise code.
.. versionadded:: 2.3
The following functions implement an iteration protocol for objects,
allowing to iterate through all key-value pairs in an object. The
items are not returned in any particular order, as this would require
@ -610,11 +640,21 @@ sorting due to the internal hashtable implementation.
*value*. This is useful when *value* is newly created and not used
after the call.
.. function:: void *json_object_key_to_iter(const char *key)
Like :func:`json_object_iter_at()`, but much faster. Only works for
values returned by :func:`json_object_iter_key()`. Using other keys
will lead to segfaults. This function is used internally to
implement :func:`json_object_foreach`.
.. versionadded:: 2.3
The iteration protocol can be used for example as follows::
/* obj is a JSON object */
const char *key;
json_t *value;
void *iter = json_object_iter(obj);
while(iter)
{

View File

@ -40,6 +40,10 @@ typedef struct hashtable {
struct hashtable_list list;
} hashtable_t;
#define hashtable_key_to_iter(key_) \
(&(container_of(key_, struct hashtable_pair, key)->list))
/**
* hashtable_init - Initialize a hashtable object
*

View File

@ -132,11 +132,17 @@ int json_object_clear(json_t *object);
int json_object_update(json_t *object, json_t *other);
void *json_object_iter(json_t *object);
void *json_object_iter_at(json_t *object, const char *key);
void *json_object_key_to_iter(const char *key);
void *json_object_iter_next(json_t *object, void *iter);
const char *json_object_iter_key(void *iter);
json_t *json_object_iter_value(void *iter);
int json_object_iter_set_new(json_t *object, void *iter, json_t *value);
#define json_object_foreach(object, key, value) \
for(key = json_object_iter_key(json_object_iter(object)); \
key && (value = json_object_iter_value(json_object_key_to_iter(key))); \
key = json_object_iter_key(json_object_iter_next(object, json_object_key_to_iter(key))))
static JSON_INLINE
int json_object_set(json_t *object, const char *key, json_t *value)
{

View File

@ -135,23 +135,15 @@ int json_object_clear(json_t *json)
int json_object_update(json_t *object, json_t *other)
{
void *iter;
const char *key;
json_t *value;
if(!json_is_object(object) || !json_is_object(other))
return -1;
iter = json_object_iter(other);
while(iter) {
const char *key;
json_t *value;
key = json_object_iter_key(iter);
value = json_object_iter_value(iter);
json_object_foreach(other, key, value) {
if(json_object_set_nocheck(object, key, value))
return -1;
iter = json_object_iter_next(other, iter);
}
return 0;
@ -215,27 +207,27 @@ int json_object_iter_set_new(json_t *json, void *iter, json_t *value)
return 0;
}
void *json_object_key_to_iter(const char *key)
{
if(!key)
return NULL;
return hashtable_key_to_iter(key);
}
static int json_object_equal(json_t *object1, json_t *object2)
{
void *iter;
const char *key;
json_t *value1, *value2;
if(json_object_size(object1) != json_object_size(object2))
return 0;
iter = json_object_iter(object1);
while(iter)
{
const char *key;
json_t *value1, *value2;
key = json_object_iter_key(iter);
value1 = json_object_iter_value(iter);
json_object_foreach(object1, key, value1) {
value2 = json_object_get(object2, key);
if(!json_equal(value1, value2))
return 0;
iter = json_object_iter_next(object1, iter);
}
return 1;
@ -244,50 +236,34 @@ static int json_object_equal(json_t *object1, json_t *object2)
static json_t *json_object_copy(json_t *object)
{
json_t *result;
void *iter;
const char *key;
json_t *value;
result = json_object();
if(!result)
return NULL;
iter = json_object_iter(object);
while(iter)
{
const char *key;
json_t *value;
key = json_object_iter_key(iter);
value = json_object_iter_value(iter);
json_object_foreach(object, key, value)
json_object_set_nocheck(result, key, value);
iter = json_object_iter_next(object, iter);
}
return result;
}
static json_t *json_object_deep_copy(json_t *object)
{
json_t *result;
void *iter;
const char *key;
json_t *value;
result = json_object();
if(!result)
return NULL;
iter = json_object_iter(object);
while(iter)
{
const char *key;
json_t *value;
key = json_object_iter_key(iter);
value = json_object_iter_value(iter);
json_object_foreach(object, key, value)
json_object_set_new_nocheck(result, key, json_deep_copy(value));
iter = json_object_iter_next(object, iter);
}
return result;
}

View File

@ -44,6 +44,7 @@ json_object_iter_next
json_object_iter_key
json_object_iter_value
json_object_iter_set_new
json_object_key_to_iter
json_dumps
json_dumpf
json_dump_file

View File

@ -437,6 +437,24 @@ static void test_preserve_order()
json_decref(object);
}
static void test_foreach()
{
const char *key;
json_t *object1, *object2, *value;
object1 = json_pack("{sisisi}", "foo", 1, "bar", 2, "baz", 3);
object2 = json_object();
json_object_foreach(object1, key, value)
json_object_set(object2, key, value);
if(!json_equal(object1, object2))
fail("json_object_foreach failed to iterate all key-value pairs");
json_decref(object1);
json_decref(object2);
}
static void run_tests()
{
test_misc();
@ -446,4 +464,5 @@ static void run_tests()
test_set_nocheck();
test_iterators();
test_preserve_order();
test_foreach();
}