--- a/src/json.c Sun Dec 14 21:14:34 2025 +0100 +++ b/src/json.c Sun Dec 14 23:17:48 2025 +0100 @@ -472,20 +472,20 @@ v->type = type; v->allocator = json->allocator; if (type == CX_JSON_ARRAY) { - cx_array_initialize_a(json->allocator, v->array.data, 16); - if (v->array.data == NULL) goto create_json_value_exit_error; // LCOV_EXCL_LINE + if (cx_array_init_a(json->allocator, v->array, 16)) { + goto create_json_value_exit_error; // LCOV_EXCL_LINE + } } else if (type == CX_JSON_OBJECT) { v->object = json_create_object_map(json->allocator); if (v->object == NULL) goto create_json_value_exit_error; // LCOV_EXCL_LINE } // add the new value to a possible parent - if (json->vbuf_size > 0) { - CxJsonValue *parent = json->vbuf[json->vbuf_size - 1]; + if (json->vbuf.size > 0) { + CxJsonValue *parent = json->vbuf.data[json->vbuf.size - 1]; assert(parent != NULL); if (parent->type == CX_JSON_ARRAY) { - CxArrayReallocator value_realloc = cx_array_reallocator(json->allocator, NULL); - if (cx_array_simple_add_a(&value_realloc, parent->array.data, v)) { + if (cx_array_add_a(json->allocator, parent->array, &v)) { goto create_json_value_exit_error; // LCOV_EXCL_LINE } } else if (parent->type == CX_JSON_OBJECT) { @@ -503,10 +503,19 @@ // add the new value to the stack, if it is an array or object if (type == CX_JSON_ARRAY || type == CX_JSON_OBJECT) { - CxArrayReallocator vbuf_realloc = cx_array_reallocator(NULL, json->vbuf_internal); - if (cx_array_simple_add_a(&vbuf_realloc, json->vbuf, v)) { - goto create_json_value_exit_error; // LCOV_EXCL_LINE + if (json->vbuf.size >= json->vbuf.capacity) { + int alloc_error; + if (json->vbuf.data == json->vbuf_internal) { + alloc_error = cx_array_move_to_new(json->vbuf, json->vbuf.size+1); + } else { + alloc_error = cx_array_reserve(json->vbuf, json->vbuf.size+1); + } + if (alloc_error) { + goto create_json_value_exit_error; // LCOV_EXCL_LINE + } } + json->vbuf.data[json->vbuf.size] = v; + json->vbuf.size++; } // if currently no value is parsed, this is now the value of interest @@ -540,22 +549,22 @@ memset(json, 0, sizeof(CxJson)); json->allocator = allocator; - json->states = json->states_internal; - json->states_capacity = cx_nmemb(json->states_internal); - json->states[0] = JP_STATE_VALUE_BEGIN; - json->states_size = 1; + json->states.data = json->states_internal; + json->states.capacity = cx_nmemb(json->states_internal); + json->states.data[0] = JP_STATE_VALUE_BEGIN; + json->states.size = 1; - json->vbuf = json->vbuf_internal; - json->vbuf_capacity = cx_nmemb(json->vbuf_internal); + json->vbuf.data = json->vbuf_internal; + json->vbuf.capacity = cx_nmemb(json->vbuf_internal); } void cxJsonDestroy(CxJson *json) { cxBufferDestroy(&json->buffer); - if (json->states != json->states_internal) { - cxFreeDefault(json->states); + if (json->states.data != json->states_internal) { + cx_array_free(json->states); } - if (json->vbuf != json->vbuf_internal) { - cxFreeDefault(json->vbuf); + if (json->vbuf.data != json->vbuf_internal) { + cx_array_free(json->vbuf); } cxJsonValueFree(json->parsed); json->parsed = NULL; @@ -584,9 +593,9 @@ } static void json_add_state(CxJson *json, int state) { - // we have guaranteed the necessary space with cx_array_simple_reserve() + // we have guaranteed the necessary space // therefore, we can safely add the state in the simplest way possible - json->states[json->states_size++] = state; + json->states.data[json->states.size++] = state; } #define return_rec(code) \ @@ -607,13 +616,21 @@ } // pop the current state - assert(json->states_size > 0); - int state = json->states[--json->states_size]; + assert(json->states.size > 0); + int state = json->states.data[--json->states.size]; - // guarantee that at least two more states fit on the stack - CxArrayReallocator state_realloc = cx_array_reallocator(NULL, json->states_internal); - if (cx_array_simple_reserve_a(&state_realloc, json->states, 2)) { - return CX_JSON_BUFFER_ALLOC_FAILED; // LCOV_EXCL_LINE + // guarantee that at least two more states fit into the array + const size_t required_states_depth = json->states.size + 2; + if (required_states_depth >= json->states.capacity) { + int alloc_error; + if (json->states.data == json->states_internal) { + alloc_error = cx_array_move_to_new(json->states, required_states_depth); + } else { + alloc_error = cx_array_reserve(json->states, required_states_depth); + } + if (alloc_error) { + return CX_JSON_BUFFER_ALLOC_FAILED; // LCOV_EXCL_LINE + } } @@ -648,8 +665,8 @@ case CX_JSON_TOKEN_END_ARRAY: { if (state == JP_STATE_VALUE_BEGIN_AR) { // discard the array from the value buffer - json->vbuf_size--; - json->states_size--; + json->vbuf.size--; + json->states.size--; return_rec(CX_JSON_NO_ERROR); } else { return_rec(CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN); @@ -708,7 +725,7 @@ return_rec(CX_JSON_NO_ERROR); } else if (token.tokentype == CX_JSON_TOKEN_END_ARRAY) { // discard the array from the value buffer - json->vbuf_size--; + json->vbuf.size--; return_rec(CX_JSON_NO_ERROR); } else { return_rec(CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN); @@ -716,7 +733,7 @@ } else if (state == JP_STATE_OBJ_NAME_OR_CLOSE || state == JP_STATE_OBJ_NAME) { if (state == JP_STATE_OBJ_NAME_OR_CLOSE && token.tokentype == CX_JSON_TOKEN_END_OBJECT) { // discard the obj from the value buffer - json->vbuf_size--; + json->vbuf.size--; return_rec(CX_JSON_NO_ERROR); } else { // expect string @@ -731,7 +748,7 @@ } assert(json->uncompleted_member_name.ptr == NULL); json->uncompleted_member_name = name; - assert(json->vbuf_size > 0); + assert(json->vbuf.size > 0); // next state json_add_state(json, JP_STATE_OBJ_COLON); @@ -752,7 +769,7 @@ return_rec(CX_JSON_NO_ERROR); } else if (token.tokentype == CX_JSON_TOKEN_END_OBJECT) { // discard the obj from the value buffer - json->vbuf_size--; + json->vbuf.size--; return_rec(CX_JSON_NO_ERROR); } else { return_rec(CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN); @@ -777,17 +794,17 @@ CxJsonStatus result; do { result = json_parse(json); - if (result == CX_JSON_NO_ERROR && json->states_size == 1) { + if (result == CX_JSON_NO_ERROR && json->states.size == 1) { // final state reached - assert(json->states[0] == JP_STATE_VALUE_END); - assert(json->vbuf_size == 0); + assert(json->states.data[0] == JP_STATE_VALUE_END); + assert(json->vbuf.size == 0); // write output value *value = json->parsed; json->parsed = NULL; // re-initialize state machine - json->states[0] = JP_STATE_VALUE_BEGIN; + json->states.data[0] = JP_STATE_VALUE_BEGIN; return CX_JSON_NO_ERROR; } @@ -796,7 +813,7 @@ // the parser might think there is no data // but when we did not reach the final state, // we know that there must be more to come - if (result == CX_JSON_NO_DATA && json->states_size > 1) { + if (result == CX_JSON_NO_DATA && json->states.size > 1) { return CX_JSON_INCOMPLETE_DATA; } @@ -842,11 +859,10 @@ break; } case CX_JSON_ARRAY: { - CxJsonArray array = value->array; - for (size_t i = 0; i < array.data_size; i++) { - cxJsonValueFree(array.data[i]); + for (size_t i = 0; i < value->array.size; i++) { + cxJsonValueFree(value->array.data[i]); } - cxFree(value->allocator, array.data); + cx_array_free_a(value->allocator, value->array); break; } case CX_JSON_STRING: { @@ -875,14 +891,23 @@ return v; } -CxJsonValue* cxJsonCreateArr(const CxAllocator* allocator) { +CxJsonValue* cxJsonCreateArr(const CxAllocator* allocator, size_t capacity) { if (allocator == NULL) allocator = cxDefaultAllocator; CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue)); if (v == NULL) return NULL; v->allocator = allocator; v->type = CX_JSON_ARRAY; - cx_array_initialize_a(allocator, v->array.data, 16); - if (v->array.data == NULL) { cxFree(allocator, v); return NULL; } + if (capacity > 0) { + if (cx_array_init_a(allocator, v->array, capacity)) { + // LCOV_EXCL_START + cxFree(allocator, v); + return NULL; + // LCOV_EXCL_STOP + } + } else { + v->array.data = NULL; + v->array.size = v->array.capacity = 0; + } return v; } @@ -1000,13 +1025,8 @@ } int cxJsonArrAddValues(CxJsonValue* arr, CxJsonValue* const* val, size_t count) { - CxArrayReallocator value_realloc = cx_array_reallocator(arr->allocator, NULL); assert(arr->type == CX_JSON_ARRAY); - return cx_array_simple_copy_a(&value_realloc, - arr->array.data, - arr->array.data_size, - val, count - ); + return cx_array_add_array_a(arr->allocator, arr->array, val, count); } int cx_json_obj_put(CxJsonValue* obj, cxstring name, CxJsonValue* child) { @@ -1020,8 +1040,8 @@ return v; } -CxJsonValue* cx_json_obj_put_arr(CxJsonValue* obj, cxstring name) { - CxJsonValue* v = cxJsonCreateArr(obj->allocator); +CxJsonValue* cx_json_obj_put_arr(CxJsonValue* obj, cxstring name, size_t capacity) { + CxJsonValue* v = cxJsonCreateArr(obj->allocator, capacity); if (v == NULL) return NULL; if (cxJsonObjPut(obj, name, v)) { cxJsonValueFree(v); return NULL; } return v; @@ -1056,23 +1076,23 @@ } CxJsonValue *cxJsonArrGet(const CxJsonValue *value, size_t index) { - if (index >= value->array.data_size) { + if (index >= value->array.size) { return &cx_json_value_nothing; } return value->array.data[index]; } CxJsonValue *cxJsonArrRemove(CxJsonValue *value, size_t index) { - if (index >= value->array.data_size) { + if (index >= value->array.size) { return NULL; } CxJsonValue *ret = value->array.data[index]; // TODO: replace with a low level cx_array_remove() - size_t count = value->array.data_size - index - 1; + size_t count = value->array.size - index - 1; if (count > 0) { memmove(value->array.data + index, value->array.data + index + 1, count * sizeof(CxJsonValue*)); } - value->array.data_size--; + value->array.size--; return ret; } @@ -1105,11 +1125,7 @@ } CxIterator cxJsonArrIter(const CxJsonValue *value) { - return cxIteratorPtr( - value->array.data, - value->array.data_size, - true // arrays need to keep order - ); + return cx_array_iterator_ptr(value->array); } CxMapIterator cxJsonObjIter(const CxJsonValue *value) { @@ -1465,8 +1481,8 @@ case CX_JSON_OBJECT: return cxMapCompare(json->object, other->object); case CX_JSON_ARRAY: - if (json->array.data_size != other->array.data_size) return -1; - for (size_t i = 0; i < json->array.data_size; i++) { + if (json->array.size != other->array.size) return -1; + for (size_t i = 0; i < json->array.size; i++) { const int d = cxJsonCompare(json->array.data[i], other->array.data[i]); if (d != 0) return d; } @@ -1527,17 +1543,10 @@ return_value(obj); } case CX_JSON_ARRAY: { - const size_t elem_count = source->array.data_size; - CxArrayReallocator reallocator = cx_array_reallocator(allocator, NULL); - CxJsonValue *arr = cxJsonCreateArr(allocator); + const size_t elem_count = source->array.size; + CxJsonValue *arr = cxJsonCreateArr(allocator, elem_count); if (arr == NULL) return NULL; // LCOV_EXCL_LINE - if (cx_array_simple_reserve_a(&reallocator, arr->array.data, elem_count)) { - // LCOV_EXCL_START - cxJsonValueFree(arr); - return NULL; - // LCOV_EXCL_STOP - } - arr->array.data_size = elem_count; + arr->array.size = elem_count; for (size_t i = 0 ; i < elem_count ; i++) { CxJsonValue *e = cx_json_clone_func(NULL, source->array.data[i], allocator, NULL); if (e == NULL) {