399 lines
12 KiB
Text
399 lines
12 KiB
Text
|
//
|
||
|
// 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 <immer/algorithm.hpp>
|
||
|
|
||
|
#include <boost/range/adaptors.hpp>
|
||
|
#include <boost/range/irange.hpp>
|
||
|
#include <catch.hpp>
|
||
|
|
||
|
#include <algorithm>
|
||
|
#include <array>
|
||
|
#include <numeric>
|
||
|
#include <vector>
|
||
|
|
||
|
#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 <typename V = VECTOR_T<unsigned>>
|
||
|
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 <typename V = FLEX_VECTOR_T<unsigned>>
|
||
|
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<unsigned>{};
|
||
|
for (auto i = 0u; i < n; ++i) {
|
||
|
v = v.push_back(i);
|
||
|
auto fv = FLEX_VECTOR_TRANSIENT_T<unsigned>{v.transient()};
|
||
|
CHECK_VECTOR_EQUALS_AUX(v, fv, [](auto&& v) { return &v; });
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TEST_CASE("drop move")
|
||
|
{
|
||
|
using vector_t = FLEX_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).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<FLEX_VECTOR_T<unsigned>>::type;
|
||
|
constexpr auto n = 667u;
|
||
|
|
||
|
SECTION("push back")
|
||
|
{
|
||
|
auto half = n / 2;
|
||
|
auto t = as_transient_tester(
|
||
|
make_test_flex_vector_front<dadaist_vector_t>(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::irange;
|
||
|
using boost::join;
|
||
|
|
||
|
auto t = as_transient_tester(
|
||
|
make_test_flex_vector_front<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;
|
||
|
} 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<dadaist_vector_t>(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<dadaist_vector_t>(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<dadaist_vector_t>(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<dadaist_vector_t>(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<dadaist_vector_t>(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<dadaist_vector_t>(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);
|
||
|
}
|
||
|
}
|