Added operator ==, added misuse throw on coying object to part of itself
This commit is contained in:
parent
f37daf3494
commit
3f968e7dd8
@ -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<const JSON*>(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);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
@ -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<JSON*&>
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,9 @@ namespace json {
|
||||
int64_t get_int() const;
|
||||
|
||||
~Integer();
|
||||
|
||||
bool operator==(const Integer& other);
|
||||
bool operator!=(const Integer& other);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user