267 lines
		
	
	
	
		
			7.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			267 lines
		
	
	
	
		
			7.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
//
 | 
						|
// immer: immutable data structures for C++
 | 
						|
// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
 | 
						|
//
 | 
						|
// This software is distributed under the Boost Software License, Version 1.0.
 | 
						|
// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
 | 
						|
//
 | 
						|
 | 
						|
#include "test/dada.hpp"
 | 
						|
#include "test/transient_tester.hpp"
 | 
						|
#include "test/util.hpp"
 | 
						|
 | 
						|
#include <catch.hpp>
 | 
						|
 | 
						|
#ifndef VECTOR_T
 | 
						|
#error "define the vector template to use in VECTOR_T"
 | 
						|
#endif
 | 
						|
 | 
						|
#ifndef VECTOR_TRANSIENT_T
 | 
						|
#error "define the vector template to use in VECTOR_TRANSIENT_T"
 | 
						|
#endif
 | 
						|
 | 
						|
template <typename V = VECTOR_T<unsigned>>
 | 
						|
auto make_test_vector(unsigned min, unsigned max)
 | 
						|
{
 | 
						|
    auto v = V{};
 | 
						|
    for (auto i = min; i < max; ++i)
 | 
						|
        v = v.push_back({i});
 | 
						|
    return v;
 | 
						|
}
 | 
						|
 | 
						|
TEST_CASE("from vector and to vector")
 | 
						|
{
 | 
						|
    constexpr auto n = 100u;
 | 
						|
 | 
						|
    auto v = make_test_vector(0, n).transient();
 | 
						|
    CHECK_VECTOR_EQUALS(v, boost::irange(0u, n));
 | 
						|
 | 
						|
    auto p = v.persistent();
 | 
						|
    CHECK_VECTOR_EQUALS(p, boost::irange(0u, n));
 | 
						|
}
 | 
						|
 | 
						|
TEST_CASE("protect persistence")
 | 
						|
{
 | 
						|
    auto v = VECTOR_T<unsigned>{}.transient();
 | 
						|
    v.push_back(12);
 | 
						|
    auto p = v.persistent();
 | 
						|
    v.set(0, 42);
 | 
						|
    CHECK(p[0] == 12);
 | 
						|
    CHECK(v[0] == 42);
 | 
						|
}
 | 
						|
 | 
						|
TEST_CASE("push back move")
 | 
						|
{
 | 
						|
    using vector_t = VECTOR_T<unsigned>;
 | 
						|
 | 
						|
    auto v = vector_t{};
 | 
						|
 | 
						|
    auto check_move = [&](vector_t&& x) -> vector_t&& {
 | 
						|
        if (vector_t::memory_policy::use_transient_rvalues)
 | 
						|
            CHECK(&x == &v);
 | 
						|
        else
 | 
						|
            CHECK(&x != &v);
 | 
						|
        return std::move(x);
 | 
						|
    };
 | 
						|
 | 
						|
    v                = check_move(std::move(v).push_back(0));
 | 
						|
    v                = check_move(std::move(v).push_back(1));
 | 
						|
    v                = check_move(std::move(v).push_back(2));
 | 
						|
    auto addr_before = &v[0];
 | 
						|
    v                = check_move(std::move(v).push_back(3));
 | 
						|
    auto addr_after  = &v[0];
 | 
						|
 | 
						|
    if (vector_t::memory_policy::use_transient_rvalues)
 | 
						|
        CHECK(addr_before == addr_after);
 | 
						|
    else
 | 
						|
        CHECK(addr_before != addr_after);
 | 
						|
 | 
						|
    CHECK_VECTOR_EQUALS(v, boost::irange(0u, 4u));
 | 
						|
}
 | 
						|
 | 
						|
TEST_CASE("set move")
 | 
						|
{
 | 
						|
    using vector_t = VECTOR_T<unsigned>;
 | 
						|
 | 
						|
    auto v = vector_t{};
 | 
						|
 | 
						|
    auto check_move = [&](vector_t&& x) -> vector_t&& {
 | 
						|
        if (vector_t::memory_policy::use_transient_rvalues)
 | 
						|
            CHECK(&x == &v);
 | 
						|
        else
 | 
						|
            CHECK(&x != &v);
 | 
						|
        return std::move(x);
 | 
						|
    };
 | 
						|
 | 
						|
    v = v.push_back(0);
 | 
						|
 | 
						|
    auto addr_before = &v[0];
 | 
						|
    v                = check_move(std::move(v).set(0, 1));
 | 
						|
    auto addr_after  = &v[0];
 | 
						|
 | 
						|
    if (vector_t::memory_policy::use_transient_rvalues)
 | 
						|
        CHECK(addr_before == addr_after);
 | 
						|
    else
 | 
						|
        CHECK(addr_before != addr_after);
 | 
						|
 | 
						|
    CHECK_VECTOR_EQUALS(v, boost::irange(1u, 2u));
 | 
						|
}
 | 
						|
 | 
						|
TEST_CASE("update move")
 | 
						|
{
 | 
						|
    using vector_t = VECTOR_T<unsigned>;
 | 
						|
 | 
						|
    auto v = vector_t{};
 | 
						|
 | 
						|
    auto check_move = [&](vector_t&& x) -> vector_t&& {
 | 
						|
        if (vector_t::memory_policy::use_transient_rvalues)
 | 
						|
            CHECK(&x == &v);
 | 
						|
        else
 | 
						|
            CHECK(&x != &v);
 | 
						|
        return std::move(x);
 | 
						|
    };
 | 
						|
 | 
						|
    v = v.push_back(0);
 | 
						|
 | 
						|
    auto addr_before = &v[0];
 | 
						|
    v = check_move(std::move(v).update(0, [](auto x) { return x + 1; }));
 | 
						|
    auto addr_after = &v[0];
 | 
						|
 | 
						|
    if (vector_t::memory_policy::use_transient_rvalues)
 | 
						|
        CHECK(addr_before == addr_after);
 | 
						|
    else
 | 
						|
        CHECK(addr_before != addr_after);
 | 
						|
 | 
						|
    CHECK_VECTOR_EQUALS(v, boost::irange(1u, 2u));
 | 
						|
}
 | 
						|
 | 
						|
TEST_CASE("take move")
 | 
						|
{
 | 
						|
    using vector_t = VECTOR_T<unsigned>;
 | 
						|
 | 
						|
    auto v = vector_t{};
 | 
						|
 | 
						|
    auto check_move = [&](vector_t&& x) -> vector_t&& {
 | 
						|
        if (vector_t::memory_policy::use_transient_rvalues)
 | 
						|
            CHECK(&x == &v);
 | 
						|
        else
 | 
						|
            CHECK(&x != &v);
 | 
						|
        return std::move(x);
 | 
						|
    };
 | 
						|
 | 
						|
    v = v.push_back(0).push_back(1);
 | 
						|
 | 
						|
    auto addr_before = &v[0];
 | 
						|
    v                = check_move(std::move(v).take(1));
 | 
						|
    auto addr_after  = &v[0];
 | 
						|
 | 
						|
    if (vector_t::memory_policy::use_transient_rvalues)
 | 
						|
        CHECK(addr_before == addr_after);
 | 
						|
    else
 | 
						|
        CHECK(addr_before != addr_after);
 | 
						|
 | 
						|
    CHECK_VECTOR_EQUALS(v, boost::irange(0u, 1u));
 | 
						|
}
 | 
						|
 | 
						|
TEST_CASE("exception safety")
 | 
						|
{
 | 
						|
    constexpr auto n = 667u;
 | 
						|
 | 
						|
    using dadaist_vector_t = typename dadaist_wrapper<VECTOR_T<unsigned>>::type;
 | 
						|
 | 
						|
    SECTION("push back")
 | 
						|
    {
 | 
						|
        auto t = as_transient_tester(dadaist_vector_t{});
 | 
						|
        auto d = dadaism{};
 | 
						|
        for (auto li = 0u, i = 0u; i < n;) {
 | 
						|
            auto s = d.next();
 | 
						|
            try {
 | 
						|
                if (t.transient)
 | 
						|
                    t.vt.push_back({i});
 | 
						|
                else
 | 
						|
                    t.vp = t.vp.push_back({i});
 | 
						|
                ++i;
 | 
						|
                if (t.step())
 | 
						|
                    li = i;
 | 
						|
            } catch (dada_error) {}
 | 
						|
            if (t.transient) {
 | 
						|
                CHECK_VECTOR_EQUALS(t.vt, boost::irange(0u, i));
 | 
						|
                CHECK_VECTOR_EQUALS(t.vp, boost::irange(0u, li));
 | 
						|
            } else {
 | 
						|
                CHECK_VECTOR_EQUALS(t.vp, boost::irange(0u, i));
 | 
						|
                CHECK_VECTOR_EQUALS(t.vt, boost::irange(0u, li));
 | 
						|
            }
 | 
						|
        }
 | 
						|
        CHECK(d.happenings > 0);
 | 
						|
        CHECK(t.d.happenings > 0);
 | 
						|
        IMMER_TRACE_E(d.happenings);
 | 
						|
        IMMER_TRACE_E(t.d.happenings);
 | 
						|
    }
 | 
						|
 | 
						|
    SECTION("update")
 | 
						|
    {
 | 
						|
        using boost::irange;
 | 
						|
        using boost::join;
 | 
						|
 | 
						|
        auto t = as_transient_tester(make_test_vector<dadaist_vector_t>(0, n));
 | 
						|
        auto d = dadaism{};
 | 
						|
        for (auto li = 0u, i = 0u; i < n;) {
 | 
						|
            auto s = d.next();
 | 
						|
            try {
 | 
						|
                if (t.transient)
 | 
						|
                    t.vt.update(i, [](auto x) { return dada(), x + 1; });
 | 
						|
                else
 | 
						|
                    t.vp = t.vp.update(i, [](auto x) { return dada(), x + 1; });
 | 
						|
                ++i;
 | 
						|
                if (t.step())
 | 
						|
                    li = i;
 | 
						|
            } catch (dada_error) {}
 | 
						|
            if (t.transient) {
 | 
						|
                CHECK_VECTOR_EQUALS(t.vt,
 | 
						|
                                    join(irange(1u, 1u + i), irange(i, n)));
 | 
						|
                CHECK_VECTOR_EQUALS(t.vp,
 | 
						|
                                    join(irange(1u, 1u + li), irange(li, n)));
 | 
						|
            } else {
 | 
						|
                CHECK_VECTOR_EQUALS(t.vp,
 | 
						|
                                    join(irange(1u, 1u + i), irange(i, n)));
 | 
						|
                CHECK_VECTOR_EQUALS(t.vt,
 | 
						|
                                    join(irange(1u, 1u + li), irange(li, n)));
 | 
						|
            }
 | 
						|
        }
 | 
						|
        CHECK(d.happenings > 0);
 | 
						|
        CHECK(t.d.happenings > 0);
 | 
						|
    }
 | 
						|
 | 
						|
    SECTION("take")
 | 
						|
    {
 | 
						|
        auto t = as_transient_tester(make_test_vector<dadaist_vector_t>(0, n));
 | 
						|
        auto d = dadaism{};
 | 
						|
        auto deltas = magic_rotator();
 | 
						|
        auto delta  = 0u;
 | 
						|
        for (auto i = n, li = i;;) {
 | 
						|
            auto s = d.next();
 | 
						|
            auto r = dadaist_vector_t{};
 | 
						|
            try {
 | 
						|
                if (t.transient)
 | 
						|
                    t.vt.take(i);
 | 
						|
                else
 | 
						|
                    t.vp = t.vp.take(i);
 | 
						|
                if (t.step())
 | 
						|
                    li = i;
 | 
						|
                delta = deltas.next();
 | 
						|
                if (i < delta)
 | 
						|
                    break;
 | 
						|
                i -= delta;
 | 
						|
            } catch (dada_error) {}
 | 
						|
            if (t.transient) {
 | 
						|
                CHECK_VECTOR_EQUALS(t.vt, boost::irange(0u, i + delta));
 | 
						|
                CHECK_VECTOR_EQUALS(t.vp, boost::irange(0u, li));
 | 
						|
            } else {
 | 
						|
                CHECK_VECTOR_EQUALS(t.vp, boost::irange(0u, i + delta));
 | 
						|
                CHECK_VECTOR_EQUALS(t.vt, boost::irange(0u, li));
 | 
						|
            }
 | 
						|
        }
 | 
						|
        CHECK(d.happenings > 0);
 | 
						|
        CHECK(t.d.happenings > 0);
 | 
						|
    }
 | 
						|
}
 |