diff --git a/doc/apiref.rst b/doc/apiref.rst index cc6b1f1..1a6a77b 100644 --- a/doc/apiref.rst +++ b/doc/apiref.rst @@ -343,6 +343,13 @@ Unicode string and the value is any JSON value. Returns a new JSON object, or *NULL* on error. Initially, the object is empty. +.. cfunction:: unsigned int json_object_size(const json_t *object) + + Returns the number of elements in *object*, or 0 if *object* is not + a JSON object. + + .. versionadded:: 1.1 + .. cfunction:: json_t *json_object_get(const json_t *object, const char *key) .. refcounting:: borrow @@ -371,6 +378,21 @@ Unicode string and the value is any JSON value. -1 if *key* was not found. +.. cfunction:: int json_object_clear(json_t *object) + + Remove all elements from *object*. Returns 0 on success and -1 if + *object* is not a JSON object. + + .. versionadded:: 1.1 + +.. cfunction:: int json_object_update(json_t *object, json_t *other) + + Update *object* with the key-value pairs from *other*, overwriting + existing keys. Returns 0 on success or -1 on error. + + .. versionadded:: 1.1 + + The following functions implement an iteration protocol for objects: .. cfunction:: void *json_object_iter(json_t *object) diff --git a/src/hashtable.c b/src/hashtable.c index afb3304..05dc167 100644 --- a/src/hashtable.c +++ b/src/hashtable.c @@ -133,6 +133,23 @@ static int hashtable_do_del(hashtable_t *hashtable, return 0; } +static void hashtable_do_clear(hashtable_t *hashtable) +{ + list_t *list, *next; + pair_t *pair; + + for(list = hashtable->list.next; list != &hashtable->list; list = next) + { + next = list->next; + pair = list_to_pair(list); + if(hashtable->free_key) + hashtable->free_key(pair->key); + if(hashtable->free_value) + hashtable->free_value(pair->value); + free(pair); + } +} + static int hashtable_do_rehash(hashtable_t *hashtable) { list_t *list, *next; @@ -220,19 +237,7 @@ int hashtable_init(hashtable_t *hashtable, void hashtable_close(hashtable_t *hashtable) { - list_t *list, *next; - pair_t *pair; - for(list = hashtable->list.next; list != &hashtable->list; list = next) - { - next = list->next; - pair = list_to_pair(list); - if(hashtable->free_key) - hashtable->free_key(pair->key); - if(hashtable->free_value) - hashtable->free_value(pair->value); - free(pair); - } - + hashtable_do_clear(hashtable); free(hashtable->buckets); } @@ -292,6 +297,22 @@ int hashtable_del(hashtable_t *hashtable, const void *key) return hashtable_do_del(hashtable, key, hash); } +void hashtable_clear(hashtable_t *hashtable) +{ + unsigned int i; + + hashtable_do_clear(hashtable); + + for(i = 0; i < num_buckets(hashtable); i++) + { + hashtable->buckets[i].first = hashtable->buckets[i].last = + &hashtable->list; + } + + list_init(&hashtable->list); + hashtable->size = 0; +} + void *hashtable_iter(hashtable_t *hashtable) { return hashtable_iter_next(hashtable, &hashtable->list); diff --git a/src/hashtable.h b/src/hashtable.h index 76666a4..d01b7e7 100644 --- a/src/hashtable.h +++ b/src/hashtable.h @@ -134,6 +134,15 @@ void *hashtable_get(hashtable_t *hashtable, const void *key); */ int hashtable_del(hashtable_t *hashtable, const void *key); +/** + * hashtable_clear - Clear hashtable + * + * @hashtable: The hashtable object + * + * Removes all items from the hashtable. + */ +void hashtable_clear(hashtable_t *hashtable); + /** * hashtable_iter - Iterate over hashtable * diff --git a/src/jansson.h b/src/jansson.h index b7a75b6..6751998 100644 --- a/src/jansson.h +++ b/src/jansson.h @@ -71,9 +71,12 @@ static inline void json_decref(json_t *json) /* getters, setters, manipulation */ +unsigned int json_object_size(const json_t *object); json_t *json_object_get(const json_t *object, const char *key); int json_object_set_new(json_t *object, const char *key, json_t *value); int json_object_del(json_t *object, const char *key); +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_next(json_t *object, void *iter); const char *json_object_iter_key(void *iter); diff --git a/src/value.c b/src/value.c index d8e9e9a..b06cb4f 100644 --- a/src/value.c +++ b/src/value.c @@ -107,6 +107,17 @@ static void json_delete_object(json_object_t *object) free(object); } +unsigned int json_object_size(const json_t *json) +{ + json_object_t *object; + + if(!json_is_object(json)) + return -1; + + object = json_to_object(json); + return object->hashtable.size; +} + json_t *json_object_get(const json_t *json, const char *key) { json_object_t *object; @@ -168,6 +179,43 @@ int json_object_del(json_t *json, const char *key) return hashtable_del(&object->hashtable, key); } +int json_object_clear(json_t *json) +{ + json_object_t *object; + + if(!json_is_object(json)) + return -1; + + object = json_to_object(json); + hashtable_clear(&object->hashtable); + + return 0; +} + +int json_object_update(json_t *object, json_t *other) +{ + void *iter; + + 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); + + if(json_object_set(object, key, value)) + return -1; + + iter = json_object_iter_next(other, iter); + } + + return 0; +} + void *json_object_iter(json_t *json) { json_object_t *object; diff --git a/test/testprogs/test_object.c b/test/testprogs/test_object.c index 1f9f83c..3be49e5 100644 --- a/test/testprogs/test_object.c +++ b/test/testprogs/test_object.c @@ -9,7 +9,137 @@ #include #include "util.h" -int main() +static void test_clear() +{ + json_t *object, *ten; + + object = json_object(); + ten = json_integer(10); + + if(!object) + fail("unable to create object"); + if(!ten) + fail("unable to create integer"); + + if(json_object_set(object, "a", ten) || + json_object_set(object, "b", ten) || + json_object_set(object, "c", ten) || + json_object_set(object, "d", ten) || + json_object_set(object, "e", ten)) + fail("unable to set value"); + + if(json_object_size(object) != 5) + fail("invalid size"); + + json_object_clear(object); + + if(json_object_size(object) != 0) + fail("invalid size after clear"); + + json_decref(ten); + json_decref(object); +} + +static void test_update() +{ + json_t *object, *other, *nine, *ten; + + object = json_object(); + other = json_object(); + + nine = json_integer(9); + ten = json_integer(10); + + if(!object || !other) + fail("unable to create object"); + if(!nine || !ten) + fail("unable to create integer"); + + + /* update an empty object with an empty object */ + + if(json_object_update(object, other)) + fail("unable to update an emtpy object with an empty object"); + + if(json_object_size(object) != 0) + fail("invalid size after update"); + + if(json_object_size(other) != 0) + fail("invalid size for updater after update"); + + + /* update an empty object with a nonempty object */ + + if(json_object_set(other, "a", ten) || + json_object_set(other, "b", ten) || + json_object_set(other, "c", ten) || + json_object_set(other, "d", ten) || + json_object_set(other, "e", ten)) + fail("unable to set value"); + + if(json_object_update(object, other)) + fail("unable to update an empty object"); + + if(json_object_size(object) != 5) + fail("invalid size after update"); + + if(json_object_get(object, "a") != ten || + json_object_get(object, "b") != ten || + json_object_get(object, "c") != ten || + json_object_get(object, "d") != ten || + json_object_get(object, "e") != ten) + fail("update works incorrectly"); + + + /* perform the same update again */ + + if(json_object_update(object, other)) + fail("unable to update an empty object"); + + if(json_object_size(object) != 5) + fail("invalid size after update"); + + if(json_object_get(object, "a") != ten || + json_object_get(object, "b") != ten || + json_object_get(object, "c") != ten || + json_object_get(object, "d") != ten || + json_object_get(object, "e") != ten) + fail("update works incorrectly"); + + + /* update a nonempty object with a nonempty object with both old + and new keys */ + + if(json_object_clear(other)) + fail("clear failed"); + + if(json_object_set(other, "a", nine) || + json_object_set(other, "b", nine) || + json_object_set(other, "f", nine) || + json_object_set(other, "g", nine) || + json_object_set(other, "h", nine)) + fail("unable to set value"); + + if(json_object_update(object, other)) + fail("unable to update a nonempty object"); + + if(json_object_size(object) != 8) + fail("invalid size after update"); + + if(json_object_get(object, "a") != nine || + json_object_get(object, "b") != nine || + json_object_get(object, "f") != nine || + json_object_get(object, "g") != nine || + json_object_get(object, "h") != nine) + fail("update works incorrectly"); + + json_decref(nine); + json_decref(ten); + json_decref(other); + json_decref(object); +} + +static void test_misc() { json_t *object, *string, *other_string, *value; void *iter; @@ -20,9 +150,7 @@ int main() if(!object) fail("unable to create object"); - if(!string) - fail("unable to create string"); - if(!other_string) + if(!string || !other_string) fail("unable to create string"); if(json_object_get(object, "a")) @@ -129,6 +257,13 @@ int main() json_decref(string); json_decref(other_string); json_decref(object); +} + +int main() +{ + test_misc(); + test_clear(); + test_update(); return 0; }