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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user