// // 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/util.hpp" #include "test/transient_tester.hpp" #include #include #include #include #include #include #include #include #ifndef FLEX_VECTOR_T #error "define the vector template to use in FLEX_VECTOR_T" #endif #ifndef FLEX_VECTOR_TRANSIENT_T #error "define the vector template to use in FLEX_VECTOR_TRANSIENT_T" #endif #ifndef VECTOR_T #error "define the vector template to use in VECTOR_T" #endif template > auto make_test_flex_vector(unsigned min, unsigned max) { auto v = V{}; for (auto i = min; i < max; ++i) v = v.push_back({i}); return v; } template > auto make_test_flex_vector_front(unsigned min, unsigned max) { auto v = V{}; for (auto i = max; i > min;) v = v.push_front({--i}); return v; } TEST_CASE("from flex_vector and to flex_vector") { constexpr auto n = 100u; auto v = make_test_flex_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("adopt regular vector contents") { const auto n = 666u; auto v = VECTOR_T{}; for (auto i = 0u; i < n; ++i) { v = v.push_back(i); auto fv = FLEX_VECTOR_TRANSIENT_T{v.transient()}; CHECK_VECTOR_EQUALS_AUX(v, fv, [] (auto&& v) { return &v; }); } } TEST_CASE("drop move") { using vector_t = FLEX_VECTOR_T; 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).drop(1)); auto addr_after = &v[0]; if (vector_t::bits_leaf > 0 && 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("exception safety relaxed") { using dadaist_vector_t = typename dadaist_wrapper>::type; constexpr auto n = 667u; SECTION("push back") { auto half = n / 2; auto t = as_transient_tester( make_test_flex_vector_front(0, half)); auto d = dadaism{}; for (auto li = half, i = half; i < n;) { auto s = d.next(); try { if (t.transient) t.vt.push_back({i}); else t.vp = t.vp.push_back({i}); ++i; } catch (dada_error) {} if (t.step()) li = i; 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::join; using boost::irange; auto t = as_transient_tester( make_test_flex_vector_front(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; } catch (dada_error) {} if (t.step()) li = i; 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_flex_vector_front(0, n)); auto d = dadaism{}; auto deltas = magic_rotator(); auto delta = deltas.next(); 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); } SECTION("drop") { auto t = as_transient_tester( make_test_flex_vector(0, n)); auto d = dadaism{}; auto deltas = magic_rotator(); auto delta = deltas.next(); for (auto i = delta, li = 0u; i < n;) { auto s = d.next(); auto r = dadaist_vector_t{}; try { if (t.transient) t.vt.drop(delta); else t.vp = t.vp.drop(delta); if (t.step()) { li = i; } delta = deltas.next(); i += delta; } catch (dada_error) {} if (t.transient) { CHECK_VECTOR_EQUALS(t.vt, boost::irange(i - delta, n)); CHECK_VECTOR_EQUALS(t.vp, boost::irange(li, n)); } else { CHECK_VECTOR_EQUALS(t.vp, boost::irange(i - delta, n)); CHECK_VECTOR_EQUALS(t.vt, boost::irange(li, n)); } } CHECK(d.happenings > 0); CHECK(t.d.happenings > 0); } SECTION("append") { auto make_ = [](auto i, auto delta) { auto d = dadaism::disable(); return make_test_flex_vector(i, i + delta); }; auto t = as_transient_tester(dadaist_vector_t{}); auto d = dadaism(); auto deltas = magic_rotator(); auto delta = deltas.next(); for (auto i = 0u, li = 0u; i < n;) { try { if (t.transient) { auto data = make_(i, delta); auto datat = data.transient(); t.vt.append(datat); } else { auto data = make_(i, delta); t.vp = t.vp + data; } i += delta; if (t.step()) { li = i; } delta = deltas.next() * 3; } 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); } SECTION("append mut") { auto make_ = [](auto i, auto delta) { auto d = dadaism::disable(); return make_test_flex_vector(i, i + delta); }; auto t = as_transient_tester(dadaist_vector_t{}); auto d = dadaism(); auto deltas = magic_rotator(); auto delta = deltas.next(); for (auto i = 0u, li = 0u; i < n;) { try { if (t.transient) { auto data = make_(i, delta); auto datat = data.transient(); t.vt.append(std::move(datat)); } else { auto data = make_(i, delta); t.vp = t.vp + data; } i += delta; if (t.step()) { li = i; } delta = deltas.next() * 3; } 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); } SECTION("prepend") { auto make_ = [](auto i, auto delta) { auto d = dadaism::disable(); return make_test_flex_vector(i, i + delta); }; auto t = as_transient_tester(dadaist_vector_t{}); auto d = dadaism(); auto deltas = magic_rotator(); auto delta = deltas.next(); for (auto i = n, li = n; i > 0;) { delta = std::min(i, delta); try { if (t.transient) { auto data = make_(i - delta, delta); auto datat = data.transient(); t.vt.prepend(datat); } else { auto data = make_(i - delta, delta); t.vp = data + t.vp; } i -= delta; if (t.step()) { li = i; } delta = deltas.next() * 3; } catch (dada_error) {} if (t.transient) { CHECK_VECTOR_EQUALS(t.vt, boost::irange(i, n)); CHECK_VECTOR_EQUALS(t.vp, boost::irange(li, n)); } else { CHECK_VECTOR_EQUALS(t.vp, boost::irange(i, n)); CHECK_VECTOR_EQUALS(t.vt, boost::irange(li, n)); } } CHECK(d.happenings == 0); CHECK(t.d.happenings > 0); } SECTION("prepend mut") { auto make_ = [](auto i, auto delta) { auto d = dadaism::disable(); return make_test_flex_vector(i, i + delta); }; auto t = as_transient_tester(dadaist_vector_t{}); auto d = dadaism(); auto deltas = magic_rotator(); auto delta = deltas.next(); for (auto i = n, li = n; i > 0;) { delta = std::min(i, delta); try { if (t.transient) { auto data = make_(i - delta, delta); auto datat = data.transient(); t.vt.prepend(std::move(datat)); } else { auto data = make_(i - delta, delta); t.vp = data + t.vp; } i -= delta; if (t.step()) { li = i; } delta = deltas.next() * 3; } catch (dada_error) {} if (t.transient) { CHECK_VECTOR_EQUALS(t.vt, boost::irange(i, n)); CHECK_VECTOR_EQUALS(t.vp, boost::irange(li, n)); } else { CHECK_VECTOR_EQUALS(t.vp, boost::irange(i, n)); CHECK_VECTOR_EQUALS(t.vt, boost::irange(li, n)); } } CHECK(d.happenings == 0); CHECK(t.d.happenings > 0); } }