add cxJsonArrayRemove() default tip

Thu, 14 Aug 2025 23:03:01 +0200

author
Mike Becker <universe@uap-core.de>
date
Thu, 14 Aug 2025 23:03:01 +0200
changeset 1337
6dfa1eb58ce3
parent 1336
5acc23b518aa

add cxJsonArrayRemove()

first part of issue #627

CHANGELOG file | annotate | diff | comparison | revisions
src/cx/json.h file | annotate | diff | comparison | revisions
src/json.c file | annotate | diff | comparison | revisions
tests/test_json.c file | annotate | diff | comparison | revisions
--- a/CHANGELOG	Sat Jul 19 21:09:07 2025 +0200
+++ b/CHANGELOG	Thu Aug 14 23:03:01 2025 +0200
@@ -13,6 +13,7 @@
  * adds cxTreeSize()
  * adds CX_PRIstr and CX_SFMT macros for formatting UCX strings
  * adds cx_strcpy() and cx_strcpy_a()
+ * adds cxJsonArrRemove()
  * adds cxStdlibAllocator and allows changes of cxDefaultAllocator
  * improves performance of the CxList array list implementation
  * changes cx_str() and cx_mutstr() to allow NULL strings
--- a/src/cx/json.h	Sat Jul 19 21:09:07 2025 +0200
+++ b/src/cx/json.h	Thu Aug 14 23:03:01 2025 +0200
@@ -1284,6 +1284,23 @@
 CxJsonValue *cxJsonArrGet(const CxJsonValue *value, size_t index);
 
 /**
+ * Removes an element from a JSON array.
+ *
+ * If the @p value is not a JSON array, the behavior is undefined.
+ *
+ * This function, in contrast to cxJsonArrayGet(), returns @c NULL
+ * when the index is out of bounds.
+ *
+ * @param value the JSON value
+ * @param index the index in the array
+ * @return the removed value from the specified index or @c NULL when the index was out of bounds
+ * @see cxJsonIsArray()
+ */
+cx_attr_nonnull
+cx_attr_export
+CxJsonValue *cxJsonArrRemove(CxJsonValue *value, size_t index);
+
+/**
  * Returns an iterator over the JSON array elements.
  *
  * The iterator yields values of type @c CxJsonValue* .
--- a/src/json.c	Sat Jul 19 21:09:07 2025 +0200
+++ b/src/json.c	Thu Aug 14 23:03:01 2025 +0200
@@ -1126,6 +1126,20 @@
     return value->value.array.array[index];
 }
 
+CxJsonValue *cxJsonArrRemove(CxJsonValue *value, size_t index) {
+    if (index >= value->value.array.array_size) {
+        return NULL;
+    }
+    CxJsonValue *ret = value->value.array.array[index];
+    // TODO: replace with a low level cx_array_remove()
+    size_t count = value->value.array.array_size - index - 1;
+    if (count > 0) {
+        memmove(value->value.array.array + index, value->value.array.array + index + 1, count * sizeof(CxJsonValue*));
+    }
+    value->value.array.array_size--;
+    return ret;
+}
+
 CxIterator cxJsonArrIter(const CxJsonValue *value) {
     return cxIteratorPtr(
         value->value.array.array,
--- a/tests/test_json.c	Sat Jul 19 21:09:07 2025 +0200
+++ b/tests/test_json.c	Thu Aug 14 23:03:01 2025 +0200
@@ -715,6 +715,39 @@
     cxJsonDestroy(&json);
 }
 
+CX_TEST(test_json_array) {
+    CxTestingAllocator talloc;
+    cx_testing_allocator_init(&talloc);
+    const CxAllocator *allocator = &talloc.base;
+    CX_TEST_DO {
+        CxJsonValue *arr = cxJsonCreateArr(allocator);
+        cxJsonArrAddIntegers(arr, (int64_t[]){ 0, 3, 6, 9, 12, 15}, 6);
+        CX_TEST_ASSERT(cxJsonArrSize(arr) == 6);
+        CxJsonValue *e = cxJsonArrGet(arr, 3);
+        CX_TEST_ASSERT(cxJsonIsNumber(e));
+        CX_TEST_ASSERT(cxJsonAsInteger(e) == 9);
+        CX_TEST_ASSERT(cxJsonAsDouble(e) == 9.0);
+        CX_TEST_ASSERT(cxJsonArrSize(arr) == 6);
+        e = cxJsonArrGet(arr, 6);
+        CX_TEST_ASSERT(!cxJsonIsNumber(e));
+        // also not null, because "nothing" is not null
+        CX_TEST_ASSERT(!cxJsonIsNull(e));
+        CX_TEST_ASSERT(e->type == CX_JSON_NOTHING);
+        CxJsonValue *removed = cxJsonArrRemove(arr, 2);
+        CX_TEST_ASSERT(cxJsonIsNumber(removed));
+        CX_TEST_ASSERT(cxJsonAsInteger(removed) == 6);
+        CX_TEST_ASSERT(cxJsonArrSize(arr) == 5);
+        e = cxJsonArrRemove(arr, 5);
+        CX_TEST_ASSERT(e == NULL);
+        cxJsonValueFree(arr);
+        // the removed element still needs to be freed
+        CX_TEST_ASSERT(!cx_testing_allocator_verify(&talloc));
+        cxJsonValueFree(removed);
+        CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
+    }
+    cx_testing_allocator_destroy(&talloc);
+}
+
 CX_TEST(test_json_array_iterator) {
     CxJson json;
     cxJsonInit(&json, NULL);
@@ -1199,6 +1232,7 @@
     cx_test_register(suite, test_json_number);
     cx_test_register(suite, test_json_number_format_errors);
     cx_test_register(suite, test_json_multiple_values);
+    cx_test_register(suite, test_json_array);
     cx_test_register(suite, test_json_array_iterator);
     cx_test_register(suite, test_json_allocator);
     cx_test_register(suite, test_json_allocator_parse_error);

mercurial