src/json.c

changeset 1594
4b9537f93239
parent 1592
c1e17411004f
--- a/src/json.c	Sat Dec 13 20:44:57 2025 +0100
+++ b/src/json.c	Sat Dec 13 20:47:07 2025 +0100
@@ -1482,3 +1482,78 @@
             // LCOV_EXCL_STOP
     }
 }
+
+CxJsonValue* cxJsonClone(const CxJsonValue* value, const CxAllocator* allocator) {
+    return cx_json_clone_func(NULL, value, allocator, NULL);
+}
+
+CxJsonValue* cx_json_clone_func(CxJsonValue* target, const CxJsonValue* source,
+        const CxAllocator* allocator, cx_attr_unused void *data) {
+    if (source == NULL || source->type == CX_JSON_NOTHING) {
+        return &cx_json_value_nothing;
+    }
+
+#define return_value(v) { \
+        CxJsonValue *ret = v; \
+        if (target == NULL) { \
+            return ret; \
+        } else { \
+            *target = *ret; \
+            cxFree(allocator, ret); \
+            return target; \
+        } \
+    }
+
+    switch (source->type) {
+        case CX_JSON_OBJECT: {
+            CxJsonValue *obj = cxJsonCreateObj(allocator);
+            if (obj == NULL) return NULL; // LCOV_EXCL_LINE
+            if (cxMapClone(obj->object, source->object, cxJsonCloneFunc, allocator, NULL)) {
+                // LCOV_EXCL_START
+                cxJsonValueFree(obj);
+                return NULL;
+                // LCOV_EXCL_STOP
+            }
+            return 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);
+            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;
+            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) {
+                    // LCOV_EXCL_START
+                    cxJsonValueFree(arr);
+                    return NULL;
+                    // LCOV_EXCL_STOP
+                }
+                arr->array.data[i] = e;
+            }
+            return arr;
+        }
+        case CX_JSON_STRING:
+            return_value(cxJsonCreateString(allocator, source->string));
+        case CX_JSON_INTEGER:
+            return_value(cxJsonCreateNumber(allocator, source->integer));
+        case CX_JSON_NUMBER:
+            return_value(cxJsonCreateNumber(allocator, source->number));
+        case CX_JSON_LITERAL:
+            return_value(cxJsonCreateLiteral(allocator, source->literal));
+        default:
+            // LCOV_EXCL_START
+            // unreachable
+            assert(false);
+            return NULL;
+            // LCOV_EXCL_STOP
+    }
+#undef return_value
+}

mercurial