use an anonymous union for the CxJsonValue

Sat, 06 Dec 2025 13:46:55 +0100

author
Mike Becker <universe@uap-core.de>
date
Sat, 06 Dec 2025 13:46:55 +0100
changeset 1543
7b66371d6da3
parent 1542
197450c2b0b3
child 1544
8fc6f4cdc5b0

use an anonymous union for the CxJsonValue

CHANGELOG file | annotate | diff | comparison | revisions
docs/Writerside/topics/about.md file | annotate | diff | comparison | revisions
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/CHANGELOG	Fri Dec 05 16:38:17 2025 +0100
+++ b/CHANGELOG	Sat Dec 06 13:46:55 2025 +0100
@@ -2,7 +2,8 @@
 ------------------------
 
  * adds cx_system_page_size() to allocator.h
- * change cxBufferReserve() to allow reducing the capacity
+ * changes cxBufferReserve() to allow reducing the capacity
+ * changes the members of CxJson and CxJsonValue
  * fix that cxReallocate(), cxReallocateArray(), cx_reallocate(), and cx_reallocatearray()
    were not returning zero after freeing the memory when passed a size of zero
 
--- a/docs/Writerside/topics/about.md	Fri Dec 05 16:38:17 2025 +0100
+++ b/docs/Writerside/topics/about.md	Sat Dec 06 13:46:55 2025 +0100
@@ -29,7 +29,8 @@
 ### Version 4.0 - preview {collapsible="true"}
 
 * adds cx_system_page_size() to allocator.h
-* change cxBufferReserve() to allow reducing the capacity
+* changes cxBufferReserve() to allow reducing the capacity
+* changes the members of CxJson and CxJsonValue
 * fix that cxReallocate(), cxReallocateArray(), cx_reallocate(), and cx_reallocatearray()
   were not returning zero after freeing the memory when passed a size of zero
 
--- a/src/cx/json.h	Fri Dec 05 16:38:17 2025 +0100
+++ b/src/cx/json.h	Sat Dec 06 13:46:55 2025 +0100
@@ -295,7 +295,7 @@
          * The literal type if the type is #CX_JSON_LITERAL.
          */
         CxJsonLiteral literal;
-    } value;
+    };
 };
 
 /**
@@ -1077,7 +1077,7 @@
  */
 cx_attr_nonnull
 CX_INLINE bool cxJsonIsBool(const CxJsonValue *value) {
-    return cxJsonIsLiteral(value) && value->value.literal != CX_JSON_NULL;
+    return cxJsonIsLiteral(value) && value->literal != CX_JSON_NULL;
 }
 
 /**
@@ -1094,7 +1094,7 @@
  */
 cx_attr_nonnull
 CX_INLINE bool cxJsonIsTrue(const CxJsonValue *value) {
-    return cxJsonIsLiteral(value) && value->value.literal == CX_JSON_TRUE;
+    return cxJsonIsLiteral(value) && value->literal == CX_JSON_TRUE;
 }
 
 /**
@@ -1111,7 +1111,7 @@
  */
 cx_attr_nonnull
 CX_INLINE bool cxJsonIsFalse(const CxJsonValue *value) {
-    return cxJsonIsLiteral(value) && value->value.literal == CX_JSON_FALSE;
+    return cxJsonIsLiteral(value) && value->literal == CX_JSON_FALSE;
 }
 
 /**
@@ -1124,7 +1124,7 @@
  */
 cx_attr_nonnull
 CX_INLINE bool cxJsonIsNull(const CxJsonValue *value) {
-    return cxJsonIsLiteral(value) && value->value.literal == CX_JSON_NULL;
+    return cxJsonIsLiteral(value) && value->literal == CX_JSON_NULL;
 }
 
 /**
@@ -1202,7 +1202,7 @@
  */
 cx_attr_nonnull
 CX_INLINE bool cxJsonAsBool(const CxJsonValue *value) {
-    return value->value.literal == CX_JSON_TRUE;
+    return value->literal == CX_JSON_TRUE;
 }
 
 /**
@@ -1216,7 +1216,7 @@
  */
 cx_attr_nonnull
 CX_INLINE size_t cxJsonArrSize(const CxJsonValue *value) {
-    return value->value.array.array_size;
+    return value->array.array_size;
 }
 
 /**
@@ -1277,7 +1277,7 @@
  */
 cx_attr_nonnull
 CX_INLINE size_t cxJsonObjSize(const CxJsonValue *value) {
-    return value->value.object.values_size;
+    return value->object.values_size;
 }
 
 /**
--- a/src/json.c	Fri Dec 05 16:38:17 2025 +0100
+++ b/src/json.c	Sat Dec 06 13:46:55 2025 +0100
@@ -52,8 +52,8 @@
     CxJsonObjValue kv_dummy;
     kv_dummy.name = cx_mutstrn((char*) name.ptr, name.length);
     return cx_array_binary_search(
-            obj->value.object.values,
-            obj->value.object.values_size,
+            obj->object.values,
+            obj->object.values_size,
             sizeof(CxJsonObjValue),
             &kv_dummy,
             json_cmp_objvalue
@@ -63,7 +63,7 @@
 static int json_add_objvalue(CxJsonValue *objv, CxJsonObjValue member) {
     assert(objv->type == CX_JSON_OBJECT);
     const CxAllocator * const al = objv->allocator;
-    CxJsonObject *obj = &(objv->value.object);
+    CxJsonObject *obj = &(objv->object);
 
     // determine the index where we need to insert the new member
     size_t index = cx_array_binary_search_sup(
@@ -534,13 +534,13 @@
     v->type = type;
     v->allocator = json->allocator;
     if (type == CX_JSON_ARRAY) {
-        cx_array_initialize_a(json->allocator, v->value.array.array, 16);
-        if (v->value.array.array == NULL) goto create_json_value_exit_error; // LCOV_EXCL_LINE
+        cx_array_initialize_a(json->allocator, v->array.array, 16);
+        if (v->array.array == NULL) goto create_json_value_exit_error; // LCOV_EXCL_LINE
     } else if (type == CX_JSON_OBJECT) {
-        cx_array_initialize_a(json->allocator, v->value.object.values, 16);
-        v->value.object.indices = cxCalloc(json->allocator, 16, sizeof(size_t));
-        if (v->value.object.values == NULL ||
-            v->value.object.indices == NULL)
+        cx_array_initialize_a(json->allocator, v->object.values, 16);
+        v->object.indices = cxCalloc(json->allocator, 16, sizeof(size_t));
+        if (v->object.values == NULL ||
+            v->object.indices == NULL)
             goto create_json_value_exit_error; // LCOV_EXCL_LINE
     }
 
@@ -550,7 +550,7 @@
         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->value.array.array, v)) {
+            if (cx_array_simple_add_a(&value_realloc, parent->array.array, v)) {
                 goto create_json_value_exit_error; // LCOV_EXCL_LINE
             }
         } else if (parent->type == CX_JSON_OBJECT) {
@@ -720,7 +720,7 @@
                 if (str.ptr == NULL) {
                     return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE
                 }
-                vbuf->value.string = str;
+                vbuf->string = str;
                 return_rec(CX_JSON_NO_ERROR);
             }
             case CX_JSON_TOKEN_INTEGER:
@@ -730,11 +730,11 @@
                     return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE
                 }
                 if (type == CX_JSON_INTEGER) {
-                    if (cx_strtoi64(token.content, &vbuf->value.integer, 10)) {
+                    if (cx_strtoi64(token.content, &vbuf->integer, 10)) {
                         return_rec(CX_JSON_FORMAT_ERROR_NUMBER);
                     }
                 } else {
-                    if (cx_strtod(token.content, &vbuf->value.number)) {
+                    if (cx_strtod(token.content, &vbuf->number)) {
                         // TODO: at the moment this is unreachable, because the tokenizer is already stricter than cx_strtod()
                         return_rec(CX_JSON_FORMAT_ERROR_NUMBER);  // LCOV_EXCL_LINE
                     }
@@ -746,11 +746,11 @@
                     return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE
                 }
                 if (0 == cx_strcmp(cx_strcast(token.content), cx_str("true"))) {
-                    vbuf->value.literal = CX_JSON_TRUE;
+                    vbuf->literal = CX_JSON_TRUE;
                 } else if (0 == cx_strcmp(cx_strcast(token.content), cx_str("false"))) {
-                    vbuf->value.literal = CX_JSON_FALSE;
+                    vbuf->literal = CX_JSON_FALSE;
                 } else {
-                    vbuf->value.literal = CX_JSON_NULL;
+                    vbuf->literal = CX_JSON_NULL;
                 }
                 return_rec(CX_JSON_NO_ERROR);
             }
@@ -864,7 +864,7 @@
     if (value == NULL || value->type == CX_JSON_NOTHING) return;
     switch (value->type) {
         case CX_JSON_OBJECT: {
-            CxJsonObject obj = value->value.object;
+            CxJsonObject obj = value->object;
             for (size_t i = 0; i < obj.values_size; i++) {
                 cxJsonValueFree(obj.values[i].value);
                 cx_strfree_a(value->allocator, &obj.values[i].name);
@@ -874,7 +874,7 @@
             break;
         }
         case CX_JSON_ARRAY: {
-            CxJsonArray array = value->value.array;
+            CxJsonArray array = value->array;
             for (size_t i = 0; i < array.array_size; i++) {
                 cxJsonValueFree(array.array[i]);
             }
@@ -882,7 +882,7 @@
             break;
         }
         case CX_JSON_STRING: {
-            cxFree(value->allocator, value->value.string.ptr);
+            cxFree(value->allocator, value->string.ptr);
             break;
         }
         default: {
@@ -898,15 +898,15 @@
     if (v == NULL) return NULL;
     v->allocator = allocator;
     v->type = CX_JSON_OBJECT;
-    cx_array_initialize_a(allocator, v->value.object.values, 16);
-    if (v->value.object.values == NULL) { // LCOV_EXCL_START
+    cx_array_initialize_a(allocator, v->object.values, 16);
+    if (v->object.values == NULL) { // LCOV_EXCL_START
         cxFree(allocator, v);
         return NULL;
         // LCOV_EXCL_STOP
     }
-    v->value.object.indices = cxCalloc(allocator, 16, sizeof(size_t));
-    if (v->value.object.indices == NULL) { // LCOV_EXCL_START
-        cxFree(allocator, v->value.object.values);
+    v->object.indices = cxCalloc(allocator, 16, sizeof(size_t));
+    if (v->object.indices == NULL) { // LCOV_EXCL_START
+        cxFree(allocator, v->object.values);
         cxFree(allocator, v);
         return NULL;
         // LCOV_EXCL_STOP
@@ -920,8 +920,8 @@
     if (v == NULL) return NULL;
     v->allocator = allocator;
     v->type = CX_JSON_ARRAY;
-    cx_array_initialize_a(allocator, v->value.array.array, 16);
-    if (v->value.array.array == NULL) { cxFree(allocator, v); return NULL; }
+    cx_array_initialize_a(allocator, v->array.array, 16);
+    if (v->array.array == NULL) { cxFree(allocator, v); return NULL; }
     return v;
 }
 
@@ -931,7 +931,7 @@
     if (v == NULL) return NULL;
     v->allocator = allocator;
     v->type = CX_JSON_NUMBER;
-    v->value.number = num;
+    v->number = num;
     return v;
 }
 
@@ -941,7 +941,7 @@
     if (v == NULL) return NULL;
     v->allocator = allocator;
     v->type = CX_JSON_INTEGER;
-    v->value.integer = num;
+    v->integer = num;
     return v;
 }
 
@@ -953,7 +953,7 @@
     v->type = CX_JSON_STRING;
     cxmutstr s = cx_strdup_a(allocator, str);
     if (s.ptr == NULL) { cxFree(allocator, v); return NULL; }
-    v->value.string = s;
+    v->string = s;
     return v;
 }
 
@@ -963,7 +963,7 @@
     if (v == NULL) return NULL;
     v->allocator = allocator;
     v->type = CX_JSON_LITERAL;
-    v->value.literal = lit;
+    v->literal = lit;
     return v;
 }
 
@@ -1042,8 +1042,8 @@
     CxArrayReallocator value_realloc = cx_array_reallocator(arr->allocator, NULL);
     assert(arr->type == CX_JSON_ARRAY);
     return cx_array_simple_copy_a(&value_realloc,
-            arr->value.array.array,
-            arr->value.array.array_size,
+            arr->array.array,
+            arr->array.array_size,
             val, count
     );
 }
@@ -1105,90 +1105,90 @@
 }
 
 CxJsonValue *cxJsonArrGet(const CxJsonValue *value, size_t index) {
-    if (index >= value->value.array.array_size) {
+    if (index >= value->array.array_size) {
         return &cx_json_value_nothing;
     }
-    return value->value.array.array[index];
+    return value->array.array[index];
 }
 
 CxJsonValue *cxJsonArrRemove(CxJsonValue *value, size_t index) {
-    if (index >= value->value.array.array_size) {
+    if (index >= value->array.array_size) {
         return NULL;
     }
-    CxJsonValue *ret = value->value.array.array[index];
+    CxJsonValue *ret = value->array.array[index];
     // TODO: replace with a low level cx_array_remove()
-    size_t count = value->value.array.array_size - index - 1;
+    size_t count = value->array.array_size - index - 1;
     if (count > 0) {
-        memmove(value->value.array.array + index, value->value.array.array + index + 1, count * sizeof(CxJsonValue*));
+        memmove(value->array.array + index, value->array.array + index + 1, count * sizeof(CxJsonValue*));
     }
-    value->value.array.array_size--;
+    value->array.array_size--;
     return ret;
 }
 
 char *cxJsonAsString(const CxJsonValue *value) {
-    return value->value.string.ptr;
+    return value->string.ptr;
 }
 
 cxstring cxJsonAsCxString(const CxJsonValue *value) {
-    return cx_strcast(value->value.string);
+    return cx_strcast(value->string);
 }
 
 cxmutstr cxJsonAsCxMutStr(const CxJsonValue *value) {
-    return value->value.string;
+    return value->string;
 }
 
 double cxJsonAsDouble(const CxJsonValue *value) {
     if (value->type == CX_JSON_INTEGER) {
-        return (double) value->value.integer;
+        return (double) value->integer;
     } else {
-        return value->value.number;
+        return value->number;
     }
 }
 
 int64_t cxJsonAsInteger(const CxJsonValue *value) {
     if (value->type == CX_JSON_INTEGER) {
-        return value->value.integer;
+        return value->integer;
     } else {
-        return (int64_t) value->value.number;
+        return (int64_t) value->number;
     }
 }
 
 CxIterator cxJsonArrIter(const CxJsonValue *value) {
     return cxIteratorPtr(
-        value->value.array.array,
-        value->value.array.array_size,
+        value->array.array,
+        value->array.array_size,
         true // arrays need to keep order
     );
 }
 
 CxIterator cxJsonObjIter(const CxJsonValue *value) {
     return cxIterator(
-        value->value.object.values,
+        value->object.values,
         sizeof(CxJsonObjValue),
-        value->value.object.values_size,
+        value->object.values_size,
         true // TODO: objects do not always need to keep order
     );
 }
 
 CxJsonValue *cx_json_obj_get(const CxJsonValue *value, cxstring name) {
     size_t index = json_find_objvalue(value, name);
-    if (index >= value->value.object.values_size) {
+    if (index >= value->object.values_size) {
         return &cx_json_value_nothing;
     } else {
-        return value->value.object.values[index].value;
+        return value->object.values[index].value;
     }
 }
 
 CxJsonValue *cx_json_obj_remove(CxJsonValue *value, cxstring name) {
     size_t index = json_find_objvalue(value, name);
-    if (index >= value->value.object.values_size) {
+    if (index >= value->object.values_size) {
         return NULL;
     } else {
-        CxJsonObjValue kv = value->value.object.values[index];
+        CxJsonObjValue kv = value->object.values[index];
         cx_strfree_a(value->allocator, &kv.name);
         // TODO: replace with cx_array_remove() / cx_array_remove_fast()
-        value->value.object.values_size--;
-        memmove(value->value.object.values + index, value->value.object.values + index + 1, (value->value.object.values_size - index) * sizeof(CxJsonObjValue));
+        value->object.values_size--;
+        memmove(value->object.values + index, value->object.values + index + 1, (value->object.values_size - index) * sizeof(CxJsonObjValue));
         return kv.value;
     }
 }
@@ -1272,13 +1272,13 @@
                 expected++;
             }
             depth++;
-            size_t elem_count = value->value.object.values_size;
+            size_t elem_count = value->object.values_size;
             for (size_t look_idx = 0; look_idx < elem_count; look_idx++) {
                 // get the member either via index array or directly
                 size_t elem_idx = settings->sort_members
                                       ? look_idx
-                                      : value->value.object.indices[look_idx];
-                CxJsonObjValue *member = &value->value.object.values[elem_idx];
+                                      : value->object.indices[look_idx];
+                CxJsonObjValue *member = &value->object.values[elem_idx];
 
                 // possible indentation
                 if (settings->pretty) {
@@ -1361,13 +1361,13 @@
         }
         case CX_JSON_STRING: {
             actual += wfunc("\"", 1, 1, target);
-            cxmutstr str = escape_string(value->value.string, settings->escape_slash);
+            cxmutstr str = escape_string(value->string, settings->escape_slash);
             actual += wfunc(str.ptr, 1, str.length, target);
-            if (str.ptr != value->value.string.ptr) {
+            if (str.ptr != value->string.ptr) {
                 cx_strfree(&str);
             }
             actual += wfunc("\"", 1, 1, target);
-            expected += 2 + value->value.string.length;
+            expected += 2 + value->string.length;
             break;
         }
         case CX_JSON_NUMBER: {
@@ -1375,7 +1375,7 @@
             // because of the way how %g is defined, we need to
             // double the precision and truncate ourselves
             precision = 1 + (precision > 15 ? 30 : 2 * precision);
-            snprintf(numbuf, 40, "%.*g", precision, value->value.number);
+            snprintf(numbuf, 40, "%.*g", precision, value->number);
             char *dot, *exp;
             unsigned char max_digits;
             // find the decimal separator and hope that it's one of . or ,
@@ -1439,17 +1439,17 @@
             break;
         }
         case CX_JSON_INTEGER: {
-            snprintf(numbuf, 32, "%" PRIi64, value->value.integer);
+            snprintf(numbuf, 32, "%" PRIi64, value->integer);
             size_t len = strlen(numbuf);
             actual += wfunc(numbuf, 1, len, target);
             expected += len;
             break;
         }
         case CX_JSON_LITERAL: {
-            if (value->value.literal == CX_JSON_TRUE) {
+            if (value->literal == CX_JSON_TRUE) {
                 actual += wfunc("true", 1, 4, target);
                 expected += 4;
-            } else if (value->value.literal == CX_JSON_FALSE) {
+            } else if (value->literal == CX_JSON_FALSE) {
                 actual += wfunc("false", 1, 5, target);
                 expected += 5;
             } else {
--- a/tests/test_json.c	Fri Dec 05 16:38:17 2025 +0100
+++ b/tests/test_json.c	Sat Dec 06 13:46:55 2025 +0100
@@ -239,8 +239,8 @@
         
         CxJsonValue *mixed2 = cxJsonObjGet(obj, "mixed2");
         char test[16];
-        strncpy(test, mixed2->value.string.ptr, 15);
-       CX_TEST_ASSERT(cxJsonIsString(mixed2));
+        strncpy(test, mixed2->string.ptr, 15);
+        CX_TEST_ASSERT(cxJsonIsString(mixed2));
         CX_TEST_ASSERT(0 == cx_strcmp(
             cxJsonAsCxString(mixed2),
             "123\xce\xa3\xf0\x9f\xaf\x85ß")
@@ -1396,14 +1396,14 @@
         CX_TEST_ASSERT(0 == cx_strcmp(cx_strn(buf.space, buf.size), "3.141"));
 
         // test 6 digits, but two are left of the decimal point
-        num->value.number = 47.110815;
+        num->number = 47.110815;
         cxBufferReset(&buf);
         writer.frac_max_digits = 6;
         cxJsonWrite(&buf, num, cxBufferWriteFunc, &writer);
         CX_TEST_ASSERT(0 == cx_strcmp(cx_strn(buf.space, buf.size), "47.110815"));
 
         // test 4 digits with exponent
-        num->value.number = 5.11223344e23;
+        num->number = 5.11223344e23;
         cxBufferReset(&buf);
         writer.frac_max_digits = 4;
         cxJsonWrite(&buf, num, cxBufferWriteFunc, &writer);

mercurial