src/json.c

changeset 1082
46cdc8689fc4
parent 1079
4e1872151fb6
child 1083
cf54e413793c
equal deleted inserted replaced
1081:33c9d7e7d830 1082:46cdc8689fc4
65 } else { 65 } else {
66 return &obj->value.object.values[index]; 66 return &obj->value.object.values[index];
67 } 67 }
68 } 68 }
69 69
70 static int json_add_objvalue(CxJsonValue *obj, CxJsonObjValue member) { 70 static int json_add_objvalue(CxJsonValue *objv, CxJsonObjValue member) {
71 assert(obj->type == CX_JSON_OBJECT); 71 assert(obj->type == CX_JSON_OBJECT);
72 CxArrayReallocator value_realloc = cx_array_reallocator(obj->allocator, NULL); 72 const CxAllocator * const al = objv->allocator;
73 return cx_array_simple_add_sorted_a( 73 CxJsonObject *obj = &(objv->value.object);
74 &value_realloc, obj->value.object.values, 74
75 member, json_cmp_objvalue 75 // determine the index where we need to insert the new member
76 size_t index = cx_array_binary_search_sup(
77 obj->values,
78 obj->values_size,
79 sizeof(CxJsonObjValue),
80 &member, json_cmp_objvalue
76 ); 81 );
82
83 // is the name already present?
84 if (index < obj->values_size && 0 == json_cmp_objvalue(&member, &obj->values[index])) {
85 // free the original value
86 cx_strfree_a(al, &obj->values[index].name);
87 cxJsonValueFree(obj->values[index].value);
88 // replace the item
89 obj->values[index] = member;
90
91 // nothing more to do
92 return 0;
93 }
94
95 // determine the old capacity and reserve for one more element
96 CxArrayReallocator arealloc = cx_array_reallocator(al, NULL);
97 size_t oldcap = obj->values_capacity;
98 if (cx_array_simple_reserve_a(&arealloc, obj->values, 1)) return 1;
99
100 // check the new capacity, if we need to realloc the index array
101 size_t newcap = obj->values_capacity;
102 if (newcap > oldcap) {
103 if (cxReallocateArray(al, &obj->indices, newcap, sizeof(size_t))) {
104 return 1;
105 }
106 }
107
108 // check if append or insert
109 if (index < obj->values_size) {
110 // move the other elements
111 memmove(
112 &obj->values[index+1],
113 &obj->values[index],
114 (obj->values_size - index) * sizeof(CxJsonObjValue)
115 );
116 // increase indices for the moved elements
117 for (size_t i = 0; i < obj->values_size ; i++) {
118 if (obj->indices[i] >= index) {
119 obj->indices[i]++;
120 }
121 }
122 }
123
124 // insert the element and set the index
125 obj->values[index] = member;
126 obj->indices[obj->values_size] = index;
127 obj->values_size++;
128
129 return 0;
77 } 130 }
78 131
79 static void token_destroy(CxJsonToken *token) { 132 static void token_destroy(CxJsonToken *token) {
80 if (token->allocated) { 133 if (token->allocated) {
81 cx_strfree(&token->content); 134 cx_strfree(&token->content);
321 374
322 return result; 375 return result;
323 } 376 }
324 377
325 static CxJsonValue* create_json_value(CxJson *json, CxJsonValueType type) { 378 static CxJsonValue* create_json_value(CxJson *json, CxJsonValueType type) {
326 CxJsonValue *v = cxMalloc(json->allocator, sizeof(CxJsonValue)); 379 CxJsonValue *v = cxCalloc(json->allocator, 1, sizeof(CxJsonValue));
327 if (v == NULL) return NULL; // LCOV_EXCL_LINE 380 if (v == NULL) return NULL; // LCOV_EXCL_LINE
328 381
329 // initialize the value 382 // initialize the value
383 v->type = type;
384 v->allocator = json->allocator;
330 if (type == CX_JSON_ARRAY) { 385 if (type == CX_JSON_ARRAY) {
331 cx_array_initialize_a(json->allocator, v->value.array.array, 16); 386 cx_array_initialize_a(json->allocator, v->value.array.array, 16);
332 if (v->value.array.array == NULL) goto create_json_value_exit_error; // LCOV_EXCL_LINE 387 if (v->value.array.array == NULL) goto create_json_value_exit_error; // LCOV_EXCL_LINE
333 } else if (type == CX_JSON_OBJECT) { 388 } else if (type == CX_JSON_OBJECT) {
334 cx_array_initialize_a(json->allocator, v->value.object.values, 16); 389 cx_array_initialize_a(json->allocator, v->value.object.values, 16);
335 if (v->value.object.values == NULL) goto create_json_value_exit_error; // LCOV_EXCL_LINE 390 v->value.object.indices = cxCalloc(json->allocator, 16, sizeof(size_t));
336 } else { 391 if (v->value.object.values == NULL ||
337 memset(v, 0, sizeof(CxJsonValue)); 392 v->value.object.indices == NULL)
338 } 393 goto create_json_value_exit_error; // LCOV_EXCL_LINE
339 v->type = type; 394 }
340 v->allocator = json->allocator;
341 395
342 // add the new value to a possible parent 396 // add the new value to a possible parent
343 if (json->vbuf_size > 0) { 397 if (json->vbuf_size > 0) {
344 CxJsonValue *parent = json->vbuf[json->vbuf_size - 1]; 398 CxJsonValue *parent = json->vbuf[json->vbuf_size - 1];
345 assert(parent != NULL); 399 assert(parent != NULL);
375 } 429 }
376 430
377 return v; 431 return v;
378 // LCOV_EXCL_START 432 // LCOV_EXCL_START
379 create_json_value_exit_error: 433 create_json_value_exit_error:
380 cxFree(json->allocator, v); 434 cxJsonValueFree(v);
381 return NULL; 435 return NULL;
382 // LCOV_EXCL_STOP 436 // LCOV_EXCL_STOP
383 } 437 }
384 438
385 #define JP_STATE_VALUE_BEGIN 0 439 #define JP_STATE_VALUE_BEGIN 0
655 for (size_t i = 0; i < obj.values_size; i++) { 709 for (size_t i = 0; i < obj.values_size; i++) {
656 cxJsonValueFree(obj.values[i].value); 710 cxJsonValueFree(obj.values[i].value);
657 cx_strfree_a(value->allocator, &obj.values[i].name); 711 cx_strfree_a(value->allocator, &obj.values[i].name);
658 } 712 }
659 cxFree(value->allocator, obj.values); 713 cxFree(value->allocator, obj.values);
714 cxFree(value->allocator, obj.indices);
660 break; 715 break;
661 } 716 }
662 case CX_JSON_ARRAY: { 717 case CX_JSON_ARRAY: {
663 CxJsonArray array = value->value.array; 718 CxJsonArray array = value->value.array;
664 for (size_t i = 0; i < array.array_size; i++) { 719 for (size_t i = 0; i < array.array_size; i++) {
682 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue)); 737 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue));
683 if (v == NULL) return NULL; 738 if (v == NULL) return NULL;
684 v->allocator = allocator; 739 v->allocator = allocator;
685 v->type = CX_JSON_OBJECT; 740 v->type = CX_JSON_OBJECT;
686 cx_array_initialize_a(allocator, v->value.object.values, 16); 741 cx_array_initialize_a(allocator, v->value.object.values, 16);
687 if (v->value.object.values == NULL) { cxFree(allocator, v); return NULL; } 742 if (v->value.object.values == NULL) { // LCOV_EXCL_START
743 cxFree(allocator, v);
744 return NULL;
745 // LCOV_EXCL_STOP
746 }
747 v->value.object.indices = cxCalloc(allocator, 16, sizeof(size_t));
748 if (v->value.object.indices == NULL) { // LCOV_EXCL_START
749 cxFree(allocator, v->value.object.values);
750 cxFree(allocator, v);
751 return NULL;
752 // LCOV_EXCL_STOP
753 }
688 return v; 754 return v;
689 } 755 }
690 756
691 CxJsonValue* cxJsonCreateArr(const CxAllocator* allocator) { 757 CxJsonValue* cxJsonCreateArr(const CxAllocator* allocator) {
692 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue)); 758 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue));
820 val, count 886 val, count
821 ); 887 );
822 } 888 }
823 889
824 int cxJsonObjPut(CxJsonValue* obj, cxstring name, CxJsonValue* child) { 890 int cxJsonObjPut(CxJsonValue* obj, cxstring name, CxJsonValue* child) {
825 // TODO: optimize - issue #462
826 for (size_t i = 0; i < obj->value.object.values_size; i++) {
827 if (0 == cx_strcmp(name, cx_strcast(obj->value.object.values[i].name))) {
828 // free the original value
829 cxJsonValueFree(obj->value.object.values[i].value);
830 obj->value.object.values[i].value = child;
831 return 0;
832 }
833 }
834
835 cxmutstr k = cx_strdup_a(obj->allocator, name); 891 cxmutstr k = cx_strdup_a(obj->allocator, name);
836 if (k.ptr == NULL) return -1; 892 if (k.ptr == NULL) return -1;
837 CxJsonObjValue kv = {k, child}; 893 CxJsonObjValue kv = {k, child};
838 return json_add_objvalue(obj, kv); 894 if (json_add_objvalue(obj, kv)) {
895 cx_strfree_a(obj->allocator, &k);
896 return 1;
897 } else {
898 return 0;
899 }
839 } 900 }
840 901
841 CxJsonValue* cxJsonObjPutObj(CxJsonValue* obj, cxstring name) { 902 CxJsonValue* cxJsonObjPutObj(CxJsonValue* obj, cxstring name) {
842 CxJsonValue* v = cxJsonCreateObj(obj->allocator); 903 CxJsonValue* v = cxJsonCreateObj(obj->allocator);
843 if (v == NULL) return NULL; 904 if (v == NULL) return NULL;
995 } else { 1056 } else {
996 actual += wfunc(begin_obj, 1, 1, target); 1057 actual += wfunc(begin_obj, 1, 1, target);
997 expected++; 1058 expected++;
998 } 1059 }
999 depth++; 1060 depth++;
1000 CxIterator iter = cxJsonObjIter(value); 1061 size_t elem_count = value->value.object.values_size;
1001 // TODO: unsorted output - realize after implementing index array 1062 for (size_t look_idx = 0; look_idx < elem_count; look_idx++) {
1002 cx_foreach(CxJsonObjValue*, member, iter) { 1063 // get the member either via index array or directly
1064 size_t elem_idx = settings->sort_members
1065 ? look_idx
1066 : value->value.object.indices[look_idx];
1067 CxJsonObjValue *member = &value->value.object.values[elem_idx];
1068 if (settings->sort_members) {
1069 depth++;depth--;
1070 }
1071
1003 // possible indentation 1072 // possible indentation
1004 if (settings->pretty) { 1073 if (settings->pretty) {
1005 if (cx_json_writer_indent(target, wfunc, settings, depth)) return 1; 1074 if (cx_json_writer_indent(target, wfunc, settings, depth)) {
1075 return 1; // LCOV_EXCL_LINE
1076 }
1006 } 1077 }
1007 1078
1008 // the name 1079 // the name
1009 actual += wfunc("\"", 1, 1, target); 1080 actual += wfunc("\"", 1, 1, target);
1010 // TODO: escape the string 1081 // TODO: escape the string
1022 1093
1023 // the value 1094 // the value
1024 if (cx_json_write_rec(target, member->value, wfunc, settings, depth)) return 1; 1095 if (cx_json_write_rec(target, member->value, wfunc, settings, depth)) return 1;
1025 1096
1026 // end of object-value 1097 // end of object-value
1027 if (iter.index < iter.elem_count - 1) { 1098 if (look_idx < elem_count - 1) {
1028 const char *obj_value_sep = ",\n"; 1099 const char *obj_value_sep = ",\n";
1029 if (settings->pretty) { 1100 if (settings->pretty) {
1030 actual += wfunc(obj_value_sep, 1, 2, target); 1101 actual += wfunc(obj_value_sep, 1, 2, target);
1031 expected += 2; 1102 expected += 2;
1032 } else { 1103 } else {
1047 actual += wfunc("}", 1, 1, target); 1118 actual += wfunc("}", 1, 1, target);
1048 expected++; 1119 expected++;
1049 break; 1120 break;
1050 } 1121 }
1051 case CX_JSON_ARRAY: { 1122 case CX_JSON_ARRAY: {
1052 // TODO: implement array wrapping
1053 actual += wfunc("[", 1, 1, target); 1123 actual += wfunc("[", 1, 1, target);
1054 expected++; 1124 expected++;
1055 CxIterator iter = cxJsonArrIter(value); 1125 CxIterator iter = cxJsonArrIter(value);
1056 cx_foreach(CxJsonValue*, element, iter) { 1126 cx_foreach(CxJsonValue*, element, iter) {
1057 if (cx_json_write_rec( 1127 if (cx_json_write_rec(

mercurial