Added operator ==, added misuse throw on coying object to part of itself

This commit is contained in:
Андреев Григорий 2024-08-09 22:50:55 +03:00
parent f37daf3494
commit 3f968e7dd8
8 changed files with 223 additions and 12 deletions

View File

@ -99,7 +99,7 @@ namespace json {
} }
/* Basic exception guarantee */ /* 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()); assert(dest_child.isNull());
if (src_child.type == array) { if (src_child.type == array) {
@ -132,7 +132,7 @@ namespace json {
copy_childless(destination, source); copy_childless(destination, source);
return; 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; JSON* dest_cur = &destination;
const JSON* src_cur = &source; const JSON* src_cur = &source;
while (dest_cur) { while (dest_cur) {
@ -153,7 +153,7 @@ namespace json {
copy_childless(dest_child, src_child); copy_childless(dest_child, src_child);
goto it_check; 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; dest_cur = &dest_child;
src_cur = &src_child; src_cur = &src_child;
} }
@ -166,13 +166,13 @@ namespace json {
src_cur = static_cast<const JSON*>(dd_src.wayback); src_cur = static_cast<const JSON*>(dd_src.wayback);
} else { } else {
JSON& src_child = dd_src.it->second; 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; ++dd_src.it;
if (!src_child.isNatalistic()) { if (!src_child.isNatalistic()) {
copy_childless(dest_child, src_child); copy_childless(dest_child, src_child);
goto it_check2; 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; dest_cur = &dest_child;
src_cur = &src_child; src_cur = &src_child;
} }
@ -180,4 +180,146 @@ namespace json {
} }
assert(!src_cur); assert(!src_cur);
} }
/* 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<typename DataT>
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<DataT*>(A_child.value);
DataT& dt_B = *static_cast<DataT*>(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<ArrayData>(A_child, B_child, A_wayback, B_wayback);
} else if (A_child.type == dictionary) {
setup_it_plus_double_wayback_at_cmp_half<DictionaryData>(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<ArrayData*>(cur_a->value);
ArrayData& dt_b = *static_cast<ArrayData*>(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<const JSON*>(dt_a.wayback);
cur_b = static_cast<const JSON*>(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<DictionaryData*>(cur_a->value);
DictionaryData& dt_b = *static_cast<DictionaryData*>(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<const JSON*>(dt_a.wayback);
cur_b = static_cast<const JSON*>(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<ArrayData*>(current->value);
it_check:
if (ad.it == ad.data.end()) {
current = static_cast<JSON*>(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<DictionaryData*>(current->value);
it_check2:
if (ad.it == ad.data.end()) {
current = static_cast<JSON*>(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;
}
} }

View File

@ -32,6 +32,10 @@ namespace json {
void nullify(JSON& obj) noexcept; void nullify(JSON& obj) noexcept;
void copy_json(JSON& destination, const JSON& source); 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<JSON*&> // #define get_wayback(data) static_cast<JSON*&>

View File

@ -39,11 +39,21 @@ namespace json {
int64_t Integer::get_int() const { int64_t Integer::get_int() const {
if (uncomprehendable_horror) if (uncomprehendable_horror)
return 9999999; return INT64_MAX;
return value; return value;
} }
Integer::~Integer() { Integer::~Integer() {
free(uncomprehendable_horror); 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);
}
} }

View File

@ -24,6 +24,9 @@ namespace json {
int64_t get_int() const; int64_t get_int() const;
~Integer(); ~Integer();
bool operator==(const Integer& other);
bool operator!=(const Integer& other);
}; };
} }

View File

@ -70,6 +70,10 @@ namespace json {
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 */ /* 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); nullify(*this);
copy_json(*this, other); copy_json(*this, other);
return *this; return *this;

View File

@ -87,6 +87,9 @@ namespace json {
JSON& operator=(const Integer& V); JSON& operator=(const Integer& V);
JSON& operator=(const char* V); JSON& operator=(const char* V);
JSON& operator=(const std::string& V); JSON& operator=(const std::string& V);
bool operator==(const JSON& B) const;
bool operator!=(const JSON& B) const;
}; };
struct ImaginaryKeyChainEValue { struct ImaginaryKeyChainEValue {

View File

@ -117,4 +117,16 @@ namespace json {
type = string; type = string;
return *this; 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);
}
} }

View File

@ -8,10 +8,43 @@ void prettyprint_json(const JSON& obj) {
printf("%s", generate_str(obj, print_pretty).c_str()); 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() { int main() {
std::string text = "{\"\":\"\", \"true\":true, \"asd\" : { \"aaa\" : [[[[[[[123, 123, 13123123]]]]]]]}} "; test_obvious(parse_str_flawless("{ \"aaa\": true, \"2\":[true]}"));
JSON j; test_obvious(parse_str_flawless("{ \"aa\": true, \"tttt\": [true, false]}"));
j = parse_str_flawless(text); test_obvious(parse_str_flawless("[[[]]]"));
prettyprint_json(j); 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; return 0;
} }