ucx/cx/json.h

changeset 115
e57ca2747782
parent 113
dde28a806552
--- a/ucx/cx/json.h	Sun Dec 07 20:00:33 2025 +0100
+++ b/ucx/cx/json.h	Sat Dec 13 15:58:58 2025 +0100
@@ -41,6 +41,7 @@
 #include "string.h"
 #include "buffer.h"
 #include "array_list.h"
+#include "map.h"
 
 #include <string.h>
 
@@ -188,9 +189,10 @@
  */
 typedef struct cx_json_array_s CxJsonArray;
 /**
- * Type alias for the JSON object struct.
+ * Type alias for the map representing a JSON object.
+ * The map contains pointers of type @c CxJsonValue.
  */
-typedef struct cx_json_object_s CxJsonObject;
+typedef CxMap* CxJsonObject;
 /**
  * Type alias for a JSON string.
  */
@@ -209,46 +211,13 @@
 typedef enum cx_json_literal CxJsonLiteral;
 
 /**
- * Type alias for a key/value pair in a JSON object.
- */
-typedef struct cx_json_obj_value_s CxJsonObjValue;
-
-/**
  * JSON array structure.
  */
 struct cx_json_array_s {
     /**
      * The array data.
      */
-    CX_ARRAY_DECLARE(CxJsonValue*, array);
-};
-
-/**
- * JSON object structure.
- */
-struct cx_json_object_s {
-    /**
-     * The key/value entries.
-     */
-    CX_ARRAY_DECLARE(CxJsonObjValue, values);
-    /**
-     * The original indices to reconstruct the order in which the members were added.
-     */
-    size_t *indices;
-};
-
-/**
- * Structure for a key/value entry in a JSON object.
- */
-struct cx_json_obj_value_s {
-    /**
-     * The key (or name in JSON terminology) of the value.
-     */
-    cxmutstr name;
-    /**
-     * The value.
-     */
-    CxJsonValue *value;
+    CX_ARRAY_DECLARE(CxJsonValue*, data);
 };
 
 /**
@@ -295,7 +264,7 @@
          * The literal type if the type is #CX_JSON_LITERAL.
          */
         CxJsonLiteral literal;
-    } value;
+    };
 };
 
 /**
@@ -349,11 +318,11 @@
     CxJsonValue *parsed;
 
     /**
-     * A pointer to an intermediate state of a currently parsed object member.
+     * The name of a not yet completely parsed object member.
      *
      * Never access this value manually.
      */
-    CxJsonObjValue uncompleted_member;
+    cxmutstr uncompleted_member_name;
 
     /**
      * State stack.
@@ -439,10 +408,6 @@
      */
     bool pretty;
     /**
-     * Set false to output the members in the order in which they were added.
-     */
-    bool sort_members;
-    /**
      * The maximum number of fractional digits in a number value.
      * The default value is 6 and values larger than 15 are reduced to 15.
      * Note that the actual number of digits may be lower, depending on the concrete number.
@@ -508,6 +473,33 @@
 CX_EXPORT int cxJsonWrite(void* target, const CxJsonValue* value,
         cx_write_func wfunc, const CxJsonWriter* settings);
 
+
+/**
+ * Produces a compact string representation of the specified JSON value.
+ *
+ * @param value the JSON value
+ * @param allocator the allocator for the string
+ * @return the produced string
+ * @see cxJsonWrite()
+ * @see cxJsonWriterCompact()
+ * @see cxJsonToPrettyString()
+ */
+cx_attr_nonnull_arg(1)
+CX_EXPORT cxmutstr cxJsonToString(CxJsonValue *value, const CxAllocator *allocator);
+
+/**
+ * Produces a pretty string representation of the specified JSON value.
+ *
+ * @param value the JSON value
+ * @param allocator the allocator for the string
+ * @return the produced string
+ * @see cxJsonWrite()
+ * @see cxJsonWriterPretty()
+ * @see cxJsonToString()
+ */
+cx_attr_nonnull_arg(1)
+CX_EXPORT cxmutstr cxJsonToPrettyString(CxJsonValue *value, const CxAllocator *allocator);
+
 /**
  * Initializes the JSON interface.
  *
@@ -530,8 +522,8 @@
 /**
  * Destroys and re-initializes the JSON interface.
  *
- * You might want to use this to reset the parser after
- * encountering a syntax error.
+ * You must use this to reset the parser after encountering a syntax error
+ * if you want to continue using it.
  *
  * @param json the JSON interface
  */
@@ -556,7 +548,7 @@
  * @retval non-zero internal allocation error
  * @see cxJsonFill()
  */
-cx_attr_nonnull cx_attr_access_r(2, 3)
+cx_attr_nonnull_arg(1) cx_attr_access_r(2, 3)
 CX_EXPORT int cxJsonFilln(CxJson *json, const char *buf, size_t len);
 
 
@@ -592,6 +584,36 @@
  */
 #define cxJsonFill(json, str) cx_json_fill(json, cx_strcast(str))
 
+
+/**
+ * Internal function - use cxJsonFromString() instead.
+ *
+ * @param allocator the allocator for the JSON value
+ * @param str the string to parse
+ * @param value a pointer where the JSON value shall be stored to
+ * @return status code
+ */
+cx_attr_nonnull_arg(3)
+CX_EXPORT CxJsonStatus cx_json_from_string(const CxAllocator *allocator,
+            cxstring str, CxJsonValue **value);
+
+/**
+ * Parses a string into a JSON value.
+ *
+ * @param allocator (@c CxAllocator*) the allocator for the JSON value
+ * @param str (any string) the string to parse
+ * @param value (@c CxJsonValue**) a pointer where the JSON value shall be stored to
+ * @retval CX_JSON_NO_ERROR success
+ * @retval CX_JSON_NO_DATA the string was empty or blank
+ * @retval CX_JSON_INCOMPLETE_DATA the string unexpectedly ended
+ * @retval CX_JSON_BUFFER_ALLOC_FAILED allocating internal buffer space failed
+ * @retval CX_JSON_VALUE_ALLOC_FAILED allocating memory for the CxJsonValue failed
+ * @retval CX_JSON_FORMAT_ERROR_NUMBER the JSON text contains an illegally formatted number
+ * @retval CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN JSON syntax error
+ */
+#define cxJsonFromString(allocator, str, value) \
+        cx_json_from_string(allocator, cx_strcast(str), value)
+
 /**
  * Creates a new (empty) JSON object.
  *
@@ -641,28 +663,27 @@
 /**
  * Creates a new JSON string.
  *
+ * Internal function - use cxJsonCreateString() instead.
+ *
  * @param allocator the allocator to use
  * @param str the string data
  * @return the new JSON value or @c NULL if allocation fails
- * @see cxJsonCreateString()
  * @see cxJsonObjPutString()
- * @see cxJsonArrAddStrings()
+ * @see cxJsonArrAddCxStrings()
  */
-cx_attr_nodiscard cx_attr_nonnull_arg(2) cx_attr_cstr_arg(2)
-CX_EXPORT CxJsonValue* cxJsonCreateString(const CxAllocator* allocator, const char *str);
+cx_attr_nodiscard
+CX_EXPORT CxJsonValue* cx_json_create_string(const CxAllocator* allocator, cxstring str);
 
 /**
  * Creates a new JSON string.
  *
- * @param allocator the allocator to use
- * @param str the string data
- * @return the new JSON value or @c NULL if allocation fails
- * @see cxJsonCreateCxString()
- * @see cxJsonObjPutCxString()
+ * @param allocator (@c CxAllocator*) the allocator to use
+ * @param str the string
+ * @return (@c CxJsonValue*) the new JSON value or @c NULL if allocation fails
+ * @see cxJsonObjPutString()
  * @see cxJsonArrAddCxStrings()
  */
-cx_attr_nodiscard
-CX_EXPORT CxJsonValue* cxJsonCreateCxString(const CxAllocator* allocator, cxstring str);
+#define cxJsonCreateString(allocator, str) cx_json_create_string(allocator, cx_strcast(str))
 
 /**
  * Creates a new JSON literal.
@@ -760,10 +781,7 @@
 /**
  * Adds or replaces a value within a JSON object.
  *
- * The value will be directly added and not copied.
- *
- * @note If a value with the specified @p name already exists,
- * it will be (recursively) freed with its own allocator.
+ * Internal function - use cxJsonObjPut().
  *
  * @param obj the JSON object
  * @param name the name of the value
@@ -772,11 +790,29 @@
  * @retval non-zero allocation failure
  */
 cx_attr_nonnull
-CX_EXPORT int cxJsonObjPut(CxJsonValue* obj, cxstring name, CxJsonValue* child);
+CX_EXPORT int cx_json_obj_put(CxJsonValue* obj, cxstring name, CxJsonValue* child);
+
+/**
+ * Adds or replaces a value within a JSON object.
+ *
+ * The value will be directly added and not copied.
+ *
+ * @note If a value with the specified @p name already exists,
+ * it will be (recursively) freed with its own allocator.
+ *
+ * @param obj (@c CxJsonValue*) the JSON object
+ * @param name (any string) the name of the value
+ * @param child (@c CxJsonValue*) the value
+ * @retval zero success
+ * @retval non-zero allocation failure
+ */
+#define cxJsonObjPut(obj, name, child) cx_json_obj_put(obj, cx_strcast(name), child)
 
 /**
  * Creates a new JSON object and adds it to an existing object.
  *
+ * Internal function - use cxJsonObjPutObj().
+ *
  * @param obj the target JSON object
  * @param name the name of the new value
  * @return the new value or @c NULL if allocation fails
@@ -784,11 +820,24 @@
  * @see cxJsonCreateObj()
  */
 cx_attr_nonnull
-CX_EXPORT CxJsonValue* cxJsonObjPutObj(CxJsonValue* obj, cxstring name);
+CX_EXPORT CxJsonValue* cx_json_obj_put_obj(CxJsonValue* obj, cxstring name);
+
+/**
+ * Creates a new JSON object and adds it to an existing object.
+ *
+ * @param obj (@c CxJsonValue*) the target JSON object
+ * @param name (any string) the name of the new value
+ * @return (@c CxJsonValue*) the new value or @c NULL if allocation fails
+ * @see cxJsonObjPut()
+ * @see cxJsonCreateObj()
+ */
+#define cxJsonObjPutObj(obj, name) cx_json_obj_put_obj(obj, cx_strcast(name))
 
 /**
  * Creates a new JSON array and adds it to an object.
  *
+ * Internal function - use cxJsonObjPutArr().
+ *
  * @param obj the target JSON object
  * @param name the name of the new value
  * @return the new value or @c NULL if allocation fails
@@ -796,11 +845,24 @@
  * @see cxJsonCreateArr()
  */
 cx_attr_nonnull
-CX_EXPORT CxJsonValue* cxJsonObjPutArr(CxJsonValue* obj, cxstring name);
+CX_EXPORT CxJsonValue* cx_json_obj_put_arr(CxJsonValue* obj, cxstring name);
+
+/**
+ * Creates a new JSON array and adds it to an object.
+ *
+ * @param obj (@c CxJsonValue*) the target JSON object
+ * @param name (any string) the name of the new value
+ * @return (@c CxJsonValue*) the new value or @c NULL if allocation fails
+ * @see cxJsonObjPut()
+ * @see cxJsonCreateArr()
+ */
+#define cxJsonObjPutArr(obj, name) cx_json_obj_put_arr(obj, cx_strcast(name))
 
 /**
  * Creates a new JSON number and adds it to an object.
  *
+ * Internal function - use cxJsonObjPutNumber().
+ *
  * @param obj the target JSON object
  * @param name the name of the new value
  * @param num the numeric value
@@ -809,11 +871,25 @@
  * @see cxJsonCreateNumber()
  */
 cx_attr_nonnull
-CX_EXPORT CxJsonValue* cxJsonObjPutNumber(CxJsonValue* obj, cxstring name, double num);
+CX_EXPORT CxJsonValue* cx_json_obj_put_number(CxJsonValue* obj, cxstring name, double num);
+
+/**
+ * Creates a new JSON number and adds it to an object.
+ *
+ * @param obj (@c CxJsonValue*) the target JSON object
+ * @param name (any string) the name of the new value
+ * @param num (@c double) the numeric value
+ * @return (@c CxJsonValue*) the new value or @c NULL if allocation fails
+ * @see cxJsonObjPut()
+ * @see cxJsonCreateNumber()
+ */
+#define cxJsonObjPutNumber(obj, name, num) cx_json_obj_put_number(obj, cx_strcast(name), num)
 
 /**
  * Creates a new JSON number, based on an integer, and adds it to an object.
  *
+ * Internal function - use cxJsonObjPutInteger().
+ *
  * @param obj the target JSON object
  * @param name the name of the new value
  * @param num the numeric value
@@ -822,12 +898,24 @@
  * @see cxJsonCreateInteger()
  */
 cx_attr_nonnull
-CX_EXPORT CxJsonValue* cxJsonObjPutInteger(CxJsonValue* obj, cxstring name, int64_t num);
+CX_EXPORT CxJsonValue* cx_json_obj_put_integer(CxJsonValue* obj, cxstring name, int64_t num);
+
+/**
+ * Creates a new JSON number, based on an integer, and adds it to an object.
+ *
+ * @param obj (@c CxJsonValue*) the target JSON object
+ * @param name (any string) the name of the new value
+ * @param num (@c int64_t) the numeric value
+ * @return (@c CxJsonValue*) the new value or @c NULL if allocation fails
+ * @see cxJsonObjPut()
+ * @see cxJsonCreateInteger()
+ */
+#define cxJsonObjPutInteger(obj, name, num) cx_json_obj_put_integer(obj, cx_strcast(name), num)
 
 /**
  * Creates a new JSON string and adds it to an object.
  *
- * The string data is copied.
+ * Internal function - use cxJsonObjPutString()
  *
  * @param obj the target JSON object
  * @param name the name of the new value
@@ -836,27 +924,28 @@
  * @see cxJsonObjPut()
  * @see cxJsonCreateString()
  */
-cx_attr_nonnull cx_attr_cstr_arg(3)
-CX_EXPORT CxJsonValue* cxJsonObjPutString(CxJsonValue* obj, cxstring name, const char* str);
+cx_attr_nonnull
+CX_EXPORT CxJsonValue* cx_json_obj_put_string(CxJsonValue* obj, cxstring name, cxstring str);
 
 /**
  * Creates a new JSON string and adds it to an object.
  *
  * The string data is copied.
  *
- * @param obj the target JSON object
- * @param name the name of the new value
- * @param str the string data
- * @return the new value or @c NULL if allocation fails
+ * @param obj (@c CxJsonValue*) the target JSON object
+ * @param name (any string) the name of the new value
+ * @param str (any string) the string data
+ * @return (@c CxJsonValue*) the new value or @c NULL if allocation fails
  * @see cxJsonObjPut()
- * @see cxJsonCreateCxString()
+ * @see cxJsonCreateString()
  */
-cx_attr_nonnull
-CX_EXPORT CxJsonValue* cxJsonObjPutCxString(CxJsonValue* obj, cxstring name, cxstring str);
+#define cxJsonObjPutString(obj, name, str) cx_json_obj_put_string(obj, cx_strcast(name), cx_strcast(str))
 
 /**
  * Creates a new JSON literal and adds it to an object.
  *
+ * Internal function - use cxJsonObjPutLiteral().
+ *
  * @param obj the target JSON object
  * @param name the name of the new value
  * @param lit the type of literal
@@ -865,7 +954,19 @@
  * @see cxJsonCreateLiteral()
  */
 cx_attr_nonnull
-CX_EXPORT CxJsonValue* cxJsonObjPutLiteral(CxJsonValue* obj, cxstring name, CxJsonLiteral lit);
+CX_EXPORT CxJsonValue* cx_json_obj_put_literal(CxJsonValue* obj, cxstring name, CxJsonLiteral lit);
+
+/**
+ * Creates a new JSON literal and adds it to an object.
+ *
+ * @param obj (@c CxJsonValue*) the target JSON object
+ * @param name (any string) the name of the new value
+ * @param lit (@c CxJsonLiteral) the type of literal
+ * @return (@c CxJsonValue*) the new value or @c NULL if allocation fails
+ * @see cxJsonObjPut()
+ * @see cxJsonCreateLiteral()
+ */
+#define cxJsonObjPutLiteral(obj, name, lit) cx_json_obj_put_literal(obj, cx_strcast(name), lit)
 
 /**
  * Recursively deallocates the memory of a JSON value.
@@ -998,7 +1099,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;
 }
 
 /**
@@ -1015,7 +1116,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;
 }
 
 /**
@@ -1032,7 +1133,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;
 }
 
 /**
@@ -1045,7 +1146,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;
 }
 
 /**
@@ -1123,7 +1224,7 @@
  */
 cx_attr_nonnull
 CX_INLINE bool cxJsonAsBool(const CxJsonValue *value) {
-    return value->value.literal == CX_JSON_TRUE;
+    return value->literal == CX_JSON_TRUE;
 }
 
 /**
@@ -1137,7 +1238,7 @@
  */
 cx_attr_nonnull
 CX_INLINE size_t cxJsonArrSize(const CxJsonValue *value) {
-    return value->value.array.array_size;
+    return value->array.data_size;
 }
 
 /**
@@ -1188,10 +1289,24 @@
 CX_EXPORT CxIterator cxJsonArrIter(const CxJsonValue *value);
 
 /**
- * Returns an iterator over the JSON object members.
+ * Returns the size of a JSON object.
+ *
+ * If the @p value is not a JSON object, the behavior is undefined.
  *
- * The iterator yields values of type @c CxJsonObjValue* which
- * contain the name and value of the member.
+ * @param value the JSON value
+ * @return the size of the object, i.e., the number of key/value pairs
+ * @see cxJsonIsObject()
+ */
+cx_attr_nonnull
+CX_INLINE size_t cxJsonObjSize(const CxJsonValue *value) {
+    return cxCollectionSize(value->object);
+}
+
+/**
+ * Returns a map iterator over the JSON object members.
+ *
+ * The iterator yields values of type @c CxMapEntry* which
+ * contain the name and the @c CxJsonObjValue* of the member.
  *
  * If the @p value is not a JSON object, the behavior is undefined.
  *
@@ -1200,7 +1315,7 @@
  * @see cxJsonIsObject()
  */
 cx_attr_nonnull cx_attr_nodiscard
-CX_EXPORT CxIterator cxJsonObjIter(const CxJsonValue *value);
+CX_EXPORT CxMapIterator cxJsonObjIter(const CxJsonValue *value);
 
 /**
  * Internal function, do not use.

mercurial