From a86d7a8f5aa5d47a315931fe11e9316a2be5045f Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Fri, 16 Apr 2021 16:12:22 +0300 Subject: [PATCH] json_object: introduce json_object_array_insert_idx() API function The behavior of the json_object_array_put_idx() is that, if a user wants to insert an element inside a JSON array, the element will be replaced. For some cases, a user would want to insert an element into the JSON array and shift the elements to the right. For indexes that are outside the length of the current array this behaves like json_object_array_put_idx(). If a user wants to enforce that the JSON array is not expanded, then the json_object_array_length() function can be used to guard against that. The main driver for this change is JSON patch, where the 'add' operation in an array means inserting a value at a certain index and shifting everything by one. Signed-off-by: Alexandru Ardelean --- arraylist.c | 21 +++++++++++++++++++++ arraylist.h | 2 ++ json-c.sym | 4 ++-- json_object.c | 6 ++++++ json_object.h | 19 +++++++++++++++++++ 5 files changed, 50 insertions(+), 2 deletions(-) diff --git a/arraylist.c b/arraylist.c index d8e12d1..bfc1425 100644 --- a/arraylist.c +++ b/arraylist.c @@ -125,6 +125,27 @@ int array_list_shrink(struct array_list *arr, size_t empty_slots) return 0; } +int array_list_insert_idx(struct array_list *arr, size_t idx, void *data) +{ + size_t move_amount; + + if (idx >= arr->length) + return array_list_put_idx(arr, idx, data); + + /* we're at full size, what size_t can support */ + if (arr->length == SIZE_T_MAX) + return -1; + + if (array_list_expand_internal(arr, arr->length + 1)) + return -1; + + move_amount = (arr->length - idx) * sizeof(void *); + memmove(arr->array + idx + 1, arr->array + idx, move_amount); + arr->array[idx] = data; + arr->length++; + return 0; +} + //static inline int _array_list_put_idx(struct array_list *arr, size_t idx, void *data) int array_list_put_idx(struct array_list *arr, size_t idx, void *data) { diff --git a/arraylist.h b/arraylist.h index f541706..a12f27f 100644 --- a/arraylist.h +++ b/arraylist.h @@ -62,6 +62,8 @@ extern void array_list_free(struct array_list *al); extern void *array_list_get_idx(struct array_list *al, size_t i); +extern int array_list_insert_idx(struct array_list *al, size_t i, void *data); + extern int array_list_put_idx(struct array_list *al, size_t i, void *data); extern int array_list_add(struct array_list *al, void *data); diff --git a/json-c.sym b/json-c.sym index 2867c80..de1fdeb 100644 --- a/json-c.sym +++ b/json-c.sym @@ -167,8 +167,8 @@ JSONC_0.15 { } JSONC_0.14; JSONC_0.16 { -# global: -# ...new symbols here... + global: + json_object_array_insert_idx; } JSONC_0.15; JSONC_0.17 { diff --git a/json_object.c b/json_object.c index 6894a93..c3974a0 100644 --- a/json_object.c +++ b/json_object.c @@ -1519,6 +1519,12 @@ int json_object_array_add(struct json_object *jso, struct json_object *val) return array_list_add(JC_ARRAY(jso)->c_array, val); } +int json_object_array_insert_idx(struct json_object *jso, size_t idx, struct json_object *val) +{ + assert(json_object_get_type(jso) == json_type_array); + return array_list_insert_idx(JC_ARRAY(jso)->c_array, idx, val); +} + int json_object_array_put_idx(struct json_object *jso, size_t idx, struct json_object *val) { assert(json_object_get_type(jso) == json_type_array); diff --git a/json_object.h b/json_object.h index 7633e64..97ef84c 100644 --- a/json_object.h +++ b/json_object.h @@ -622,6 +622,25 @@ JSON_EXPORT int json_object_array_add(struct json_object *obj, struct json_objec JSON_EXPORT int json_object_array_put_idx(struct json_object *obj, size_t idx, struct json_object *val); +/** Insert an element at a specified index in an array (a json_object of type json_type_array) + * + * The reference count will *not* be incremented. This is to make adding + * fields to objects in code more compact. If you want to retain a reference + * to an added object you must wrap the passed object with json_object_get + * + * The array size will be automatically be expanded to the size of the + * index if the index is larger than the current size. + * If the index is within the existing array limits, then the element will be + * inserted and all elements will be shifted. This is the only difference between + * this function and json_object_array_put_idx(). + * + * @param obj the json_object instance + * @param idx the index to insert the element at + * @param val the json_object to be added + */ +JSON_EXPORT int json_object_array_insert_idx(struct json_object *obj, size_t idx, + struct json_object *val); + /** Get the element at specified index of array `obj` (which must be a json_object of type json_type_array) * * *No* reference counts will be changed, and ownership of the returned