--- 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 + } +}