From d8343d09e0606f635af2856d2a38af8074fe9e59 Mon Sep 17 00:00:00 2001 From: MaxBrandtner Date: Fri, 3 May 2024 10:27:43 +0200 Subject: [PATCH 1/7] adds jv_paths(), jv_addpath(), jv_new() --- src/jq_test.c | 22 +++++++++++ src/jv.c | 57 +++++++++++++++++++++++++++ src/jv.h | 3 ++ src/jv_aux.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 187 insertions(+) diff --git a/src/jq_test.c b/src/jq_test.c index 39456861a5..40cdca5747 100644 --- a/src/jq_test.c +++ b/src/jq_test.c @@ -490,4 +490,26 @@ static void jv_test() { //jv_dump(jv_copy(o2), 0); printf("\n"); jv_free(o2); } + + { + jv input = jv_parse("{\"key\":[{\"this\":{\"some\":\"thing\"}}, 1, [true]]}"); + jv output = jv_paths(jv_copy(input)); + jv_dump(input, JV_PRINT_TAB); + jv_dump(output, JV_PRINT_TAB); + } + + { + jv input = jv_parse("{\"key\":{\"some\":{\"test\":\"value\"}, \"other\":\"thing\"}}"); + jv add = jv_parse("{\"some\":{\"test\":\"other\"}, \"added\":\"thing\"}"); + jv output = jv_addpath(jv_copy(input), JV_ARRAY(jv_string("key")), jv_copy(add)); + jv_dump(input, JV_PRINT_TAB); + jv_dump(add, JV_PRINT_TAB); + jv_dump(output, JV_PRINT_TAB); + } + + { + jv output = jv_new(jv_parse("{\"test\":[{\"some\":\"value\"}, 1, true, false, null]}")); + + jv_free(output); + } } diff --git a/src/jv.c b/src/jv.c index e23d8ec124..36bbcff0d3 100644 --- a/src/jv.c +++ b/src/jv.c @@ -1862,6 +1862,63 @@ jv jv_object_iter_value(jv object, int iter) { /* * Memory management */ +jv jv_new(jv input){ + switch(jv_get_kind(input)){ + case JV_KIND_INVALID: + if(!jv_invalid_has_msg(jv_copy(input))){ + jv_free(input); + return jv_invalid(); + } + return jv_invalid_with_msg(jv_new(jv_invalid_get_msg(jv_copy(input)))); + case JV_KIND_OBJECT: + case JV_KIND_ARRAY: + jv keys = jv_keys(jv_copy(input)); + size_t keys_length = jv_array_length(jv_copy(keys)); + + jv output_object; + if(jv_get_kind(input) == JV_KIND_OBJECT){ + output_object = jv_object(); + }else{ + output_object = jv_array(); + } + + for(size_t i = 0; i < keys_length; i++){ + jv key = JV_ARRAY(jv_new(jv_array_get(jv_copy(keys), i))); + + output_object = jv_setpath( + output_object,key, + jv_new( + jv_getpath(jv_copy(output_object), jv_copy(key)) + ) + ); + } + + jv_free(keys); + jv_free(input); + + return output_object; + case JV_KIND_STRING: + jv output_string = jv_string(jv_string_value(input)); + jv_free(input); + return output_string; + case JV_KIND_NUMBER: + double val = jv_number_value(input); + jv_free(input); + return jv_number(val); + case JV_KIND_TRUE: + jv_free(input); + return jv_true(); + case JV_KIND_FALSE: + jv_free(input); + return jv_false(); + case JV_KIND_NULL: + jv_free(input); + return jv_null(); + default: + return jv_invalid(); + } +} + jv jv_copy(jv j) { if (JVP_IS_ALLOCATED(j)) { jvp_refcnt_inc(j.u.ptr); diff --git a/src/jv.h b/src/jv.h index 083509ec26..f19def01c6 100644 --- a/src/jv.h +++ b/src/jv.h @@ -51,6 +51,7 @@ jv_kind jv_get_kind(jv); const char* jv_kind_name(jv_kind); static int jv_is_valid(jv x) { return jv_get_kind(x) != JV_KIND_INVALID; } +jv jv_new(jv); jv jv_copy(jv); void jv_free(jv); @@ -256,8 +257,10 @@ jv jv_get(jv, jv); jv jv_set(jv, jv, jv); jv jv_has(jv, jv); jv jv_setpath(jv, jv, jv); +jv jv_addpath(jv, jv, jv); jv jv_getpath(jv, jv); jv jv_delpaths(jv, jv); +jv jv_paths(jv); jv jv_keys(jv /*object or array*/); jv jv_keys_unsorted(jv /*object or array*/); int jv_cmp(jv, jv); diff --git a/src/jv_aux.c b/src/jv_aux.c index 6004799c6a..a1fa00dcc2 100644 --- a/src/jv_aux.c +++ b/src/jv_aux.c @@ -427,6 +427,70 @@ jv jv_setpath(jv root, jv path, jv value) { return jv_set(root, pathcurr, jv_setpath(subroot, pathrest, value)); } +jv jv_addpath(jv root, jv path, jv add){ + if(jv_get_kind(path) != JV_KIND_ARRAY || !jv_is_valid(add)){ + jv_free(root); + jv_free(path); + jv_free(add); + return jv_invalid(); + } + + if(jv_get_kind(root) != JV_KIND_OBJECT && jv_get_kind(root) != JV_KIND_ARRAY){ + jv_free(root); + + if(!jv_equal(jv_copy(path), jv_array())){ + jv_free(path); + jv_free(add); + return jv_invalid(); + } + + jv_free(path); + + return add; + } + + if(!jv_equal(jv_copy(path), jv_array())){ + return jv_setpath(root, path, jv_addpath(jv_getpath(jv_copy(root), jv_copy(path)), jv_array(), add)); + } + + jv root_paths = jv_paths(jv_copy(root)); + jv add_paths = jv_paths(jv_copy(add)); + + size_t add_paths_length = jv_array_length(jv_copy(add_paths)); + + for(size_t i = 0; i < add_paths_length; i++){ + jv add_path = jv_array_get(jv_copy(add_paths), i); + jv add_path_value = jv_getpath(jv_copy(add), jv_copy(add_path)); + + if(!jv_is_valid(add_path_value) || jv_get_kind(add_path_value) == JV_KIND_NULL){ + jv_free(root); + jv_free(path); + jv_free(add); + jv_free(root_paths); + jv_free(add_paths); + jv_free(add_path); + jv_free(add_path_value); + return jv_invalid(); + } + + if(jv_get_kind(add_path_value) == JV_KIND_OBJECT || jv_get_kind(add_path_value) == JV_KIND_ARRAY){ + jv_free(add_path); + jv_free(add_path_value); + continue; + } + + root = jv_setpath(root, add_path, add_path_value); + } + + jv_free(path); + jv_free(add); + + jv_free(root_paths); + jv_free(add_paths); + + return root; +} + jv jv_getpath(jv root, jv path) { if (jv_get_kind(path) != JV_KIND_ARRAY) { jv_free(root); @@ -538,6 +602,47 @@ static int string_cmp(const void* pa, const void* pb){ return r; } +jv jv_paths(jv input){ + if(jv_get_kind(input) != JV_KIND_OBJECT && jv_get_kind(input) != JV_KIND_ARRAY){ + jv_free(input); + return jv_invalid(); + } + + jv keys = jv_keys(jv_copy(input)); + + size_t keys_length = jv_array_length(jv_copy(keys)); + + jv output = jv_array(); + + for(size_t i = 0; i < keys_length; i++){ + jv key = jv_array_get(jv_copy(keys), i); + jv insert_paths = jv_paths(jv_getpath(jv_copy(input), JV_ARRAY(jv_copy(key)))); + + output = jv_array_append(output, JV_ARRAY(jv_copy(key))); + + if(jv_get_kind(insert_paths) == JV_KIND_INVALID){ + jv_free(insert_paths); + jv_free(key); + + continue; + } + + size_t paths_length = jv_array_length(jv_copy(insert_paths)); + + for(size_t j = 0; j < paths_length; j++){ + output = jv_array_append(output, jv_array_concat(JV_ARRAY(jv_copy(key)), jv_array_get(jv_copy(insert_paths), j))); + } + + jv_free(key); + jv_free(insert_paths); + } + + jv_free(input); + jv_free(keys); + + return output; +} + jv jv_keys_unsorted(jv x) { if (jv_get_kind(x) != JV_KIND_OBJECT) return jv_keys(x); From 232a245313e6b61071be4b0fa6c3de584cce7103 Mon Sep 17 00:00:00 2001 From: MaxBrandtner Date: Fri, 3 May 2024 10:43:52 +0200 Subject: [PATCH 2/7] (hopefully) fixes scoping issue in switch statement on build targets --- src/jv.c | 65 ++++++++++++++++++++++++++++++-------------------------- 1 file changed, 35 insertions(+), 30 deletions(-) diff --git a/src/jv.c b/src/jv.c index 36bbcff0d3..ace285a20a 100644 --- a/src/jv.c +++ b/src/jv.c @@ -1872,39 +1872,44 @@ jv jv_new(jv input){ return jv_invalid_with_msg(jv_new(jv_invalid_get_msg(jv_copy(input)))); case JV_KIND_OBJECT: case JV_KIND_ARRAY: - jv keys = jv_keys(jv_copy(input)); - size_t keys_length = jv_array_length(jv_copy(keys)); - - jv output_object; - if(jv_get_kind(input) == JV_KIND_OBJECT){ - output_object = jv_object(); - }else{ - output_object = jv_array(); - } - - for(size_t i = 0; i < keys_length; i++){ - jv key = JV_ARRAY(jv_new(jv_array_get(jv_copy(keys), i))); - - output_object = jv_setpath( - output_object,key, - jv_new( - jv_getpath(jv_copy(output_object), jv_copy(key)) - ) - ); + { + jv keys = jv_keys(jv_copy(input)); + size_t keys_length = jv_array_length(jv_copy(keys)); + + jv output_object; + if(jv_get_kind(input) == JV_KIND_OBJECT){ + output_object = jv_object(); + }else{ + output_object = jv_array(); + } + + for(size_t i = 0; i < keys_length; i++){ + jv key = JV_ARRAY(jv_new(jv_array_get(jv_copy(keys), i))); + + output_object = jv_setpath( + output_object,key, + jv_new( + jv_getpath(jv_copy(output_object), jv_copy(key)) + ) + ); + } + + jv_free(keys); + jv_free(input); + return output_object; } - - jv_free(keys); - jv_free(input); - - return output_object; case JV_KIND_STRING: - jv output_string = jv_string(jv_string_value(input)); - jv_free(input); - return output_string; + { + jv output_string = jv_string(jv_string_value(input)); + jv_free(input); + return output_string; + } case JV_KIND_NUMBER: - double val = jv_number_value(input); - jv_free(input); - return jv_number(val); + { + double val = jv_number_value(input); + jv_free(input); + return jv_number(val); + } case JV_KIND_TRUE: jv_free(input); return jv_true(); From c43ae9376e3099cf3b05214cff7117d3d26aca9e Mon Sep 17 00:00:00 2001 From: MaxBrandtner Date: Fri, 3 May 2024 10:54:25 +0200 Subject: [PATCH 3/7] renames jv_new to jv_clone --- src/jq_test.c | 2 +- src/jv.c | 8 ++++---- src/jv.h | 3 ++- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/jq_test.c b/src/jq_test.c index 40cdca5747..1dd3219287 100644 --- a/src/jq_test.c +++ b/src/jq_test.c @@ -508,7 +508,7 @@ static void jv_test() { } { - jv output = jv_new(jv_parse("{\"test\":[{\"some\":\"value\"}, 1, true, false, null]}")); + jv output = jv_clone(jv_parse("{\"test\":[{\"some\":\"value\"}, 1, true, false, null]}")); jv_free(output); } diff --git a/src/jv.c b/src/jv.c index ace285a20a..08256c30e8 100644 --- a/src/jv.c +++ b/src/jv.c @@ -1862,14 +1862,14 @@ jv jv_object_iter_value(jv object, int iter) { /* * Memory management */ -jv jv_new(jv input){ +jv jv_clone(jv input){ switch(jv_get_kind(input)){ case JV_KIND_INVALID: if(!jv_invalid_has_msg(jv_copy(input))){ jv_free(input); return jv_invalid(); } - return jv_invalid_with_msg(jv_new(jv_invalid_get_msg(jv_copy(input)))); + return jv_invalid_with_msg(jv_clone(jv_invalid_get_msg(jv_copy(input)))); case JV_KIND_OBJECT: case JV_KIND_ARRAY: { @@ -1884,11 +1884,11 @@ jv jv_new(jv input){ } for(size_t i = 0; i < keys_length; i++){ - jv key = JV_ARRAY(jv_new(jv_array_get(jv_copy(keys), i))); + jv key = JV_ARRAY(jv_clone(jv_array_get(jv_copy(keys), i))); output_object = jv_setpath( output_object,key, - jv_new( + jv_clone( jv_getpath(jv_copy(output_object), jv_copy(key)) ) ); diff --git a/src/jv.h b/src/jv.h index f19def01c6..a61a48761a 100644 --- a/src/jv.h +++ b/src/jv.h @@ -51,7 +51,8 @@ jv_kind jv_get_kind(jv); const char* jv_kind_name(jv_kind); static int jv_is_valid(jv x) { return jv_get_kind(x) != JV_KIND_INVALID; } -jv jv_new(jv); +//jv_clone() creates a deep copy of the input aka the content of the output will be identical to the input, but no shared memory exists between them +jv jv_clone(jv); jv jv_copy(jv); void jv_free(jv); From 29b398f7bb63f69c03d9129de22b676abb085efe Mon Sep 17 00:00:00 2001 From: MaxBrandtner Date: Fri, 3 May 2024 14:14:58 +0200 Subject: [PATCH 4/7] change jv_clone to jv_unshare --- src/jq_test.c | 2 +- src/jv.c | 8 ++++---- src/jv.h | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/jq_test.c b/src/jq_test.c index 1dd3219287..0c01cd56f0 100644 --- a/src/jq_test.c +++ b/src/jq_test.c @@ -508,7 +508,7 @@ static void jv_test() { } { - jv output = jv_clone(jv_parse("{\"test\":[{\"some\":\"value\"}, 1, true, false, null]}")); + jv output = jv_unshare(jv_parse("{\"test\":[{\"some\":\"value\"}, 1, true, false, null]}")); jv_free(output); } diff --git a/src/jv.c b/src/jv.c index 08256c30e8..b09744f3c2 100644 --- a/src/jv.c +++ b/src/jv.c @@ -1862,14 +1862,14 @@ jv jv_object_iter_value(jv object, int iter) { /* * Memory management */ -jv jv_clone(jv input){ +jv jv_unshare(jv input){ switch(jv_get_kind(input)){ case JV_KIND_INVALID: if(!jv_invalid_has_msg(jv_copy(input))){ jv_free(input); return jv_invalid(); } - return jv_invalid_with_msg(jv_clone(jv_invalid_get_msg(jv_copy(input)))); + return jv_invalid_with_msg(jv_unshare(jv_invalid_get_msg(jv_copy(input)))); case JV_KIND_OBJECT: case JV_KIND_ARRAY: { @@ -1884,11 +1884,11 @@ jv jv_clone(jv input){ } for(size_t i = 0; i < keys_length; i++){ - jv key = JV_ARRAY(jv_clone(jv_array_get(jv_copy(keys), i))); + jv key = JV_ARRAY(jv_unshare(jv_array_get(jv_copy(keys), i))); output_object = jv_setpath( output_object,key, - jv_clone( + jv_unshare( jv_getpath(jv_copy(output_object), jv_copy(key)) ) ); diff --git a/src/jv.h b/src/jv.h index a61a48761a..487eba030d 100644 --- a/src/jv.h +++ b/src/jv.h @@ -51,8 +51,8 @@ jv_kind jv_get_kind(jv); const char* jv_kind_name(jv_kind); static int jv_is_valid(jv x) { return jv_get_kind(x) != JV_KIND_INVALID; } -//jv_clone() creates a deep copy of the input aka the content of the output will be identical to the input, but no shared memory exists between them -jv jv_clone(jv); +//jv_unshare() creates a deep copy of the input aka the content of the output will be identical to the input, but no shared memory exists between them +jv jv_unshare(jv); jv jv_copy(jv); void jv_free(jv); From 440b1e4fa567cc0a5cbfa5240f5c05ce61585ac8 Mon Sep 17 00:00:00 2001 From: MaxBrandtner Date: Tue, 7 May 2024 10:55:10 +0200 Subject: [PATCH 5/7] makes jv_object and jv_array case more efficient for jv_unshare() --- src/jv.c | 53 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 17 deletions(-) diff --git a/src/jv.c b/src/jv.c index b09744f3c2..770234df18 100644 --- a/src/jv.c +++ b/src/jv.c @@ -1871,33 +1871,52 @@ jv jv_unshare(jv input){ } return jv_invalid_with_msg(jv_unshare(jv_invalid_get_msg(jv_copy(input)))); case JV_KIND_OBJECT: - case JV_KIND_ARRAY: { jv keys = jv_keys(jv_copy(input)); size_t keys_length = jv_array_length(jv_copy(keys)); - - jv output_object; - if(jv_get_kind(input) == JV_KIND_OBJECT){ - output_object = jv_object(); - }else{ - output_object = jv_array(); - } - + + jv output_object = jv_object(); + for(size_t i = 0; i < keys_length; i++){ - jv key = JV_ARRAY(jv_unshare(jv_array_get(jv_copy(keys), i))); - - output_object = jv_setpath( - output_object,key, - jv_unshare( - jv_getpath(jv_copy(output_object), jv_copy(key)) - ) - ); + jv key = jv_array_get(jv_copy(keys), i); + output_object = jv_object_set( + output_object, jv_unshare(key), + jv_unshare( + jv_object_get( + jv_copy(input), + jv_copy(key) + ) + ) + ); } jv_free(keys); jv_free(input); return output_object; } + case JV_KIND_ARRAY: + { + size_t amount = jv_array_length(jv_copy(input)); + + jv output_array = jv_array_sized(amount); + + for(size_t i = 0; i < amount; i++){ + output_array = jv_array_set( + output_array, + i, + jv_unshare( + jv_array_get( + jv_copy(input), + i + ) + ) + ); + } + + jv_free(input); + + return output_array; + } case JV_KIND_STRING: { jv output_string = jv_string(jv_string_value(input)); From e600eebabb71f85fb639ba906df70353e8103827 Mon Sep 17 00:00:00 2001 From: MaxBrandtner Date: Tue, 14 May 2024 14:55:23 +0200 Subject: [PATCH 6/7] Add basic unit-tests --- src/jq_test.c | 96 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 84 insertions(+), 12 deletions(-) diff --git a/src/jq_test.c b/src/jq_test.c index 0c01cd56f0..94ffee69d9 100644 --- a/src/jq_test.c +++ b/src/jq_test.c @@ -492,24 +492,96 @@ static void jv_test() { } { - jv input = jv_parse("{\"key\":[{\"this\":{\"some\":\"thing\"}}, 1, [true]]}"); - jv output = jv_paths(jv_copy(input)); - jv_dump(input, JV_PRINT_TAB); - jv_dump(output, JV_PRINT_TAB); + assert(jv_equal( + jv_paths( + jv_parse("{" + "\"key\":[" + "{\"this\":{\"some\":true}}," + "false," + "null," + "10," + "[true]" + "]" + "}") + ), + jv_parse("[" + "[\"key\"]," + "[\"key\", 0]," + "[\"key\", 0, \"this\"]," + "[\"key\", 0, \"this\", \"some\"]," + "[\"key\", 1]," + "[\"key\", 2]," + "[\"key\", 3]," + "[\"key\", 4]," + "[\"key\", 4, 0]" + "]") + )); + } { - jv input = jv_parse("{\"key\":{\"some\":{\"test\":\"value\"}, \"other\":\"thing\"}}"); - jv add = jv_parse("{\"some\":{\"test\":\"other\"}, \"added\":\"thing\"}"); - jv output = jv_addpath(jv_copy(input), JV_ARRAY(jv_string("key")), jv_copy(add)); - jv_dump(input, JV_PRINT_TAB); - jv_dump(add, JV_PRINT_TAB); - jv_dump(output, JV_PRINT_TAB); + assert(jv_equal( + jv_addpath( + jv_parse("{" + "\"key\":{" + "\"some\":{" + "\"test\":\"value\"" + "}," + "\"other\":\"thing\"" + "}" + "}"), + JV_ARRAY(jv_string("key")), + jv_parse("{" + "\"some\":{" + "\"test\":\"other\"" + "}," + "\"added\":\"thing\"" + "}") + ), + jv_parse("{" + "\"key\":{" + "\"some\":{" + "\"test\":\"other\"" + "}," + "\"other\":\"thing\"," + "\"added\":\"thing\"" + "}" + "}") + ) + ); + } { - jv output = jv_unshare(jv_parse("{\"test\":[{\"some\":\"value\"}, 1, true, false, null]}")); + jv initial = jv_parse("{\"test\":[{\"some\":\"value\"}, 1, true, false, null]}"); + jv new = jv_unshare(jv_copy(initial)); + + assert(jv_equal(jv_copy(initial), jv_copy(new))); + assert(!jv_identical(jv_copy(initial), jv_copy(new))); + + jv paths = jv_paths(jv_copy(initial)); + + size_t paths_length = jv_array_length(jv_copy(paths)); + + for(size_t i = 0; i < paths_length; i++){ + jv path_i = jv_array_get(jv_copy(paths), i); + assert(!jv_identical( + jv_getpath( + jv_copy(initial), + jv_copy(path_i) + ), + jv_getpath( + jv_copy(new), + jv_copy(path_i) + ) + )); + + jv_free(path_i); + } + + jv_free(initial); + jv_free(new); + jv_free(paths); - jv_free(output); } } From cc8f7713de90f0e6cd9db1f8a0b22b64250b0af4 Mon Sep 17 00:00:00 2001 From: MaxBrandtner Date: Sat, 8 Jun 2024 16:13:55 +0200 Subject: [PATCH 7/7] Implements jv_is_unshared() --- src/jq_test.c | 87 ++--------------------------------------- src/jv.c | 53 +++++++++++++++++++++++-- src/jv.h | 3 +- src/jv_aux.c | 104 +------------------------------------------------- 4 files changed, 55 insertions(+), 192 deletions(-) diff --git a/src/jq_test.c b/src/jq_test.c index 94ffee69d9..a83640c4fa 100644 --- a/src/jq_test.c +++ b/src/jq_test.c @@ -492,96 +492,17 @@ static void jv_test() { } { - assert(jv_equal( - jv_paths( - jv_parse("{" - "\"key\":[" - "{\"this\":{\"some\":true}}," - "false," - "null," - "10," - "[true]" - "]" - "}") - ), - jv_parse("[" - "[\"key\"]," - "[\"key\", 0]," - "[\"key\", 0, \"this\"]," - "[\"key\", 0, \"this\", \"some\"]," - "[\"key\", 1]," - "[\"key\", 2]," - "[\"key\", 3]," - "[\"key\", 4]," - "[\"key\", 4, 0]" - "]") - )); + jv test_unshared = JV_OBJECT(jv_string("some"), JV_ARRAY(jv_string("other"), jv_true())); - } - - { - assert(jv_equal( - jv_addpath( - jv_parse("{" - "\"key\":{" - "\"some\":{" - "\"test\":\"value\"" - "}," - "\"other\":\"thing\"" - "}" - "}"), - JV_ARRAY(jv_string("key")), - jv_parse("{" - "\"some\":{" - "\"test\":\"other\"" - "}," - "\"added\":\"thing\"" - "}") - ), - jv_parse("{" - "\"key\":{" - "\"some\":{" - "\"test\":\"other\"" - "}," - "\"other\":\"thing\"," - "\"added\":\"thing\"" - "}" - "}") - ) - ); + assert(jv_is_unshared(test_unshared)); + jv_free(test_unshared); - } - - { jv initial = jv_parse("{\"test\":[{\"some\":\"value\"}, 1, true, false, null]}"); jv new = jv_unshare(jv_copy(initial)); assert(jv_equal(jv_copy(initial), jv_copy(new))); - assert(!jv_identical(jv_copy(initial), jv_copy(new))); - - jv paths = jv_paths(jv_copy(initial)); - - size_t paths_length = jv_array_length(jv_copy(paths)); - - for(size_t i = 0; i < paths_length; i++){ - jv path_i = jv_array_get(jv_copy(paths), i); - assert(!jv_identical( - jv_getpath( - jv_copy(initial), - jv_copy(path_i) - ), - jv_getpath( - jv_copy(new), - jv_copy(path_i) - ) - )); - - jv_free(path_i); - } - + assert(jv_is_unshared(new)); jv_free(initial); jv_free(new); - jv_free(paths); - } } diff --git a/src/jv.c b/src/jv.c index 770234df18..cc42ea226a 100644 --- a/src/jv.c +++ b/src/jv.c @@ -1865,11 +1865,13 @@ jv jv_object_iter_value(jv object, int iter) { jv jv_unshare(jv input){ switch(jv_get_kind(input)){ case JV_KIND_INVALID: - if(!jv_invalid_has_msg(jv_copy(input))){ - jv_free(input); - return jv_invalid(); + { + if(!jv_invalid_has_msg(jv_copy(input))){ + jv_free(input); + return jv_invalid(); + } + return jv_invalid_with_msg(jv_unshare(jv_invalid_get_msg(jv_copy(input)))); } - return jv_invalid_with_msg(jv_unshare(jv_invalid_get_msg(jv_copy(input)))); case JV_KIND_OBJECT: { jv keys = jv_keys(jv_copy(input)); @@ -1943,6 +1945,49 @@ jv jv_unshare(jv input){ } } +int jv_is_unshared(jv a){ + if(jv_get_refcnt(a) != 1){ + fprintf(stderr, "input refcnt != 1\n"); + return 1; + } + if(jv_get_kind(a) == JV_KIND_OBJECT){ + jv keys = jv_keys(jv_copy(a)); + size_t keys_length = jv_array_length(jv_copy(keys)); + for(size_t i = 0; i < keys_length; i++){ + jv key = jv_array_get(jv_copy(keys), i); + if(jv_get_refcnt(key) > 3){ + fprintf(stderr, "key in object does not have refcnt 1, %d\n", jv_get_refcnt(key)); + jv_free(key); + jv_free(keys); + return 0; + } + + jv value = jv_object_get(jv_copy(a), key); + jv_free(value); + if(!jv_is_unshared(value)){ + fprintf(stderr, "failed on object\n"); + jv_free(keys); + return 0; + } + } + + jv_free(keys); + + }else if(jv_get_kind(a) == JV_KIND_ARRAY){ + size_t a_length = jv_array_length(jv_copy(a)); + for(size_t i = 0; i < a_length; i++){ + jv value = jv_array_get(jv_copy(a), i); + jv_free(value); + if(!jv_is_unshared(value)){ + fprintf(stderr, "failed on array value\n"); + return 0; + } + } + } + + return 1; +} + jv jv_copy(jv j) { if (JVP_IS_ALLOCATED(j)) { jvp_refcnt_inc(j.u.ptr); diff --git a/src/jv.h b/src/jv.h index 487eba030d..d31f5b1ff8 100644 --- a/src/jv.h +++ b/src/jv.h @@ -53,6 +53,7 @@ static int jv_is_valid(jv x) { return jv_get_kind(x) != JV_KIND_INVALID; } //jv_unshare() creates a deep copy of the input aka the content of the output will be identical to the input, but no shared memory exists between them jv jv_unshare(jv); +int jv_is_unshared(jv); jv jv_copy(jv); void jv_free(jv); @@ -258,10 +259,8 @@ jv jv_get(jv, jv); jv jv_set(jv, jv, jv); jv jv_has(jv, jv); jv jv_setpath(jv, jv, jv); -jv jv_addpath(jv, jv, jv); jv jv_getpath(jv, jv); jv jv_delpaths(jv, jv); -jv jv_paths(jv); jv jv_keys(jv /*object or array*/); jv jv_keys_unsorted(jv /*object or array*/); int jv_cmp(jv, jv); diff --git a/src/jv_aux.c b/src/jv_aux.c index a1fa00dcc2..24ffb032c0 100644 --- a/src/jv_aux.c +++ b/src/jv_aux.c @@ -427,69 +427,7 @@ jv jv_setpath(jv root, jv path, jv value) { return jv_set(root, pathcurr, jv_setpath(subroot, pathrest, value)); } -jv jv_addpath(jv root, jv path, jv add){ - if(jv_get_kind(path) != JV_KIND_ARRAY || !jv_is_valid(add)){ - jv_free(root); - jv_free(path); - jv_free(add); - return jv_invalid(); - } - - if(jv_get_kind(root) != JV_KIND_OBJECT && jv_get_kind(root) != JV_KIND_ARRAY){ - jv_free(root); - - if(!jv_equal(jv_copy(path), jv_array())){ - jv_free(path); - jv_free(add); - return jv_invalid(); - } - - jv_free(path); - - return add; - } - - if(!jv_equal(jv_copy(path), jv_array())){ - return jv_setpath(root, path, jv_addpath(jv_getpath(jv_copy(root), jv_copy(path)), jv_array(), add)); - } - - jv root_paths = jv_paths(jv_copy(root)); - jv add_paths = jv_paths(jv_copy(add)); - - size_t add_paths_length = jv_array_length(jv_copy(add_paths)); - - for(size_t i = 0; i < add_paths_length; i++){ - jv add_path = jv_array_get(jv_copy(add_paths), i); - jv add_path_value = jv_getpath(jv_copy(add), jv_copy(add_path)); - - if(!jv_is_valid(add_path_value) || jv_get_kind(add_path_value) == JV_KIND_NULL){ - jv_free(root); - jv_free(path); - jv_free(add); - jv_free(root_paths); - jv_free(add_paths); - jv_free(add_path); - jv_free(add_path_value); - return jv_invalid(); - } - - if(jv_get_kind(add_path_value) == JV_KIND_OBJECT || jv_get_kind(add_path_value) == JV_KIND_ARRAY){ - jv_free(add_path); - jv_free(add_path_value); - continue; - } - - root = jv_setpath(root, add_path, add_path_value); - } - - jv_free(path); - jv_free(add); - - jv_free(root_paths); - jv_free(add_paths); - - return root; -} + jv jv_getpath(jv root, jv path) { if (jv_get_kind(path) != JV_KIND_ARRAY) { @@ -602,46 +540,6 @@ static int string_cmp(const void* pa, const void* pb){ return r; } -jv jv_paths(jv input){ - if(jv_get_kind(input) != JV_KIND_OBJECT && jv_get_kind(input) != JV_KIND_ARRAY){ - jv_free(input); - return jv_invalid(); - } - - jv keys = jv_keys(jv_copy(input)); - - size_t keys_length = jv_array_length(jv_copy(keys)); - - jv output = jv_array(); - - for(size_t i = 0; i < keys_length; i++){ - jv key = jv_array_get(jv_copy(keys), i); - jv insert_paths = jv_paths(jv_getpath(jv_copy(input), JV_ARRAY(jv_copy(key)))); - - output = jv_array_append(output, JV_ARRAY(jv_copy(key))); - - if(jv_get_kind(insert_paths) == JV_KIND_INVALID){ - jv_free(insert_paths); - jv_free(key); - - continue; - } - - size_t paths_length = jv_array_length(jv_copy(insert_paths)); - - for(size_t j = 0; j < paths_length; j++){ - output = jv_array_append(output, jv_array_concat(JV_ARRAY(jv_copy(key)), jv_array_get(jv_copy(insert_paths), j))); - } - - jv_free(key); - jv_free(insert_paths); - } - - jv_free(input); - jv_free(keys); - - return output; -} jv jv_keys_unsorted(jv x) { if (jv_get_kind(x) != JV_KIND_OBJECT)