src/json.c

changeset 1543
7b66371d6da3
parent 1513
4d641c6a2f82
child 1547
12da0654e4a9
equal deleted inserted replaced
1542:197450c2b0b3 1543:7b66371d6da3
50 static size_t json_find_objvalue(const CxJsonValue *obj, cxstring name) { 50 static size_t json_find_objvalue(const CxJsonValue *obj, cxstring name) {
51 assert(obj->type == CX_JSON_OBJECT); 51 assert(obj->type == CX_JSON_OBJECT);
52 CxJsonObjValue kv_dummy; 52 CxJsonObjValue kv_dummy;
53 kv_dummy.name = cx_mutstrn((char*) name.ptr, name.length); 53 kv_dummy.name = cx_mutstrn((char*) name.ptr, name.length);
54 return cx_array_binary_search( 54 return cx_array_binary_search(
55 obj->value.object.values, 55 obj->object.values,
56 obj->value.object.values_size, 56 obj->object.values_size,
57 sizeof(CxJsonObjValue), 57 sizeof(CxJsonObjValue),
58 &kv_dummy, 58 &kv_dummy,
59 json_cmp_objvalue 59 json_cmp_objvalue
60 ); 60 );
61 } 61 }
62 62
63 static int json_add_objvalue(CxJsonValue *objv, CxJsonObjValue member) { 63 static int json_add_objvalue(CxJsonValue *objv, CxJsonObjValue member) {
64 assert(objv->type == CX_JSON_OBJECT); 64 assert(objv->type == CX_JSON_OBJECT);
65 const CxAllocator * const al = objv->allocator; 65 const CxAllocator * const al = objv->allocator;
66 CxJsonObject *obj = &(objv->value.object); 66 CxJsonObject *obj = &(objv->object);
67 67
68 // determine the index where we need to insert the new member 68 // determine the index where we need to insert the new member
69 size_t index = cx_array_binary_search_sup( 69 size_t index = cx_array_binary_search_sup(
70 obj->values, 70 obj->values,
71 obj->values_size, 71 obj->values_size,
532 532
533 // initialize the value 533 // initialize the value
534 v->type = type; 534 v->type = type;
535 v->allocator = json->allocator; 535 v->allocator = json->allocator;
536 if (type == CX_JSON_ARRAY) { 536 if (type == CX_JSON_ARRAY) {
537 cx_array_initialize_a(json->allocator, v->value.array.array, 16); 537 cx_array_initialize_a(json->allocator, v->array.array, 16);
538 if (v->value.array.array == NULL) goto create_json_value_exit_error; // LCOV_EXCL_LINE 538 if (v->array.array == NULL) goto create_json_value_exit_error; // LCOV_EXCL_LINE
539 } else if (type == CX_JSON_OBJECT) { 539 } else if (type == CX_JSON_OBJECT) {
540 cx_array_initialize_a(json->allocator, v->value.object.values, 16); 540 cx_array_initialize_a(json->allocator, v->object.values, 16);
541 v->value.object.indices = cxCalloc(json->allocator, 16, sizeof(size_t)); 541 v->object.indices = cxCalloc(json->allocator, 16, sizeof(size_t));
542 if (v->value.object.values == NULL || 542 if (v->object.values == NULL ||
543 v->value.object.indices == NULL) 543 v->object.indices == NULL)
544 goto create_json_value_exit_error; // LCOV_EXCL_LINE 544 goto create_json_value_exit_error; // LCOV_EXCL_LINE
545 } 545 }
546 546
547 // add the new value to a possible parent 547 // add the new value to a possible parent
548 if (json->vbuf_size > 0) { 548 if (json->vbuf_size > 0) {
549 CxJsonValue *parent = json->vbuf[json->vbuf_size - 1]; 549 CxJsonValue *parent = json->vbuf[json->vbuf_size - 1];
550 assert(parent != NULL); 550 assert(parent != NULL);
551 if (parent->type == CX_JSON_ARRAY) { 551 if (parent->type == CX_JSON_ARRAY) {
552 CxArrayReallocator value_realloc = cx_array_reallocator(json->allocator, NULL); 552 CxArrayReallocator value_realloc = cx_array_reallocator(json->allocator, NULL);
553 if (cx_array_simple_add_a(&value_realloc, parent->value.array.array, v)) { 553 if (cx_array_simple_add_a(&value_realloc, parent->array.array, v)) {
554 goto create_json_value_exit_error; // LCOV_EXCL_LINE 554 goto create_json_value_exit_error; // LCOV_EXCL_LINE
555 } 555 }
556 } else if (parent->type == CX_JSON_OBJECT) { 556 } else if (parent->type == CX_JSON_OBJECT) {
557 // the member was already created after parsing the name 557 // the member was already created after parsing the name
558 assert(json->uncompleted_member.name.ptr != NULL); 558 assert(json->uncompleted_member.name.ptr != NULL);
718 } 718 }
719 cxmutstr str = unescape_string(json->allocator, token.content); 719 cxmutstr str = unescape_string(json->allocator, token.content);
720 if (str.ptr == NULL) { 720 if (str.ptr == NULL) {
721 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE 721 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE
722 } 722 }
723 vbuf->value.string = str; 723 vbuf->string = str;
724 return_rec(CX_JSON_NO_ERROR); 724 return_rec(CX_JSON_NO_ERROR);
725 } 725 }
726 case CX_JSON_TOKEN_INTEGER: 726 case CX_JSON_TOKEN_INTEGER:
727 case CX_JSON_TOKEN_NUMBER: { 727 case CX_JSON_TOKEN_NUMBER: {
728 int type = token.tokentype == CX_JSON_TOKEN_INTEGER ? CX_JSON_INTEGER : CX_JSON_NUMBER; 728 int type = token.tokentype == CX_JSON_TOKEN_INTEGER ? CX_JSON_INTEGER : CX_JSON_NUMBER;
729 if (NULL == (vbuf = json_create_value(json, type))) { 729 if (NULL == (vbuf = json_create_value(json, type))) {
730 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE 730 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE
731 } 731 }
732 if (type == CX_JSON_INTEGER) { 732 if (type == CX_JSON_INTEGER) {
733 if (cx_strtoi64(token.content, &vbuf->value.integer, 10)) { 733 if (cx_strtoi64(token.content, &vbuf->integer, 10)) {
734 return_rec(CX_JSON_FORMAT_ERROR_NUMBER); 734 return_rec(CX_JSON_FORMAT_ERROR_NUMBER);
735 } 735 }
736 } else { 736 } else {
737 if (cx_strtod(token.content, &vbuf->value.number)) { 737 if (cx_strtod(token.content, &vbuf->number)) {
738 // TODO: at the moment this is unreachable, because the tokenizer is already stricter than cx_strtod() 738 // TODO: at the moment this is unreachable, because the tokenizer is already stricter than cx_strtod()
739 return_rec(CX_JSON_FORMAT_ERROR_NUMBER); // LCOV_EXCL_LINE 739 return_rec(CX_JSON_FORMAT_ERROR_NUMBER); // LCOV_EXCL_LINE
740 } 740 }
741 } 741 }
742 return_rec(CX_JSON_NO_ERROR); 742 return_rec(CX_JSON_NO_ERROR);
744 case CX_JSON_TOKEN_LITERAL: { 744 case CX_JSON_TOKEN_LITERAL: {
745 if ((vbuf = json_create_value(json, CX_JSON_LITERAL)) == NULL) { 745 if ((vbuf = json_create_value(json, CX_JSON_LITERAL)) == NULL) {
746 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE 746 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE
747 } 747 }
748 if (0 == cx_strcmp(cx_strcast(token.content), cx_str("true"))) { 748 if (0 == cx_strcmp(cx_strcast(token.content), cx_str("true"))) {
749 vbuf->value.literal = CX_JSON_TRUE; 749 vbuf->literal = CX_JSON_TRUE;
750 } else if (0 == cx_strcmp(cx_strcast(token.content), cx_str("false"))) { 750 } else if (0 == cx_strcmp(cx_strcast(token.content), cx_str("false"))) {
751 vbuf->value.literal = CX_JSON_FALSE; 751 vbuf->literal = CX_JSON_FALSE;
752 } else { 752 } else {
753 vbuf->value.literal = CX_JSON_NULL; 753 vbuf->literal = CX_JSON_NULL;
754 } 754 }
755 return_rec(CX_JSON_NO_ERROR); 755 return_rec(CX_JSON_NO_ERROR);
756 } 756 }
757 default: { 757 default: {
758 return_rec(CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN); 758 return_rec(CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN);
862 862
863 void cxJsonValueFree(CxJsonValue *value) { 863 void cxJsonValueFree(CxJsonValue *value) {
864 if (value == NULL || value->type == CX_JSON_NOTHING) return; 864 if (value == NULL || value->type == CX_JSON_NOTHING) return;
865 switch (value->type) { 865 switch (value->type) {
866 case CX_JSON_OBJECT: { 866 case CX_JSON_OBJECT: {
867 CxJsonObject obj = value->value.object; 867 CxJsonObject obj = value->object;
868 for (size_t i = 0; i < obj.values_size; i++) { 868 for (size_t i = 0; i < obj.values_size; i++) {
869 cxJsonValueFree(obj.values[i].value); 869 cxJsonValueFree(obj.values[i].value);
870 cx_strfree_a(value->allocator, &obj.values[i].name); 870 cx_strfree_a(value->allocator, &obj.values[i].name);
871 } 871 }
872 cxFree(value->allocator, obj.values); 872 cxFree(value->allocator, obj.values);
873 cxFree(value->allocator, obj.indices); 873 cxFree(value->allocator, obj.indices);
874 break; 874 break;
875 } 875 }
876 case CX_JSON_ARRAY: { 876 case CX_JSON_ARRAY: {
877 CxJsonArray array = value->value.array; 877 CxJsonArray array = value->array;
878 for (size_t i = 0; i < array.array_size; i++) { 878 for (size_t i = 0; i < array.array_size; i++) {
879 cxJsonValueFree(array.array[i]); 879 cxJsonValueFree(array.array[i]);
880 } 880 }
881 cxFree(value->allocator, array.array); 881 cxFree(value->allocator, array.array);
882 break; 882 break;
883 } 883 }
884 case CX_JSON_STRING: { 884 case CX_JSON_STRING: {
885 cxFree(value->allocator, value->value.string.ptr); 885 cxFree(value->allocator, value->string.ptr);
886 break; 886 break;
887 } 887 }
888 default: { 888 default: {
889 break; 889 break;
890 } 890 }
896 if (allocator == NULL) allocator = cxDefaultAllocator; 896 if (allocator == NULL) allocator = cxDefaultAllocator;
897 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue)); 897 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue));
898 if (v == NULL) return NULL; 898 if (v == NULL) return NULL;
899 v->allocator = allocator; 899 v->allocator = allocator;
900 v->type = CX_JSON_OBJECT; 900 v->type = CX_JSON_OBJECT;
901 cx_array_initialize_a(allocator, v->value.object.values, 16); 901 cx_array_initialize_a(allocator, v->object.values, 16);
902 if (v->value.object.values == NULL) { // LCOV_EXCL_START 902 if (v->object.values == NULL) { // LCOV_EXCL_START
903 cxFree(allocator, v); 903 cxFree(allocator, v);
904 return NULL; 904 return NULL;
905 // LCOV_EXCL_STOP 905 // LCOV_EXCL_STOP
906 } 906 }
907 v->value.object.indices = cxCalloc(allocator, 16, sizeof(size_t)); 907 v->object.indices = cxCalloc(allocator, 16, sizeof(size_t));
908 if (v->value.object.indices == NULL) { // LCOV_EXCL_START 908 if (v->object.indices == NULL) { // LCOV_EXCL_START
909 cxFree(allocator, v->value.object.values); 909 cxFree(allocator, v->object.values);
910 cxFree(allocator, v); 910 cxFree(allocator, v);
911 return NULL; 911 return NULL;
912 // LCOV_EXCL_STOP 912 // LCOV_EXCL_STOP
913 } 913 }
914 return v; 914 return v;
918 if (allocator == NULL) allocator = cxDefaultAllocator; 918 if (allocator == NULL) allocator = cxDefaultAllocator;
919 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue)); 919 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue));
920 if (v == NULL) return NULL; 920 if (v == NULL) return NULL;
921 v->allocator = allocator; 921 v->allocator = allocator;
922 v->type = CX_JSON_ARRAY; 922 v->type = CX_JSON_ARRAY;
923 cx_array_initialize_a(allocator, v->value.array.array, 16); 923 cx_array_initialize_a(allocator, v->array.array, 16);
924 if (v->value.array.array == NULL) { cxFree(allocator, v); return NULL; } 924 if (v->array.array == NULL) { cxFree(allocator, v); return NULL; }
925 return v; 925 return v;
926 } 926 }
927 927
928 CxJsonValue* cxJsonCreateNumber(const CxAllocator* allocator, double num) { 928 CxJsonValue* cxJsonCreateNumber(const CxAllocator* allocator, double num) {
929 if (allocator == NULL) allocator = cxDefaultAllocator; 929 if (allocator == NULL) allocator = cxDefaultAllocator;
930 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue)); 930 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue));
931 if (v == NULL) return NULL; 931 if (v == NULL) return NULL;
932 v->allocator = allocator; 932 v->allocator = allocator;
933 v->type = CX_JSON_NUMBER; 933 v->type = CX_JSON_NUMBER;
934 v->value.number = num; 934 v->number = num;
935 return v; 935 return v;
936 } 936 }
937 937
938 CxJsonValue* cxJsonCreateInteger(const CxAllocator* allocator, int64_t num) { 938 CxJsonValue* cxJsonCreateInteger(const CxAllocator* allocator, int64_t num) {
939 if (allocator == NULL) allocator = cxDefaultAllocator; 939 if (allocator == NULL) allocator = cxDefaultAllocator;
940 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue)); 940 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue));
941 if (v == NULL) return NULL; 941 if (v == NULL) return NULL;
942 v->allocator = allocator; 942 v->allocator = allocator;
943 v->type = CX_JSON_INTEGER; 943 v->type = CX_JSON_INTEGER;
944 v->value.integer = num; 944 v->integer = num;
945 return v; 945 return v;
946 } 946 }
947 947
948 CxJsonValue* cx_json_create_string(const CxAllocator* allocator, cxstring str) { 948 CxJsonValue* cx_json_create_string(const CxAllocator* allocator, cxstring str) {
949 if (allocator == NULL) allocator = cxDefaultAllocator; 949 if (allocator == NULL) allocator = cxDefaultAllocator;
951 if (v == NULL) return NULL; 951 if (v == NULL) return NULL;
952 v->allocator = allocator; 952 v->allocator = allocator;
953 v->type = CX_JSON_STRING; 953 v->type = CX_JSON_STRING;
954 cxmutstr s = cx_strdup_a(allocator, str); 954 cxmutstr s = cx_strdup_a(allocator, str);
955 if (s.ptr == NULL) { cxFree(allocator, v); return NULL; } 955 if (s.ptr == NULL) { cxFree(allocator, v); return NULL; }
956 v->value.string = s; 956 v->string = s;
957 return v; 957 return v;
958 } 958 }
959 959
960 CxJsonValue* cxJsonCreateLiteral(const CxAllocator* allocator, CxJsonLiteral lit) { 960 CxJsonValue* cxJsonCreateLiteral(const CxAllocator* allocator, CxJsonLiteral lit) {
961 if (allocator == NULL) allocator = cxDefaultAllocator; 961 if (allocator == NULL) allocator = cxDefaultAllocator;
962 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue)); 962 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue));
963 if (v == NULL) return NULL; 963 if (v == NULL) return NULL;
964 v->allocator = allocator; 964 v->allocator = allocator;
965 v->type = CX_JSON_LITERAL; 965 v->type = CX_JSON_LITERAL;
966 v->value.literal = lit; 966 v->literal = lit;
967 return v; 967 return v;
968 } 968 }
969 969
970 // LCOV_EXCL_START 970 // LCOV_EXCL_START
971 // never called as long as malloc() does not return NULL 971 // never called as long as malloc() does not return NULL
1040 1040
1041 int cxJsonArrAddValues(CxJsonValue* arr, CxJsonValue* const* val, size_t count) { 1041 int cxJsonArrAddValues(CxJsonValue* arr, CxJsonValue* const* val, size_t count) {
1042 CxArrayReallocator value_realloc = cx_array_reallocator(arr->allocator, NULL); 1042 CxArrayReallocator value_realloc = cx_array_reallocator(arr->allocator, NULL);
1043 assert(arr->type == CX_JSON_ARRAY); 1043 assert(arr->type == CX_JSON_ARRAY);
1044 return cx_array_simple_copy_a(&value_realloc, 1044 return cx_array_simple_copy_a(&value_realloc,
1045 arr->value.array.array, 1045 arr->array.array,
1046 arr->value.array.array_size, 1046 arr->array.array_size,
1047 val, count 1047 val, count
1048 ); 1048 );
1049 } 1049 }
1050 1050
1051 int cx_json_obj_put(CxJsonValue* obj, cxstring name, CxJsonValue* child) { 1051 int cx_json_obj_put(CxJsonValue* obj, cxstring name, CxJsonValue* child) {
1103 if (cxJsonObjPut(obj, name, v)) { cxJsonValueFree(v); return NULL;} 1103 if (cxJsonObjPut(obj, name, v)) { cxJsonValueFree(v); return NULL;}
1104 return v; 1104 return v;
1105 } 1105 }
1106 1106
1107 CxJsonValue *cxJsonArrGet(const CxJsonValue *value, size_t index) { 1107 CxJsonValue *cxJsonArrGet(const CxJsonValue *value, size_t index) {
1108 if (index >= value->value.array.array_size) { 1108 if (index >= value->array.array_size) {
1109 return &cx_json_value_nothing; 1109 return &cx_json_value_nothing;
1110 } 1110 }
1111 return value->value.array.array[index]; 1111 return value->array.array[index];
1112 } 1112 }
1113 1113
1114 CxJsonValue *cxJsonArrRemove(CxJsonValue *value, size_t index) { 1114 CxJsonValue *cxJsonArrRemove(CxJsonValue *value, size_t index) {
1115 if (index >= value->value.array.array_size) { 1115 if (index >= value->array.array_size) {
1116 return NULL; 1116 return NULL;
1117 } 1117 }
1118 CxJsonValue *ret = value->value.array.array[index]; 1118 CxJsonValue *ret = value->array.array[index];
1119 // TODO: replace with a low level cx_array_remove() 1119 // TODO: replace with a low level cx_array_remove()
1120 size_t count = value->value.array.array_size - index - 1; 1120 size_t count = value->array.array_size - index - 1;
1121 if (count > 0) { 1121 if (count > 0) {
1122 memmove(value->value.array.array + index, value->value.array.array + index + 1, count * sizeof(CxJsonValue*)); 1122 memmove(value->array.array + index, value->array.array + index + 1, count * sizeof(CxJsonValue*));
1123 } 1123 }
1124 value->value.array.array_size--; 1124 value->array.array_size--;
1125 return ret; 1125 return ret;
1126 } 1126 }
1127 1127
1128 char *cxJsonAsString(const CxJsonValue *value) { 1128 char *cxJsonAsString(const CxJsonValue *value) {
1129 return value->value.string.ptr; 1129 return value->string.ptr;
1130 } 1130 }
1131 1131
1132 cxstring cxJsonAsCxString(const CxJsonValue *value) { 1132 cxstring cxJsonAsCxString(const CxJsonValue *value) {
1133 return cx_strcast(value->value.string); 1133 return cx_strcast(value->string);
1134 } 1134 }
1135 1135
1136 cxmutstr cxJsonAsCxMutStr(const CxJsonValue *value) { 1136 cxmutstr cxJsonAsCxMutStr(const CxJsonValue *value) {
1137 return value->value.string; 1137 return value->string;
1138 } 1138 }
1139 1139
1140 double cxJsonAsDouble(const CxJsonValue *value) { 1140 double cxJsonAsDouble(const CxJsonValue *value) {
1141 if (value->type == CX_JSON_INTEGER) { 1141 if (value->type == CX_JSON_INTEGER) {
1142 return (double) value->value.integer; 1142 return (double) value->integer;
1143 } else { 1143 } else {
1144 return value->value.number; 1144 return value->number;
1145 } 1145 }
1146 } 1146 }
1147 1147
1148 int64_t cxJsonAsInteger(const CxJsonValue *value) { 1148 int64_t cxJsonAsInteger(const CxJsonValue *value) {
1149 if (value->type == CX_JSON_INTEGER) { 1149 if (value->type == CX_JSON_INTEGER) {
1150 return value->value.integer; 1150 return value->integer;
1151 } else { 1151 } else {
1152 return (int64_t) value->value.number; 1152 return (int64_t) value->number;
1153 } 1153 }
1154 } 1154 }
1155 1155
1156 CxIterator cxJsonArrIter(const CxJsonValue *value) { 1156 CxIterator cxJsonArrIter(const CxJsonValue *value) {
1157 return cxIteratorPtr( 1157 return cxIteratorPtr(
1158 value->value.array.array, 1158 value->array.array,
1159 value->value.array.array_size, 1159 value->array.array_size,
1160 true // arrays need to keep order 1160 true // arrays need to keep order
1161 ); 1161 );
1162 } 1162 }
1163 1163
1164 CxIterator cxJsonObjIter(const CxJsonValue *value) { 1164 CxIterator cxJsonObjIter(const CxJsonValue *value) {
1165 return cxIterator( 1165 return cxIterator(
1166 value->value.object.values, 1166 value->object.values,
1167 sizeof(CxJsonObjValue), 1167 sizeof(CxJsonObjValue),
1168 value->value.object.values_size, 1168 value->object.values_size,
1169 true // TODO: objects do not always need to keep order 1169 true // TODO: objects do not always need to keep order
1170 ); 1170 );
1171 } 1171 }
1172 1172
1173 CxJsonValue *cx_json_obj_get(const CxJsonValue *value, cxstring name) { 1173 CxJsonValue *cx_json_obj_get(const CxJsonValue *value, cxstring name) {
1174 size_t index = json_find_objvalue(value, name); 1174 size_t index = json_find_objvalue(value, name);
1175 if (index >= value->value.object.values_size) { 1175 if (index >= value->object.values_size) {
1176 return &cx_json_value_nothing; 1176 return &cx_json_value_nothing;
1177 } else { 1177 } else {
1178 return value->value.object.values[index].value; 1178 return value->object.values[index].value;
1179 } 1179 }
1180 } 1180 }
1181 1181
1182 CxJsonValue *cx_json_obj_remove(CxJsonValue *value, cxstring name) { 1182 CxJsonValue *cx_json_obj_remove(CxJsonValue *value, cxstring name) {
1183 size_t index = json_find_objvalue(value, name); 1183 size_t index = json_find_objvalue(value, name);
1184 if (index >= value->value.object.values_size) { 1184 if (index >= value->object.values_size) {
1185 return NULL; 1185 return NULL;
1186 } else { 1186 } else {
1187 CxJsonObjValue kv = value->value.object.values[index]; 1187 CxJsonObjValue kv = value->object.values[index];
1188 cx_strfree_a(value->allocator, &kv.name); 1188 cx_strfree_a(value->allocator, &kv.name);
1189 // TODO: replace with cx_array_remove() / cx_array_remove_fast() 1189 // TODO: replace with cx_array_remove() / cx_array_remove_fast()
1190 value->value.object.values_size--; 1190 value->object.values_size--;
1191 memmove(value->value.object.values + index, value->value.object.values + index + 1, (value->value.object.values_size - index) * sizeof(CxJsonObjValue)); 1191 memmove(value->object.values + index, value->object.values + index + 1, (value->object.values_size - index) * sizeof(CxJsonObjValue));
1192 return kv.value; 1192 return kv.value;
1193 } 1193 }
1194 } 1194 }
1195 1195
1196 CxJsonWriter cxJsonWriterCompact(void) { 1196 CxJsonWriter cxJsonWriterCompact(void) {
1270 } else { 1270 } else {
1271 actual += wfunc(begin_obj, 1, 1, target); 1271 actual += wfunc(begin_obj, 1, 1, target);
1272 expected++; 1272 expected++;
1273 } 1273 }
1274 depth++; 1274 depth++;
1275 size_t elem_count = value->value.object.values_size; 1275 size_t elem_count = value->object.values_size;
1276 for (size_t look_idx = 0; look_idx < elem_count; look_idx++) { 1276 for (size_t look_idx = 0; look_idx < elem_count; look_idx++) {
1277 // get the member either via index array or directly 1277 // get the member either via index array or directly
1278 size_t elem_idx = settings->sort_members 1278 size_t elem_idx = settings->sort_members
1279 ? look_idx 1279 ? look_idx
1280 : value->value.object.indices[look_idx]; 1280 : value->object.indices[look_idx];
1281 CxJsonObjValue *member = &value->value.object.values[elem_idx]; 1281 CxJsonObjValue *member = &value->object.values[elem_idx];
1282 1282
1283 // possible indentation 1283 // possible indentation
1284 if (settings->pretty) { 1284 if (settings->pretty) {
1285 if (cx_json_writer_indent(target, wfunc, settings, depth)) { 1285 if (cx_json_writer_indent(target, wfunc, settings, depth)) {
1286 return 1; // LCOV_EXCL_LINE 1286 return 1; // LCOV_EXCL_LINE
1359 expected++; 1359 expected++;
1360 break; 1360 break;
1361 } 1361 }
1362 case CX_JSON_STRING: { 1362 case CX_JSON_STRING: {
1363 actual += wfunc("\"", 1, 1, target); 1363 actual += wfunc("\"", 1, 1, target);
1364 cxmutstr str = escape_string(value->value.string, settings->escape_slash); 1364 cxmutstr str = escape_string(value->string, settings->escape_slash);
1365 actual += wfunc(str.ptr, 1, str.length, target); 1365 actual += wfunc(str.ptr, 1, str.length, target);
1366 if (str.ptr != value->value.string.ptr) { 1366 if (str.ptr != value->string.ptr) {
1367 cx_strfree(&str); 1367 cx_strfree(&str);
1368 } 1368 }
1369 actual += wfunc("\"", 1, 1, target); 1369 actual += wfunc("\"", 1, 1, target);
1370 expected += 2 + value->value.string.length; 1370 expected += 2 + value->string.length;
1371 break; 1371 break;
1372 } 1372 }
1373 case CX_JSON_NUMBER: { 1373 case CX_JSON_NUMBER: {
1374 int precision = settings->frac_max_digits; 1374 int precision = settings->frac_max_digits;
1375 // because of the way how %g is defined, we need to 1375 // because of the way how %g is defined, we need to
1376 // double the precision and truncate ourselves 1376 // double the precision and truncate ourselves
1377 precision = 1 + (precision > 15 ? 30 : 2 * precision); 1377 precision = 1 + (precision > 15 ? 30 : 2 * precision);
1378 snprintf(numbuf, 40, "%.*g", precision, value->value.number); 1378 snprintf(numbuf, 40, "%.*g", precision, value->number);
1379 char *dot, *exp; 1379 char *dot, *exp;
1380 unsigned char max_digits; 1380 unsigned char max_digits;
1381 // find the decimal separator and hope that it's one of . or , 1381 // find the decimal separator and hope that it's one of . or ,
1382 dot = strchr(numbuf, '.'); 1382 dot = strchr(numbuf, '.');
1383 if (dot == NULL) { 1383 if (dot == NULL) {
1437 expected += len; 1437 expected += len;
1438 } 1438 }
1439 break; 1439 break;
1440 } 1440 }
1441 case CX_JSON_INTEGER: { 1441 case CX_JSON_INTEGER: {
1442 snprintf(numbuf, 32, "%" PRIi64, value->value.integer); 1442 snprintf(numbuf, 32, "%" PRIi64, value->integer);
1443 size_t len = strlen(numbuf); 1443 size_t len = strlen(numbuf);
1444 actual += wfunc(numbuf, 1, len, target); 1444 actual += wfunc(numbuf, 1, len, target);
1445 expected += len; 1445 expected += len;
1446 break; 1446 break;
1447 } 1447 }
1448 case CX_JSON_LITERAL: { 1448 case CX_JSON_LITERAL: {
1449 if (value->value.literal == CX_JSON_TRUE) { 1449 if (value->literal == CX_JSON_TRUE) {
1450 actual += wfunc("true", 1, 4, target); 1450 actual += wfunc("true", 1, 4, target);
1451 expected += 4; 1451 expected += 4;
1452 } else if (value->value.literal == CX_JSON_FALSE) { 1452 } else if (value->literal == CX_JSON_FALSE) {
1453 actual += wfunc("false", 1, 5, target); 1453 actual += wfunc("false", 1, 5, target);
1454 expected += 5; 1454 expected += 5;
1455 } else { 1455 } else {
1456 actual += wfunc("null", 1, 4, target); 1456 actual += wfunc("null", 1, 4, target);
1457 expected += 4; 1457 expected += 4;

mercurial