# HG changeset patch # User Mike Becker # Date 1734709861 -3600 # Node ID e3009345984b489c8cda4004e42a1427202e5bac # Parent aaad28e23dace657e24b90223d39e32d0039d186 add cxJsonArrIter() - fixes #524 diff -r aaad28e23dac -r e3009345984b src/cx/json.h --- 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 diff -r aaad28e23dac -r e3009345984b src/json.c --- 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 diff -r aaad28e23dac -r e3009345984b tests/test_json.c --- 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);