Extend object API
authorPetri Lehtinen <petri@digip.org>
Sun, 11 Oct 2009 17:42:43 +0000 (20:42 +0300)
committerPetri Lehtinen <petri@digip.org>
Sun, 11 Oct 2009 17:44:01 +0000 (20:44 +0300)
Added functions:

  json_object_size
  json_object_clear
  json_object_update

doc/apiref.rst
src/hashtable.c
src/hashtable.h
src/jansson.h
src/value.c
test/testprogs/test_object.c

index cc6b1f1..1a6a77b 100644 (file)
@@ -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)
index afb3304..05dc167 100644 (file)
@@ -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);
index 76666a4..d01b7e7 100644 (file)
@@ -135,6 +135,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
  *
  * @hashtable: The hashtable object
index b7a75b6..6751998 100644 (file)
@@ -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);
index d8e9e9a..b06cb4f 100644 (file)
@@ -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;
index 1f9f83c..3be49e5 100644 (file)
@@ -9,7 +9,137 @@
 #include <string.h>
 #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;
 }