add cxJsonArrIter() - fixes #524

Fri, 20 Dec 2024 16:51:01 +0100

author
Mike Becker <universe@uap-core.de>
date
Fri, 20 Dec 2024 16:51:01 +0100
changeset 1033
e3009345984b
parent 1032
aaad28e23dac
child 1034
424b5b74a68f

add cxJsonArrIter() - fixes #524

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/src/cx/json.h	Fri Dec 20 15:15:18 2024 +0100
+++ b/src/cx/json.h	Fri Dec 20 16:51:01 2024 +0100
@@ -759,7 +759,7 @@
 /**
  * Obtains a C string from the given JSON value.
  *
- * If the value is not a string, the behavior is undefined.
+ * If the \p value is not a string, the behavior is undefined.
  *
  * @param value the JSON value
  * @return the value represented as C string
@@ -774,7 +774,7 @@
 /**
  * Obtains a UCX string from the given JSON value.
  *
- * If the value is not a string, the behavior is undefined.
+ * If the \p value is not a string, the behavior is undefined.
  *
  * @param value the JSON value
  * @return the value represented as UCX string
@@ -788,7 +788,7 @@
 /**
  * Obtains a mutable UCX string from the given JSON value.
  *
- * If the value is not a string, the behavior is undefined.
+ * If the \p value is not a string, the behavior is undefined.
  *
  * @param value the JSON value
  * @return the value represented as mutable UCX string
@@ -802,7 +802,7 @@
 /**
  * Obtains a double-precision floating point value from the given JSON value.
  *
- * If the value is not a JSON number, the behavior is undefined.
+ * If the \p value is not a JSON number, the behavior is undefined.
  *
  * @param value the JSON value
  * @return the value represented as double
@@ -820,7 +820,7 @@
 /**
  * Obtains a 64-bit signed integer from the given JSON value.
  *
- * If the value is not a JSON number, the behavior is undefined.
+ * If the \p value is not a JSON number, the behavior is undefined.
  * If it is a JSON number, but not an integer, the value will be
  * converted to an integer, possibly losing precision.
  *
@@ -841,7 +841,7 @@
 /**
  * Obtains a Boolean value from the given JSON value.
  *
- * If the value is not a JSON literal, the behavior is undefined.
+ * If the \p value is not a JSON literal, the behavior is undefined.
  * The \c null literal is interpreted as \c false.
  *
  * @param value the JSON value
@@ -856,7 +856,7 @@
 /**
  * Returns the size of a JSON array.
  *
- * If the value is not a JSON array, the behavior is undefined.
+ * If the \p value is not a JSON array, the behavior is undefined.
  *
  * @param value the JSON value
  * @return the size of the array
@@ -870,7 +870,7 @@
 /**
  * Returns an element from a JSON array.
  *
- * If the value is not a JSON array, the behavior is undefined.
+ * If the \p value is not a JSON array, the behavior is undefined.
  *
  * This function guarantees to return a value. If the index is
  * out of bounds, the returned value will be of type
@@ -886,9 +886,24 @@
 CxJsonValue *cxJsonArrGet(const CxJsonValue *value, size_t index);
 
 /**
+ * Returns an iterator over the JSON array elements.
+ *
+ * The iterator yields values of type \c CxJsonValue* .
+ *
+ * If the \p value is not a JSON array, the behavior is undefined.
+ *
+ * @param value the JSON value
+ * @return an iterator over the array elements
+ * @see cxJsonIsArray()
+ */
+cx_attr_nonnull
+cx_attr_nodiscard
+CxIterator cxJsonArrIter(const CxJsonValue *value);
+
+/**
  * Returns a value corresponding to a key in a JSON object.
  *
- * If the value is not a JSON object, the behavior is undefined.
+ * If the \p value is not a JSON object, the behavior is undefined.
  *
  * This function guarantees to return a JSON value. If the
  * object does not contain \p name, the returned JSON value
--- a/src/json.c	Fri Dec 20 15:15:18 2024 +0100
+++ b/src/json.c	Fri Dec 20 16:51:01 2024 +0100
@@ -674,6 +674,39 @@
     return value->value.array.array[index];
 }
 
+static void *cx_json_iter_current(const void *it) {
+    const CxIterator *iter = it;
+    return *(CxJsonValue**)iter->elem_handle;
+}
+
+static bool cx_json_iter_valid(const void *it) {
+    const CxIterator *iter = it;
+    return iter->index < iter->elem_count;
+}
+
+static void cx_json_iter_next(void *it) {
+    CxIterator *iter = it;
+    iter->index++;
+    iter->elem_handle = (char *) iter->elem_handle + sizeof(void *);
+}
+
+CxIterator cxJsonArrIter(const CxJsonValue *value) {
+    CxIterator iter;
+
+    iter.index = 0;
+    iter.elem_count = value->value.array.array_size;
+    iter.src_handle.m = value->value.array.array;
+    iter.elem_handle = iter.src_handle.m;
+    iter.elem_size = sizeof(CxJsonValue*);
+    iter.base.valid = cx_json_iter_valid;
+    iter.base.current = cx_json_iter_current;
+    iter.base.next = cx_json_iter_next;
+    iter.base.remove = false;
+    iter.base.mutating = false;
+
+    return iter;
+}
+
 CxJsonValue *cxJsonObjGet(const CxJsonValue *value, const char *name) {
     const CxJsonObject *obj = &(value->value.object);
     // TODO: think about sorting the object so that we can use binary search here
--- a/tests/test_json.c	Fri Dec 20 15:15:18 2024 +0100
+++ b/tests/test_json.c	Fri Dec 20 16:51:01 2024 +0100
@@ -535,6 +535,27 @@
     cxJsonDestroy(&json);
 }
 
+CX_TEST(test_json_array_iterator) {
+    CxJson json;
+    cxJsonInit(&json, NULL);
+    CX_TEST_DO {
+        CxJsonValue *v;
+        CxJsonStatus result;
+        cxJsonFill(&json, "[ 0, 3, 6, 9, 12, 15 ]\n");
+        result = cxJsonNext(&json, &v);
+        CX_TEST_ASSERT(result == CX_JSON_NO_ERROR);
+        CX_TEST_ASSERT(cxJsonIsArray(v));
+        CxIterator iter = cxJsonArrIter(v);
+        unsigned i = 0;
+        cx_foreach(CxJsonValue*, elem, iter) {
+            CX_TEST_ASSERT(cxJsonIsNumber(elem));
+            CX_TEST_ASSERT(i == cxJsonAsInteger(elem));
+            i += 3;
+        }
+    }
+    cxJsonDestroy(&json);
+}
+
 CX_TEST(test_json_allocator) {
     CxTestingAllocator talloc;
     cx_testing_allocator_init(&talloc);
@@ -610,6 +631,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_iterator);
     cx_test_register(suite, test_json_allocator);
     cx_test_register(suite, test_json_allocator_parse_error);
     

mercurial