Merge pull request #293 from akheron/object-insertion-order
Always preserve insertion order of object items
This commit is contained in:
commit
14573dc920
@ -659,7 +659,8 @@ allowed in object keys.
|
|||||||
/* block of code that uses key and value */
|
/* block of code that uses key and value */
|
||||||
}
|
}
|
||||||
|
|
||||||
The items are not returned in any particular order.
|
The items are returned in the order they were inserted to the
|
||||||
|
object.
|
||||||
|
|
||||||
**Note:** It's not safe to call ``json_object_del(object, key)``
|
**Note:** It's not safe to call ``json_object_del(object, key)``
|
||||||
during iteration. If you need to, use
|
during iteration. If you need to, use
|
||||||
@ -685,9 +686,8 @@ allowed in object keys.
|
|||||||
|
|
||||||
|
|
||||||
The following functions can be used to iterate through all key-value
|
The following functions can be used to iterate through all key-value
|
||||||
pairs in an object. The items are not returned in any particular order,
|
pairs in an object. The items are returned in the order they were
|
||||||
as this would require sorting due to the internal hashtable
|
inserted to the object.
|
||||||
implementation.
|
|
||||||
|
|
||||||
.. function:: void *json_object_iter(json_t *object)
|
.. function:: void *json_object_iter(json_t *object)
|
||||||
|
|
||||||
@ -885,10 +885,13 @@ can be ORed together to obtain *flags*.
|
|||||||
compared.
|
compared.
|
||||||
|
|
||||||
``JSON_PRESERVE_ORDER``
|
``JSON_PRESERVE_ORDER``
|
||||||
If this flag is used, object keys in the output are sorted into the
|
**Deprecated since version 2.8:** Order of object keys
|
||||||
same order in which they were first inserted to the object. For
|
is always preserved.
|
||||||
example, decoding a JSON text and then encoding with this flag
|
|
||||||
preserves the order of object keys.
|
Prior to version 2.8: If this flag is used, object keys in the
|
||||||
|
output are sorted into the same order in which they were first
|
||||||
|
inserted to the object. For example, decoding a JSON text and then
|
||||||
|
encoding with this flag preserves the order of object keys.
|
||||||
|
|
||||||
``JSON_ENCODE_ANY``
|
``JSON_ENCODE_ANY``
|
||||||
Specifying this flag makes it possible to encode any JSON value on
|
Specifying this flag makes it possible to encode any JSON value on
|
||||||
@ -1508,9 +1511,7 @@ the same child values in the copied value. Deep copying makes a fresh
|
|||||||
copy of the child values, too. Moreover, all the child values are deep
|
copy of the child values, too. Moreover, all the child values are deep
|
||||||
copied in a recursive fashion.
|
copied in a recursive fashion.
|
||||||
|
|
||||||
Copying objects doesn't preserve the insertion order of keys. Deep
|
Copying objects preserves the insertion order of keys.
|
||||||
copying also loses the key insertion order of any objects deeper in
|
|
||||||
the hierarchy.
|
|
||||||
|
|
||||||
.. function:: json_t *json_copy(json_t *value)
|
.. function:: json_t *json_copy(json_t *value)
|
||||||
|
|
||||||
|
37
src/dump.c
37
src/dump.c
@ -25,11 +25,6 @@
|
|||||||
#define FLAGS_TO_INDENT(f) ((f) & 0x1F)
|
#define FLAGS_TO_INDENT(f) ((f) & 0x1F)
|
||||||
#define FLAGS_TO_PRECISION(f) (((f) >> 11) & 0x1F)
|
#define FLAGS_TO_PRECISION(f) (((f) >> 11) & 0x1F)
|
||||||
|
|
||||||
struct object_key {
|
|
||||||
size_t serial;
|
|
||||||
const char *key;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int dump_to_strbuffer(const char *buffer, size_t size, void *data)
|
static int dump_to_strbuffer(const char *buffer, size_t size, void *data)
|
||||||
{
|
{
|
||||||
return strbuffer_append_bytes((strbuffer_t *)data, buffer, size);
|
return strbuffer_append_bytes((strbuffer_t *)data, buffer, size);
|
||||||
@ -165,18 +160,9 @@ static int dump_string(const char *str, size_t len, json_dump_callback_t dump, v
|
|||||||
return dump("\"", 1, data);
|
return dump("\"", 1, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int object_key_compare_keys(const void *key1, const void *key2)
|
static int compare_keys(const void *key1, const void *key2)
|
||||||
{
|
{
|
||||||
return strcmp(((const struct object_key *)key1)->key,
|
return strcmp(*(const char **)key1, *(const char **)key2);
|
||||||
((const struct object_key *)key2)->key);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int object_key_compare_serials(const void *key1, const void *key2)
|
|
||||||
{
|
|
||||||
size_t a = ((const struct object_key *)key1)->serial;
|
|
||||||
size_t b = ((const struct object_key *)key2)->serial;
|
|
||||||
|
|
||||||
return a < b ? -1 : a == b ? 0 : 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_dump(const json_t *json, size_t flags, int depth,
|
static int do_dump(const json_t *json, size_t flags, int depth,
|
||||||
@ -309,40 +295,33 @@ static int do_dump(const json_t *json, size_t flags, int depth,
|
|||||||
if(dump_indent(flags, depth + 1, 0, dump, data))
|
if(dump_indent(flags, depth + 1, 0, dump, data))
|
||||||
goto object_error;
|
goto object_error;
|
||||||
|
|
||||||
if(flags & JSON_SORT_KEYS || flags & JSON_PRESERVE_ORDER)
|
if(flags & JSON_SORT_KEYS)
|
||||||
{
|
{
|
||||||
struct object_key *keys;
|
const char **keys;
|
||||||
size_t size, i;
|
size_t size, i;
|
||||||
int (*cmp_func)(const void *, const void *);
|
|
||||||
|
|
||||||
size = json_object_size(json);
|
size = json_object_size(json);
|
||||||
keys = jsonp_malloc(size * sizeof(struct object_key));
|
keys = jsonp_malloc(size * sizeof(const char *));
|
||||||
if(!keys)
|
if(!keys)
|
||||||
goto object_error;
|
goto object_error;
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
while(iter)
|
while(iter)
|
||||||
{
|
{
|
||||||
keys[i].serial = hashtable_iter_serial(iter);
|
keys[i] = json_object_iter_key(iter);
|
||||||
keys[i].key = json_object_iter_key(iter);
|
|
||||||
iter = json_object_iter_next((json_t *)json, iter);
|
iter = json_object_iter_next((json_t *)json, iter);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
assert(i == size);
|
assert(i == size);
|
||||||
|
|
||||||
if(flags & JSON_SORT_KEYS)
|
qsort(keys, size, sizeof(const char *), compare_keys);
|
||||||
cmp_func = object_key_compare_keys;
|
|
||||||
else
|
|
||||||
cmp_func = object_key_compare_serials;
|
|
||||||
|
|
||||||
qsort(keys, size, sizeof(struct object_key), cmp_func);
|
|
||||||
|
|
||||||
for(i = 0; i < size; i++)
|
for(i = 0; i < size; i++)
|
||||||
{
|
{
|
||||||
const char *key;
|
const char *key;
|
||||||
json_t *value;
|
json_t *value;
|
||||||
|
|
||||||
key = keys[i].key;
|
key = keys[i];
|
||||||
value = json_object_get(json, key);
|
value = json_object_get(json, key);
|
||||||
assert(value);
|
assert(value);
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@ extern volatile uint32_t hashtable_seed;
|
|||||||
#include "lookup3.h"
|
#include "lookup3.h"
|
||||||
|
|
||||||
#define list_to_pair(list_) container_of(list_, pair_t, list)
|
#define list_to_pair(list_) container_of(list_, pair_t, list)
|
||||||
|
#define ordered_list_to_pair(list_) container_of(list_, pair_t, ordered_list)
|
||||||
#define hash_str(key) ((size_t)hashlittle((key), strlen(key), hashtable_seed))
|
#define hash_str(key) ((size_t)hashlittle((key), strlen(key), hashtable_seed))
|
||||||
|
|
||||||
static JSON_INLINE void list_init(list_t *list)
|
static JSON_INLINE void list_init(list_t *list)
|
||||||
@ -126,6 +127,7 @@ static int hashtable_do_del(hashtable_t *hashtable,
|
|||||||
bucket->last = pair->list.prev;
|
bucket->last = pair->list.prev;
|
||||||
|
|
||||||
list_remove(&pair->list);
|
list_remove(&pair->list);
|
||||||
|
list_remove(&pair->ordered_list);
|
||||||
json_decref(pair->value);
|
json_decref(pair->value);
|
||||||
|
|
||||||
jsonp_free(pair);
|
jsonp_free(pair);
|
||||||
@ -197,6 +199,7 @@ int hashtable_init(hashtable_t *hashtable)
|
|||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
list_init(&hashtable->list);
|
list_init(&hashtable->list);
|
||||||
|
list_init(&hashtable->ordered_list);
|
||||||
|
|
||||||
for(i = 0; i < hashsize(hashtable->order); i++)
|
for(i = 0; i < hashsize(hashtable->order); i++)
|
||||||
{
|
{
|
||||||
@ -213,9 +216,7 @@ void hashtable_close(hashtable_t *hashtable)
|
|||||||
jsonp_free(hashtable->buckets);
|
jsonp_free(hashtable->buckets);
|
||||||
}
|
}
|
||||||
|
|
||||||
int hashtable_set(hashtable_t *hashtable,
|
int hashtable_set(hashtable_t *hashtable, const char *key, json_t *value)
|
||||||
const char *key, size_t serial,
|
|
||||||
json_t *value)
|
|
||||||
{
|
{
|
||||||
pair_t *pair;
|
pair_t *pair;
|
||||||
bucket_t *bucket;
|
bucket_t *bucket;
|
||||||
@ -253,12 +254,13 @@ int hashtable_set(hashtable_t *hashtable,
|
|||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
pair->hash = hash;
|
pair->hash = hash;
|
||||||
pair->serial = serial;
|
|
||||||
strncpy(pair->key, key, len + 1);
|
strncpy(pair->key, key, len + 1);
|
||||||
pair->value = value;
|
pair->value = value;
|
||||||
list_init(&pair->list);
|
list_init(&pair->list);
|
||||||
|
list_init(&pair->ordered_list);
|
||||||
|
|
||||||
insert_to_bucket(hashtable, bucket, &pair->list);
|
insert_to_bucket(hashtable, bucket, &pair->list);
|
||||||
|
list_insert(&hashtable->ordered_list, &pair->ordered_list);
|
||||||
|
|
||||||
hashtable->size++;
|
hashtable->size++;
|
||||||
}
|
}
|
||||||
@ -300,12 +302,13 @@ void hashtable_clear(hashtable_t *hashtable)
|
|||||||
}
|
}
|
||||||
|
|
||||||
list_init(&hashtable->list);
|
list_init(&hashtable->list);
|
||||||
|
list_init(&hashtable->ordered_list);
|
||||||
hashtable->size = 0;
|
hashtable->size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *hashtable_iter(hashtable_t *hashtable)
|
void *hashtable_iter(hashtable_t *hashtable)
|
||||||
{
|
{
|
||||||
return hashtable_iter_next(hashtable, &hashtable->list);
|
return hashtable_iter_next(hashtable, &hashtable->ordered_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *hashtable_iter_at(hashtable_t *hashtable, const char *key)
|
void *hashtable_iter_at(hashtable_t *hashtable, const char *key)
|
||||||
@ -321,38 +324,32 @@ void *hashtable_iter_at(hashtable_t *hashtable, const char *key)
|
|||||||
if(!pair)
|
if(!pair)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return &pair->list;
|
return &pair->ordered_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *hashtable_iter_next(hashtable_t *hashtable, void *iter)
|
void *hashtable_iter_next(hashtable_t *hashtable, void *iter)
|
||||||
{
|
{
|
||||||
list_t *list = (list_t *)iter;
|
list_t *list = (list_t *)iter;
|
||||||
if(list->next == &hashtable->list)
|
if(list->next == &hashtable->ordered_list)
|
||||||
return NULL;
|
return NULL;
|
||||||
return list->next;
|
return list->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *hashtable_iter_key(void *iter)
|
void *hashtable_iter_key(void *iter)
|
||||||
{
|
{
|
||||||
pair_t *pair = list_to_pair((list_t *)iter);
|
pair_t *pair = ordered_list_to_pair((list_t *)iter);
|
||||||
return pair->key;
|
return pair->key;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t hashtable_iter_serial(void *iter)
|
|
||||||
{
|
|
||||||
pair_t *pair = list_to_pair((list_t *)iter);
|
|
||||||
return pair->serial;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *hashtable_iter_value(void *iter)
|
void *hashtable_iter_value(void *iter)
|
||||||
{
|
{
|
||||||
pair_t *pair = list_to_pair((list_t *)iter);
|
pair_t *pair = ordered_list_to_pair((list_t *)iter);
|
||||||
return pair->value;
|
return pair->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void hashtable_iter_set(void *iter, json_t *value)
|
void hashtable_iter_set(void *iter, json_t *value)
|
||||||
{
|
{
|
||||||
pair_t *pair = list_to_pair((list_t *)iter);
|
pair_t *pair = ordered_list_to_pair((list_t *)iter);
|
||||||
|
|
||||||
json_decref(pair->value);
|
json_decref(pair->value);
|
||||||
pair->value = value;
|
pair->value = value;
|
||||||
|
@ -21,9 +21,9 @@ struct hashtable_list {
|
|||||||
too */
|
too */
|
||||||
struct hashtable_pair {
|
struct hashtable_pair {
|
||||||
struct hashtable_list list;
|
struct hashtable_list list;
|
||||||
|
struct hashtable_list ordered_list;
|
||||||
size_t hash;
|
size_t hash;
|
||||||
json_t *value;
|
json_t *value;
|
||||||
size_t serial;
|
|
||||||
char key[1];
|
char key[1];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -37,11 +37,12 @@ typedef struct hashtable {
|
|||||||
struct hashtable_bucket *buckets;
|
struct hashtable_bucket *buckets;
|
||||||
size_t order; /* hashtable has pow(2, order) buckets */
|
size_t order; /* hashtable has pow(2, order) buckets */
|
||||||
struct hashtable_list list;
|
struct hashtable_list list;
|
||||||
|
struct hashtable_list ordered_list;
|
||||||
} hashtable_t;
|
} hashtable_t;
|
||||||
|
|
||||||
|
|
||||||
#define hashtable_key_to_iter(key_) \
|
#define hashtable_key_to_iter(key_) \
|
||||||
(&(container_of(key_, struct hashtable_pair, key)->list))
|
(&(container_of(key_, struct hashtable_pair, key)->ordered_list))
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -80,9 +81,7 @@ void hashtable_close(hashtable_t *hashtable);
|
|||||||
*
|
*
|
||||||
* Returns 0 on success, -1 on failure (out of memory).
|
* Returns 0 on success, -1 on failure (out of memory).
|
||||||
*/
|
*/
|
||||||
int hashtable_set(hashtable_t *hashtable,
|
int hashtable_set(hashtable_t *hashtable, const char *key, json_t *value);
|
||||||
const char *key, size_t serial,
|
|
||||||
json_t *value);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* hashtable_get - Get a value associated with a key
|
* hashtable_get - Get a value associated with a key
|
||||||
@ -159,13 +158,6 @@ void *hashtable_iter_next(hashtable_t *hashtable, void *iter);
|
|||||||
*/
|
*/
|
||||||
void *hashtable_iter_key(void *iter);
|
void *hashtable_iter_key(void *iter);
|
||||||
|
|
||||||
/**
|
|
||||||
* hashtable_iter_serial - Retrieve the serial number pointed to by an iterator
|
|
||||||
*
|
|
||||||
* @iter: The iterator
|
|
||||||
*/
|
|
||||||
size_t hashtable_iter_serial(void *iter);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* hashtable_iter_value - Retrieve the value pointed by an iterator
|
* hashtable_iter_value - Retrieve the value pointed by an iterator
|
||||||
*
|
*
|
||||||
|
@ -34,7 +34,6 @@
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
json_t json;
|
json_t json;
|
||||||
hashtable_t hashtable;
|
hashtable_t hashtable;
|
||||||
size_t serial;
|
|
||||||
int visited;
|
int visited;
|
||||||
} json_object_t;
|
} json_object_t;
|
||||||
|
|
||||||
|
@ -464,7 +464,7 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap)
|
|||||||
if(unpack(s, value, ap))
|
if(unpack(s, value, ap))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
hashtable_set(&key_set, key, 0, json_null());
|
hashtable_set(&key_set, key, json_null());
|
||||||
next_token(s);
|
next_token(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,7 +67,6 @@ json_t *json_object(void)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
object->serial = 0;
|
|
||||||
object->visited = 0;
|
object->visited = 0;
|
||||||
|
|
||||||
return &object->json;
|
return &object->json;
|
||||||
@ -115,7 +114,7 @@ int json_object_set_new_nocheck(json_t *json, const char *key, json_t *value)
|
|||||||
}
|
}
|
||||||
object = json_to_object(json);
|
object = json_to_object(json);
|
||||||
|
|
||||||
if(hashtable_set(&object->hashtable, key, object->serial++, value))
|
if(hashtable_set(&object->hashtable, key, value))
|
||||||
{
|
{
|
||||||
json_decref(value);
|
json_decref(value);
|
||||||
return -1;
|
return -1;
|
||||||
@ -154,9 +153,7 @@ int json_object_clear(json_t *json)
|
|||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
object = json_to_object(json);
|
object = json_to_object(json);
|
||||||
|
|
||||||
hashtable_clear(&object->hashtable);
|
hashtable_clear(&object->hashtable);
|
||||||
object->serial = 0;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -232,6 +232,9 @@ static void test_copy_object(void)
|
|||||||
const char *json_object_text =
|
const char *json_object_text =
|
||||||
"{\"foo\": \"bar\", \"a\": 1, \"b\": 3.141592, \"c\": [1,2,3,4]}";
|
"{\"foo\": \"bar\", \"a\": 1, \"b\": 3.141592, \"c\": [1,2,3,4]}";
|
||||||
|
|
||||||
|
const char *keys[] = {"foo", "a", "b", "c"};
|
||||||
|
int i;
|
||||||
|
|
||||||
json_t *object, *copy;
|
json_t *object, *copy;
|
||||||
void *iter;
|
void *iter;
|
||||||
|
|
||||||
@ -247,6 +250,7 @@ static void test_copy_object(void)
|
|||||||
if(!json_equal(copy, object))
|
if(!json_equal(copy, object))
|
||||||
fail("copying an object produces an inequal copy");
|
fail("copying an object produces an inequal copy");
|
||||||
|
|
||||||
|
i = 0;
|
||||||
iter = json_object_iter(object);
|
iter = json_object_iter(object);
|
||||||
while(iter)
|
while(iter)
|
||||||
{
|
{
|
||||||
@ -258,9 +262,13 @@ static void test_copy_object(void)
|
|||||||
value2 = json_object_get(copy, key);
|
value2 = json_object_get(copy, key);
|
||||||
|
|
||||||
if(value1 != value2)
|
if(value1 != value2)
|
||||||
fail("deep copying an object modifies its items");
|
fail("copying an object modifies its items");
|
||||||
|
|
||||||
|
if (strcmp(key, keys[i]) != 0)
|
||||||
|
fail("copying an object doesn't preserve key order");
|
||||||
|
|
||||||
iter = json_object_iter_next(object, iter);
|
iter = json_object_iter_next(object, iter);
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
json_decref(object);
|
json_decref(object);
|
||||||
@ -272,6 +280,9 @@ static void test_deep_copy_object(void)
|
|||||||
const char *json_object_text =
|
const char *json_object_text =
|
||||||
"{\"foo\": \"bar\", \"a\": 1, \"b\": 3.141592, \"c\": [1,2,3,4]}";
|
"{\"foo\": \"bar\", \"a\": 1, \"b\": 3.141592, \"c\": [1,2,3,4]}";
|
||||||
|
|
||||||
|
const char *keys[] = {"foo", "a", "b", "c"};
|
||||||
|
int i;
|
||||||
|
|
||||||
json_t *object, *copy;
|
json_t *object, *copy;
|
||||||
void *iter;
|
void *iter;
|
||||||
|
|
||||||
@ -287,6 +298,7 @@ static void test_deep_copy_object(void)
|
|||||||
if(!json_equal(copy, object))
|
if(!json_equal(copy, object))
|
||||||
fail("deep copying an object produces an inequal copy");
|
fail("deep copying an object produces an inequal copy");
|
||||||
|
|
||||||
|
i = 0;
|
||||||
iter = json_object_iter(object);
|
iter = json_object_iter(object);
|
||||||
while(iter)
|
while(iter)
|
||||||
{
|
{
|
||||||
@ -300,7 +312,11 @@ static void test_deep_copy_object(void)
|
|||||||
if(value1 == value2)
|
if(value1 == value2)
|
||||||
fail("deep copying an object doesn't copy its items");
|
fail("deep copying an object doesn't copy its items");
|
||||||
|
|
||||||
|
if (strcmp(key, keys[i]) != 0)
|
||||||
|
fail("deep copying an object doesn't preserve key order");
|
||||||
|
|
||||||
iter = json_object_iter_next(object, iter);
|
iter = json_object_iter_next(object, iter);
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
json_decref(object);
|
json_decref(object);
|
||||||
|
@ -275,11 +275,7 @@ static void test_set_nocheck()
|
|||||||
|
|
||||||
static void test_iterators()
|
static void test_iterators()
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
json_t *object, *foo, *bar, *baz;
|
json_t *object, *foo, *bar, *baz;
|
||||||
const char *iter_keys[3];
|
|
||||||
int have_key[3] = { 0, 0, 0 };
|
|
||||||
json_t *iter_values[3];
|
|
||||||
void *iter;
|
void *iter;
|
||||||
|
|
||||||
if(json_object_iter(NULL))
|
if(json_object_iter(NULL))
|
||||||
@ -306,50 +302,30 @@ static void test_iterators()
|
|||||||
iter = json_object_iter(object);
|
iter = json_object_iter(object);
|
||||||
if(!iter)
|
if(!iter)
|
||||||
fail("unable to get iterator");
|
fail("unable to get iterator");
|
||||||
iter_keys[0] = json_object_iter_key(iter);
|
if (strcmp(json_object_iter_key(iter), "a") != 0)
|
||||||
iter_values[0] = json_object_iter_value(iter);
|
fail("iterating doesn't yield keys in order");
|
||||||
|
if (json_object_iter_value(iter) != foo)
|
||||||
|
fail("iterating doesn't yield values in order");
|
||||||
|
|
||||||
iter = json_object_iter_next(object, iter);
|
iter = json_object_iter_next(object, iter);
|
||||||
if(!iter)
|
if(!iter)
|
||||||
fail("unable to increment iterator");
|
fail("unable to increment iterator");
|
||||||
iter_keys[1] = json_object_iter_key(iter);
|
if (strcmp(json_object_iter_key(iter), "b") != 0)
|
||||||
iter_values[1] = json_object_iter_value(iter);
|
fail("iterating doesn't yield keys in order");
|
||||||
|
if (json_object_iter_value(iter) != bar)
|
||||||
|
fail("iterating doesn't yield values in order");
|
||||||
|
|
||||||
iter = json_object_iter_next(object, iter);
|
iter = json_object_iter_next(object, iter);
|
||||||
if(!iter)
|
if(!iter)
|
||||||
fail("unable to increment iterator");
|
fail("unable to increment iterator");
|
||||||
iter_keys[2] = json_object_iter_key(iter);
|
if (strcmp(json_object_iter_key(iter), "c") != 0)
|
||||||
iter_values[2] = json_object_iter_value(iter);
|
fail("iterating doesn't yield keys in order");
|
||||||
|
if (json_object_iter_value(iter) != baz)
|
||||||
|
fail("iterating doesn't yield values in order");
|
||||||
|
|
||||||
if(json_object_iter_next(object, iter) != NULL)
|
if(json_object_iter_next(object, iter) != NULL)
|
||||||
fail("able to iterate over the end");
|
fail("able to iterate over the end");
|
||||||
|
|
||||||
/* Check that keys have correct values */
|
|
||||||
for (i = 0; i < 3; i++) {
|
|
||||||
if (strcmp(iter_keys[i], "a") == 0) {
|
|
||||||
if (iter_values[i] != foo)
|
|
||||||
fail("wrong value for iter key a");
|
|
||||||
else
|
|
||||||
have_key[0] = 1;
|
|
||||||
} else if (strcmp(iter_keys[i], "b") == 0) {
|
|
||||||
if (iter_values[i] != bar)
|
|
||||||
fail("wrong value for iter key b");
|
|
||||||
else
|
|
||||||
have_key[1] = 1;
|
|
||||||
} else if (strcmp(iter_keys[i], "c") == 0) {
|
|
||||||
if (iter_values[i] != baz)
|
|
||||||
fail("wrong value for iter key c");
|
|
||||||
else
|
|
||||||
have_key[2] = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check that we got all keys */
|
|
||||||
for(i = 0; i < 3; i++) {
|
|
||||||
if(!have_key[i])
|
|
||||||
fail("a key wasn't iterated over");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(json_object_iter_at(object, "foo"))
|
if(json_object_iter_at(object, "foo"))
|
||||||
fail("json_object_iter_at() succeeds for non-existent key");
|
fail("json_object_iter_at() succeeds for non-existent key");
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user