src/json.c

changeset 1607
0ecb13118cac
parent 1605
55b13f583356
--- 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) {

mercurial