diff --git a/doc/apiref.rst b/doc/apiref.rst index 8623623..cc6b1f1 100644 --- a/doc/apiref.rst +++ b/doc/apiref.rst @@ -291,6 +291,44 @@ A JSON array is an ordered collection of other JSON values. .. versionadded:: 1.1 +.. cfunction:: int json_array_insert(json_t *array, unsigned int index, json_t *value) + + Inserts *value* to *array* at position *index*, shifting the + elements at *index* and after it one position towards the end of + the array. Returns 0 on success and -1 on error. + + .. versionadded:: 1.1 + +.. cfunction:: int json_array_insert_new(json_t *array, unsigned int index, json_t *value) + + Like :cfunc:`json_array_insert()` but steals the reference to + *value*. This is useful when *value* is newly created and not used + after the call. + + .. versionadded:: 1.1 + +.. cfunction:: int json_array_remove(json_t *array, unsigned int index) + + Removes the element in *array* at position *index*, shifting the + elements after *index* one position towards the start of the array. + Returns 0 on success and -1 on error. + + .. versionadded:: 1.1 + +.. cfunction:: int json_array_clear(json_t *array) + + Removes all elements from *array*. Returns 0 on sucess and -1 on + error. + + .. versionadded:: 1.1 + +.. cfunction:: int json_array_extend(json_t *array, json_t *other_array) + + Appends all elements in *other_array* to the end of *array*. + Returns 0 on success and -1 on error. + + .. versionadded:: 1.1 + Object ====== diff --git a/src/jansson.h b/src/jansson.h index b5cdddb..b7a75b6 100644 --- a/src/jansson.h +++ b/src/jansson.h @@ -89,6 +89,10 @@ unsigned int json_array_size(const json_t *array); json_t *json_array_get(const json_t *array, unsigned int index); int json_array_set_new(json_t *array, unsigned int index, json_t *value); int json_array_append_new(json_t *array, json_t *value); +int json_array_insert_new(json_t *array, unsigned int index, json_t *value); +int json_array_remove(json_t *array, unsigned int index); +int json_array_clear(json_t *array); +int json_array_extend(json_t *array, json_t *other); static inline int json_array_set(json_t *array, unsigned int index, json_t *value) @@ -102,6 +106,11 @@ int json_array_append(json_t *array, json_t *value) return json_array_append_new(array, json_incref(value)); } +static inline +int json_array_insert(json_t *array, unsigned int index, json_t *value) +{ + return json_array_insert_new(array, index, json_incref(value)); +} const char *json_string_value(const json_t *json); int json_integer_value(const json_t *json); diff --git a/src/value.c b/src/value.c index 29f787c..bf5fd54 100644 --- a/src/value.c +++ b/src/value.c @@ -217,8 +217,13 @@ json_t *json_array(void) json_init(&array->json, JSON_ARRAY); array->entries = 0; - array->size = 0; - array->table = NULL; + array->size = 8; + + array->table = malloc(array->size * sizeof(json_t *)); + if(!array->table) { + free(array); + return NULL; + } return &array->json; } @@ -281,6 +286,48 @@ int json_array_set_new(json_t *json, unsigned int index, json_t *value) return 0; } +static void array_move(json_array_t *array, unsigned int dest, + unsigned int src, unsigned int count) +{ + memmove(&array->table[dest], &array->table[src], count * sizeof(json_t *)); +} + +static void array_copy(json_t **dest, unsigned int dpos, + json_t **src, unsigned int spos, + unsigned int count) +{ + memcpy(&dest[dpos], &src[spos], count * sizeof(json_t *)); +} + +static json_t **json_array_grow(json_array_t *array, + unsigned int amount, + int copy) +{ + unsigned int new_size; + json_t **old_table, **new_table; + + if(array->entries + amount <= array->size) + return array->table; + + old_table = array->table; + + new_size = max(array->size + amount, array->size * 2); + new_table = malloc(new_size * sizeof(json_t *)); + if(!new_table) + return NULL; + + array->size = new_size; + array->table = new_table; + + if(copy) { + array_copy(array->table, 0, old_table, 0, array->entries); + free(old_table); + return array->table; + } + + return old_table; +} + int json_array_append_new(json_t *json, json_t *value) { json_array_t *array; @@ -295,14 +342,9 @@ int json_array_append_new(json_t *json, json_t *value) } array = json_to_array(json); - if(array->entries == array->size) { - array->size = max(8, array->size * 2); - array->table = realloc(array->table, array->size * sizeof(json_t *)); - if(!array->table) - { - json_decref(value); - return -1; - } + if(!json_array_grow(array, 1, 1)) { + json_decref(value); + return -1; } array->table[array->entries] = value; @@ -311,6 +353,103 @@ int json_array_append_new(json_t *json, json_t *value) return 0; } +int json_array_insert_new(json_t *json, unsigned int index, json_t *value) +{ + json_array_t *array; + json_t **old_table; + + if(!value) + return -1; + + if(!json_is_array(json)) { + json_decref(value); + return -1; + } + array = json_to_array(json); + + if(index > array->entries) { + json_decref(value); + return -1; + } + + old_table = json_array_grow(array, 1, 0); + if(!old_table) { + json_decref(value); + return -1; + } + + if(old_table != array->table) { + array_copy(array->table, 0, old_table, 0, index); + array_copy(array->table, index + 1, old_table, index, + array->entries - index); + free(old_table); + } + else + array_move(array, index + 1, index, array->entries - index); + + array->table[index] = value; + array->entries++; + + return 0; +} + +int json_array_remove(json_t *json, unsigned int index) +{ + json_array_t *array; + + if(!json_is_array(json)) + return -1; + array = json_to_array(json); + + if(index >= array->entries) + return -1; + + json_decref(array->table[index]); + + array_move(array, index, index + 1, array->entries - index); + array->entries--; + + return 0; +} + +int json_array_clear(json_t *json) +{ + json_array_t *array; + unsigned int i; + + if(!json_is_array(json)) + return -1; + array = json_to_array(json); + + for(i = 0; i < array->entries; i++) + json_decref(array->table[i]); + + array->entries = 0; + return 0; +} + +int json_array_extend(json_t *json, json_t *other_json) +{ + json_array_t *array, *other; + unsigned int i; + + if(!json_is_array(json) || !json_is_array(other_json)) + return -1; + array = json_to_array(json); + other = json_to_array(other_json); + + if(!json_array_grow(array, other->entries, 1)) + return -1; + + for(i = 0; i < other->entries; i++) + json_incref(other->table[i]); + + array_copy(array->table, array->entries, other->table, 0, other->entries); + + array->entries += other->entries; + return 0; +} + /*** string ***/ diff --git a/test/testprogs/test_array.c b/test/testprogs/test_array.c index b597afb..53f6f3d 100644 --- a/test/testprogs/test_array.c +++ b/test/testprogs/test_array.c @@ -8,7 +8,7 @@ #include #include "util.h" -int main() +static void test_misc(void) { json_t *array, *five, *seven, *value; int i; @@ -19,9 +19,7 @@ int main() if(!array) fail("unable to create array"); - if(!five) - fail("unable to create integer"); - if(!seven) + if(!five || !seven) fail("unable to create integer"); if(json_array_size(array) != 0) @@ -114,6 +112,242 @@ int main() json_decref(five); json_decref(seven); json_decref(array); +} + +static void test_insert(void) +{ + json_t *array, *five, *seven, *eleven, *value; + int i; + + array = json_array(); + five = json_integer(5); + seven = json_integer(7); + eleven = json_integer(11); + + if(!array) + fail("unable to create array"); + if(!five || !seven || !eleven) + fail("unable to create integer"); + + + if(!json_array_insert(array, 1, five)) + fail("able to insert value out of bounds"); + + + if(json_array_insert(array, 0, five)) + fail("unable to insert value in an empty array"); + + if(json_array_get(array, 0) != five) + fail("json_array_insert works incorrectly"); + + if(json_array_size(array) != 1) + fail("array size is invalid after insertion"); + + + if(json_array_insert(array, 1, seven)) + fail("unable to insert value at the end of an array"); + + if(json_array_get(array, 0) != five) + fail("json_array_insert works incorrectly"); + + if(json_array_get(array, 1) != seven) + fail("json_array_insert works incorrectly"); + + if(json_array_size(array) != 2) + fail("array size is invalid after insertion"); + + + if(json_array_insert(array, 1, eleven)) + fail("unable to insert value in the middle of an array"); + + if(json_array_get(array, 0) != five) + fail("json_array_insert works incorrectly"); + + if(json_array_get(array, 1) != eleven) + fail("json_array_insert works incorrectly"); + + if(json_array_get(array, 2) != seven) + fail("json_array_insert works incorrectly"); + + if(json_array_size(array) != 3) + fail("array size is invalid after insertion"); + + + if(json_array_insert_new(array, 2, json_integer(123))) + fail("unable to insert value in the middle of an array"); + + value = json_array_get(array, 2); + if(!json_is_integer(value) || json_integer_value(value) != 123) + fail("json_array_insert_new works incorrectly"); + + if(json_array_size(array) != 4) + fail("array size is invalid after insertion"); + + + for(i = 0; i < 20; i++) { + if(json_array_insert(array, 0, seven)) + fail("unable to insert value at the begining of an array"); + } + + for(i = 0; i < 20; i++) { + if(json_array_get(array, i) != seven) + fail("json_aray_insert works incorrectly"); + } + + if(json_array_size(array) != 24) + fail("array size is invalid after loop insertion"); + + json_decref(five); + json_decref(seven); + json_decref(eleven); + json_decref(array); +} + +static void test_remove(void) +{ + json_t *array, *five, *seven; + + array = json_array(); + five = json_integer(5); + seven = json_integer(7); + + if(!array) + fail("unable to create array"); + if(!five) + fail("unable to create integer"); + if(!seven) + fail("unable to create integer"); + + + if(!json_array_remove(array, 0)) + fail("able to remove an unexisting index"); + + + if(json_array_append(array, five)) + fail("unable to append"); + + if(!json_array_remove(array, 1)) + fail("able to remove an unexisting index"); + + if(json_array_remove(array, 0)) + fail("unable to remove"); + + if(json_array_size(array) != 0) + fail("array size is invalid after removing"); + + + if(json_array_append(array, five) || + json_array_append(array, seven) || + json_array_append(array, five) || + json_array_append(array, seven)) + fail("unable to append"); + + if(json_array_remove(array, 2)) + fail("unable to remove"); + + if(json_array_size(array) != 3) + fail("array size is invalid after removing"); + + if(json_array_get(array, 0) != five || + json_array_get(array, 1) != seven || + json_array_get(array, 2) != seven) + fail("remove works incorrectly"); + + json_decref(five); + json_decref(seven); + json_decref(array); +} + +static void test_clear(void) +{ + json_t *array, *five, *seven; + int i; + + array = json_array(); + five = json_integer(5); + seven = json_integer(7); + + if(!array) + fail("unable to create array"); + if(!five || !seven) + fail("unable to create integer"); + + for(i = 0; i < 10; i++) { + if(json_array_append(array, five)) + fail("unable to append"); + } + for(i = 0; i < 10; i++) { + if(json_array_append(array, seven)) + fail("unable to append"); + } + + if(json_array_size(array) != 20) + fail("array size is invalid after appending"); + + if(json_array_clear(array)) + fail("unable to clear"); + + if(json_array_size(array) != 0) + fail("array size is invalid after clearing"); + + json_decref(five); + json_decref(seven); + json_decref(array); +} + +static void test_extend(void) +{ + json_t *array1, *array2, *five, *seven; + int i; + + array1 = json_array(); + array2 = json_array(); + five = json_integer(5); + seven = json_integer(7); + + if(!array1 || !array2) + fail("unable to create array"); + if(!five || !seven) + fail("unable to create integer"); + + for(i = 0; i < 10; i++) { + if(json_array_append(array1, five)) + fail("unable to append"); + } + for(i = 0; i < 10; i++) { + if(json_array_append(array2, seven)) + fail("unable to append"); + } + + if(json_array_size(array1) != 10 || json_array_size(array2) != 10) + fail("array size is invalid after appending"); + + if(json_array_extend(array1, array2)) + fail("unable to extend"); + + for(i = 0; i < 10; i++) { + if(json_array_get(array1, i) != five) + fail("invalid array contents after extending"); + } + for(i = 10; i < 20; i++) { + if(json_array_get(array1, i) != seven) + fail("invalid array contents after extending"); + } + + json_decref(five); + json_decref(seven); + json_decref(array1); + json_decref(array2); +} + + +int main() +{ + test_misc(); + test_insert(); + test_remove(); + test_clear(); + test_extend(); return 0; } diff --git a/test/testprogs/util.h b/test/testprogs/util.h index 6e518a2..ec8e0e4 100644 --- a/test/testprogs/util.h +++ b/test/testprogs/util.h @@ -8,10 +8,13 @@ #ifndef TESTPROGS_UTIL_H #define TESTPROGS_UTIL_H +#include + #define fail(msg) \ do { \ - fprintf(stderr, "%s:%d: %s\n", __FILE__, __LINE__, msg); \ - return 1; \ + fprintf(stderr, "%s:%s:%d: %s\n", \ + __FILE__, __FUNCTION__, __LINE__, msg); \ + exit(1); \ } while(0) #endif