# HG changeset patch # User Mike Becker # Date 1765628642 -3600 # Node ID 97fc8c55aeea300ac4378a823418cf7855f59726 # Parent 32b82c4242525908db929b9163393d5a73b5ec26 add cxJsonCompare() resolves #781 except for the tests diff -r 32b82c424252 -r 97fc8c55aeea CHANGELOG --- a/CHANGELOG Sat Dec 13 12:54:56 2025 +0100 +++ b/CHANGELOG Sat Dec 13 13:24:02 2025 +0100 @@ -3,6 +3,7 @@ * adds cx_system_page_size() to allocator.h * adds cxJsonFromString(), cxJsonToString(), and cxJsonToPrettyString() + * adds cxJsonCompare() * adds cxMapCompare() * adds line continuation support to CxProperties / CxPropertiesConfig * adds cxBufferMaximumCapacity() diff -r 32b82c424252 -r 97fc8c55aeea docs/Writerside/topics/about.md --- a/docs/Writerside/topics/about.md Sat Dec 13 12:54:56 2025 +0100 +++ b/docs/Writerside/topics/about.md Sat Dec 13 13:24:02 2025 +0100 @@ -30,6 +30,7 @@ * adds cx_system_page_size() to allocator.h * adds cxJsonFromString(), cxJsonToString(), and cxJsonToPrettyString() +* adds cxJsonCompare() * adds cxMapCompare() * adds line continuation support to CxProperties / CxPropertiesConfig * adds cxBufferMaximumCapacity() diff -r 32b82c424252 -r 97fc8c55aeea docs/Writerside/topics/json.h.md --- a/docs/Writerside/topics/json.h.md Sat Dec 13 12:54:56 2025 +0100 +++ b/docs/Writerside/topics/json.h.md Sat Dec 13 13:24:02 2025 +0100 @@ -166,6 +166,19 @@ > If you don't have full control over the JSON data, you should always check the datatype of a value first before accessing it. >{style="note"} +## Compare Values + +```C +#include + +int cxJsonCompare(const CxJsonValue *value, + const CxJsonValue *other); +``` + +The function `cxJsonCompare()` performs a deep comparison of two JSON values. +It returns zero if both values are equal except for the order of object members. +When the values are not equal, the return-value is an unspecified non-zero value. + ## Deallocate Memory ```C diff -r 32b82c424252 -r 97fc8c55aeea src/json.c --- a/src/json.c Sat Dec 13 12:54:56 2025 +0100 +++ b/src/json.c Sat Dec 13 13:24:02 2025 +0100 @@ -453,9 +453,10 @@ } static CxJsonObject json_create_object_map(const CxAllocator *allocator) { - // TODO: we might want to add a comparator that is sorting the elements by their key CxMap *map = cxKvListCreateAsMap(allocator, NULL, CX_STORE_POINTERS); if (map == NULL) return NULL; // LCOV_EXCL_LINE + // TODO: fix the specification of the compare function + map->collection.cmpfunc = (cx_compare_func) cxJsonCompare; cxDefineDestructor(map, cxJsonValueFree); return map; } @@ -1441,3 +1442,36 @@ CxJsonWriter writer = cxJsonWriterPretty(true); return cx_json_to_string(value, allocator, &writer); } + +int cxJsonCompare(const CxJsonValue *json, const CxJsonValue *other) { + if (json == NULL && other == NULL) return 0; + if (json == NULL || other == NULL) return -1; + if (json->type != other->type) return -1; + switch (json->type) { + case CX_JSON_NOTHING: + return 0; + 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++) { + const int d = cxJsonCompare(json->array.data[i], other->array.data[i]); + if (d != 0) return d; + } + return 0; + case CX_JSON_STRING: + return cx_strcmp(json->string, other->string); + case CX_JSON_INTEGER: + return cx_vcmp_int64(json->integer, other->integer); + case CX_JSON_NUMBER: + return cx_vcmp_double(json->number, other->number); + case CX_JSON_LITERAL: + return json->literal == other->literal ? 0 : -1; + default: + // LCOV_EXCL_START + // unreachable + assert(false); + return -1; + // LCOV_EXCL_STOP + } +}