From 3f968e7dd8aace0d4327c04402d59b8e81c90b87 Mon Sep 17 00:00:00 2001 From: Andreev Gregory Date: Fri, 9 Aug 2024 22:50:55 +0300 Subject: [PATCH] Added operator ==, added misuse throw on coying object to part of itself --- src/library/libjsonincpp/inner_storage.cpp | 154 ++++++++++++++++++- src/library/libjsonincpp/inner_storage.h | 4 + src/library/libjsonincpp/integer.cpp | 12 +- src/library/libjsonincpp/integer.h | 3 + src/library/libjsonincpp/jsonobj.cpp | 6 +- src/library/libjsonincpp/jsonobj.h | 3 + src/library/libjsonincpp/quality_of_life.cpp | 12 ++ src/tests/test0.cpp | 41 ++++- 8 files changed, 223 insertions(+), 12 deletions(-) diff --git a/src/library/libjsonincpp/inner_storage.cpp b/src/library/libjsonincpp/inner_storage.cpp index 0a9ec27..4b243a4 100644 --- a/src/library/libjsonincpp/inner_storage.cpp +++ b/src/library/libjsonincpp/inner_storage.cpp @@ -99,7 +99,7 @@ namespace json { } /* Basic exception guarantee */ - void setup_it_plus_double_wayback(JSON& dest_child, const JSON& src_child, JSON* dest_wayback, const JSON* src_wayback) + void setup_it_plus_double_wayback_at_copying(JSON& dest_child, const JSON& src_child, JSON* dest_wayback, const JSON* src_wayback) { assert(dest_child.isNull()); if (src_child.type == array) { @@ -132,7 +132,7 @@ namespace json { copy_childless(destination, source); return; } - setup_it_plus_double_wayback(destination, source, NULL, NULL); + setup_it_plus_double_wayback_at_copying(destination, source, NULL, NULL); JSON* dest_cur = &destination; const JSON* src_cur = &source; while (dest_cur) { @@ -153,7 +153,7 @@ namespace json { copy_childless(dest_child, src_child); goto it_check; } - setup_it_plus_double_wayback(dest_child, src_child, dest_cur, src_cur); + setup_it_plus_double_wayback_at_copying(dest_child, src_child, dest_cur, src_cur); dest_cur = &dest_child; src_cur = &src_child; } @@ -166,13 +166,13 @@ namespace json { src_cur = static_cast(dd_src.wayback); } else { JSON& src_child = dd_src.it->second; - JSON& dest_child = dd_dest.data[dd_src.it->first]; // This function blows. ... I mean throws + JSON& dest_child = dd_dest.data[dd_src.it->first]; // This function throws ++dd_src.it; if (!src_child.isNatalistic()) { copy_childless(dest_child, src_child); goto it_check2; } - setup_it_plus_double_wayback(dest_child, src_child, dest_cur, src_cur); + setup_it_plus_double_wayback_at_copying(dest_child, src_child, dest_cur, src_cur); dest_cur = &dest_child; src_cur = &src_child; } @@ -180,4 +180,146 @@ namespace json { } assert(!src_cur); } -} \ No newline at end of file + + /* returns false if immediate unequality is obvious, true if both are arrays, both are dicts, or A == B */ + bool eq_compare_simple(const JSON &A, const JSON &B) { + json_t t = A.type; + if (t != B.type) + return false; + if (t == integer) { + if (A.asInteger() != B.asInteger()) + return false; + } + if (t == string) { + if (A.asString() != B.asString()) + return false; + } + return true; + } + + template + void setup_it_plus_double_wayback_at_cmp_half( + const JSON& A_child, const JSON& B_child, const JSON* A_wayback, const JSON* B_wayback) { + DataT& dt_A = *static_cast(A_child.value); + DataT& dt_B = *static_cast(B_child.value); + dt_A.it = dt_A.data.begin(); + dt_B.it = dt_B.data.begin(); + dt_A.wayback = (void*)A_wayback; + dt_B.wayback = (void*)B_wayback; + } + + void setup_it_plus_double_wayback_at_cmp(const JSON& A_child, const JSON& B_child, const JSON* A_wayback, const JSON* B_wayback) { + assert(A_child.type == B_child.type); + if (A_child.type == array) { + setup_it_plus_double_wayback_at_cmp_half(A_child, B_child, A_wayback, B_wayback); + } else if (A_child.type == dictionary) { + setup_it_plus_double_wayback_at_cmp_half(A_child, B_child, A_wayback, B_wayback); + } else + assert(false); + } + + bool eq_compare_json(const JSON &A, const JSON &B) noexcept{ + if (!eq_compare_simple(A, B)) + return false; + if (!A.isNatalistic()) + return true; + setup_it_plus_double_wayback_at_cmp(A, B, NULL, NULL); + const JSON* cur_a = &A; + const JSON* cur_b = &B; + while (cur_a) { + assert(cur_b); + if (cur_a->type == array) { + ArrayData& dt_a = *static_cast(cur_a->value); + ArrayData& dt_b = *static_cast(cur_b->value); + again: + if (dt_a.it == dt_a.data.end()) { + if (dt_b.it != dt_b.data.end()) + return false; + cur_a = static_cast(dt_a.wayback); + cur_b = static_cast(dt_b.wayback); + } else { + if (dt_b.it == dt_b.data.end()) + return false; + JSON& child_A = *(dt_a.it++); + JSON& child_B = *(dt_b.it++); + if (!eq_compare_simple(child_A, child_B)) + return false; + if (!child_A.isNatalistic()) + goto again; + setup_it_plus_double_wayback_at_cmp(child_A, child_B, cur_a, cur_b); + cur_a = &child_A; + cur_b = &child_B; + } + } else if (cur_a->type == dictionary) { + DictionaryData& dt_a = *static_cast(cur_a->value); + DictionaryData& dt_b = *static_cast(cur_b->value); + again2: + if (dt_a.it == dt_a.data.end()) { + if (dt_b.it != dt_b.data.end()) + return false; + cur_a = static_cast(dt_a.wayback); + cur_b = static_cast(dt_b.wayback); + } else { + if (dt_b.it == dt_b.data.end()) + return false; + if (dt_a.it->first != dt_b.it->first) + return false; + JSON& child_A = (dt_a.it++)->second; + JSON& child_B = (dt_b.it++)->second; + if (!eq_compare_simple(child_A, child_B)) + return false; + if (!child_A.isNatalistic()) + goto again2; + setup_it_plus_double_wayback_at_cmp(child_A, child_B, cur_a, cur_b); + cur_a = &child_A; + cur_b = &child_B; + } + } + } + assert(!cur_b); + return true; + } + + bool is_subtree_of(const JSON &A, const JSON &B) noexcept { + if (!B.isNatalistic()) + return &A == &B; + const JSON* current = &B; + setup_nr_iterators(B, NULL); + while (current) { + if (current == &A) + return true; + if (current->type == array) { + ArrayData& ad = *static_cast(current->value); + it_check: + if (ad.it == ad.data.end()) { + current = static_cast(ad.wayback); + } else { + JSON& child = *(ad.it++); + if (!child.isNatalistic()){ + if (&A == &child) + return true; + goto it_check; + } + setup_nr_iterators(child, (void*)current); + current = &child; + } + } else if (current->type == dictionary) { + DictionaryData& ad = *static_cast(current->value); + it_check2: + if (ad.it == ad.data.end()) { + current = static_cast(ad.wayback); + } else { + JSON& child = (ad.it++)->second; + if (!child.isNatalistic()){ + if (&A == &child) + return true; + goto it_check2; + } + setup_nr_iterators(child, (void*)current); + current = &child; + } + } + } + return false; + } +} diff --git a/src/library/libjsonincpp/inner_storage.h b/src/library/libjsonincpp/inner_storage.h index 978498e..08d40cc 100644 --- a/src/library/libjsonincpp/inner_storage.h +++ b/src/library/libjsonincpp/inner_storage.h @@ -32,6 +32,10 @@ namespace json { void nullify(JSON& obj) noexcept; void copy_json(JSON& destination, const JSON& source); + + bool eq_compare_json(const JSON& A, const JSON& B) noexcept; + + bool is_subtree_of(const JSON& A, const JSON& B) noexcept; } // #define get_wayback(data) static_cast diff --git a/src/library/libjsonincpp/integer.cpp b/src/library/libjsonincpp/integer.cpp index f2e11ba..2065f38 100644 --- a/src/library/libjsonincpp/integer.cpp +++ b/src/library/libjsonincpp/integer.cpp @@ -39,11 +39,21 @@ namespace json { int64_t Integer::get_int() const { if (uncomprehendable_horror) - return 9999999; + return INT64_MAX; return value; } Integer::~Integer() { free(uncomprehendable_horror); } + + bool Integer::operator==(const Integer &other) { + if (uncomprehendable_horror || other.uncomprehendable_horror) + return to_string() == other.to_string(); + return value == other.value; + } + + bool Integer::operator!=(const Integer &other) { + return !(*this == other); + } } diff --git a/src/library/libjsonincpp/integer.h b/src/library/libjsonincpp/integer.h index fa1922a..20a9683 100644 --- a/src/library/libjsonincpp/integer.h +++ b/src/library/libjsonincpp/integer.h @@ -24,6 +24,9 @@ namespace json { int64_t get_int() const; ~Integer(); + + bool operator==(const Integer& other); + bool operator!=(const Integer& other); }; } diff --git a/src/library/libjsonincpp/jsonobj.cpp b/src/library/libjsonincpp/jsonobj.cpp index edd1a90..e21ec63 100644 --- a/src/library/libjsonincpp/jsonobj.cpp +++ b/src/library/libjsonincpp/jsonobj.cpp @@ -68,8 +68,12 @@ namespace json { constr_end } - JSON & JSON::operator=(const JSON &other) { + JSON& JSON::operator=(const JSON &other) { /* This is another one of those super serious functions that must not be recursive no matter what */ + if (is_subtree_of(*this, other)) + throw misuse("Copying json tree to it's subtree"); + if (is_subtree_of(other, *this)) + throw misuse("Copying json-subtree to json object"); nullify(*this); copy_json(*this, other); return *this; diff --git a/src/library/libjsonincpp/jsonobj.h b/src/library/libjsonincpp/jsonobj.h index 1832ce4..6f2c07d 100644 --- a/src/library/libjsonincpp/jsonobj.h +++ b/src/library/libjsonincpp/jsonobj.h @@ -87,6 +87,9 @@ namespace json { JSON& operator=(const Integer& V); JSON& operator=(const char* V); JSON& operator=(const std::string& V); + + bool operator==(const JSON& B) const; + bool operator!=(const JSON& B) const; }; struct ImaginaryKeyChainEValue { diff --git a/src/library/libjsonincpp/quality_of_life.cpp b/src/library/libjsonincpp/quality_of_life.cpp index 71565dd..54d636a 100644 --- a/src/library/libjsonincpp/quality_of_life.cpp +++ b/src/library/libjsonincpp/quality_of_life.cpp @@ -117,4 +117,16 @@ namespace json { type = string; return *this; } + + bool JSON::operator==(const JSON &B) const { + if (this == &B) + return true; + if (is_subtree_of(*this, B) || is_subtree_of(B, *this)) + return false; + return eq_compare_json(*this, B); + } + + bool JSON::operator!=(const JSON &B) const { + return !eq_compare_json(*this, B); + } } diff --git a/src/tests/test0.cpp b/src/tests/test0.cpp index b4f0f2c..09ba6e9 100644 --- a/src/tests/test0.cpp +++ b/src/tests/test0.cpp @@ -8,10 +8,43 @@ void prettyprint_json(const JSON& obj) { printf("%s", generate_str(obj, print_pretty).c_str()); } +void test2(const JSON& A, const JSON& B, bool answer) { + if ((A == B) == answer) + printf("Test passed\n"); + else { + fprintf(stderr, "Test failed"); + abort(); + } +} + +void test(const JSON& A, const JSON& B, bool answer) { + test2(A, B, answer); + test2(B, A, answer); +} + +void test_obvious(const JSON& A) { + test(A, A, true); + JSON B = A; + test(B, A, true); + /* Let's get real */ + JSON big; + big[1] = A; + test(big, A, false); + big[0] = A; + test(*big[0], *big[1], true); +} + int main() { - std::string text = "{\"\":\"\", \"true\":true, \"asd\" : { \"aaa\" : [[[[[[[123, 123, 13123123]]]]]]]}} "; - JSON j; - j = parse_str_flawless(text); - prettyprint_json(j); + test_obvious(parse_str_flawless("{ \"aaa\": true, \"2\":[true]}")); + test_obvious(parse_str_flawless("{ \"aa\": true, \"tttt\": [true, false]}")); + test_obvious(parse_str_flawless("[[[]]]")); + test_obvious(parse_str_flawless("[[[\"asdasdasdasd\", {\"aaa\" : 12311, \"\":\"\"}]]]")); + test(parse_str_flawless("1321231231231231231231231231231231"), parse_str_flawless("-132123123123123123123123123123123123"), false); + test(parse_str_flawless("1321231231231231231231231231231231"), parse_str_flawless("-132123123123123123123.123123123123123"), false); + test(parse_str_flawless("999999999999999999"), parse_str_flawless("999999999999999999"), true); + test(parse_str_flawless("9999999999999999999"), parse_str_flawless("9999999999999999999"), true); + test(parse_str_flawless("132123123123123123123123123123123123"), parse_str_flawless("132123123123123123123123123123123123"), true); + test(parse_str_flawless("{}"), parse_str_flawless("{}"), true); + test(parse_str_flawless("{}"), parse_str_flawless("true"), false); return 0; } \ No newline at end of file