mirror of
https://github.com/Naios/continuable.git
synced 2026-02-09 11:16:40 +08:00
Convert more tests into proper gtest cases
This commit is contained in:
parent
a5640a5d35
commit
5904ea06b4
@ -72,7 +72,7 @@ struct all_map {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST(traverse_single_test, test_container_categories) {
|
TEST(traverse_container, categories) {
|
||||||
using cti::detail::traversal::container_category_of_t;
|
using cti::detail::traversal::container_category_of_t;
|
||||||
using cti::detail::traversal::container_category_tag;
|
using cti::detail::traversal::container_category_tag;
|
||||||
|
|
||||||
@ -94,7 +94,7 @@ TEST(traverse_single_test, test_container_categories) {
|
|||||||
"Wrong category!");
|
"Wrong category!");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(traverse_single_test, test_mixed_traversal) {
|
TEST(traverse_mixed, traversal) {
|
||||||
auto res =
|
auto res =
|
||||||
map_pack(all_map_float{}, 0, 1.f, make_tuple(1.f, 3),
|
map_pack(all_map_float{}, 0, 1.f, make_tuple(1.f, 3),
|
||||||
std::vector<std::vector<int>>{{1, 2}, {4, 5}},
|
std::vector<std::vector<int>>{{1, 2}, {4, 5}},
|
||||||
@ -110,19 +110,19 @@ TEST(traverse_single_test, test_mixed_traversal) {
|
|||||||
EXPECT_TRUE((res == expected));
|
EXPECT_TRUE((res == expected));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(traverse_single_test, test_mixed_traversal_build_regression) {
|
TEST(traverse_mixed, build_regression) {
|
||||||
// Broken build regression tests:
|
// Broken build regression tests:
|
||||||
traverse_pack(my_mapper{}, int(0), 1.f);
|
traverse_pack(my_mapper{}, int(0), 1.f);
|
||||||
map_pack(all_map{}, 0, std::vector<int>{1, 2});
|
map_pack(all_map{}, 0, std::vector<int>{1, 2});
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(traverse_single_test, test_mixed_traversal_container_container_map) {
|
TEST(traverse_mixed, container_container_map) {
|
||||||
// Also a regression test
|
// Also a regression test
|
||||||
auto res = map_pack(all_map{}, std::vector<std::vector<int>>{{1, 2}});
|
auto res = map_pack(all_map{}, std::vector<std::vector<int>>{{1, 2}});
|
||||||
EXPECT_EQ((res[0][0]), (0));
|
EXPECT_EQ((res[0][0]), (0));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(traverse_single_test, test_mixed_traversal_result_tuple_mapped) {
|
TEST(traverse_mixed, result_tuple_mapped) {
|
||||||
auto res = map_pack(
|
auto res = map_pack(
|
||||||
my_mapper{}, 0, 1.f,
|
my_mapper{}, 0, 1.f,
|
||||||
make_tuple(1.f, 3, std::vector<std::vector<int>>{{1, 2}, {4, 5}},
|
make_tuple(1.f, 3, std::vector<std::vector<int>>{{1, 2}, {4, 5}},
|
||||||
@ -141,7 +141,7 @@ TEST(traverse_single_test, test_mixed_traversal_result_tuple_mapped) {
|
|||||||
EXPECT_TRUE((res == expected));
|
EXPECT_TRUE((res == expected));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(traverse_single_test, test_mixed_traversal_all_elements_traversed) {
|
TEST(traverse_mixed, all_elements_traversed) {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
traverse_pack(
|
traverse_pack(
|
||||||
[&](int el) {
|
[&](int el) {
|
||||||
@ -153,30 +153,6 @@ TEST(traverse_single_test, test_mixed_traversal_all_elements_traversed) {
|
|||||||
EXPECT_EQ((count), (7));
|
EXPECT_EQ((count), (7));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
struct my_unwrapper {
|
|
||||||
template <typename T,
|
|
||||||
typename std::enable_if<is_future<T>::value>::type* = nullptr>
|
|
||||||
auto operator()(T future) const -> typename future_traits<T>::result_type {
|
|
||||||
return future.get();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static void test_mixed_early_unwrapping() {
|
|
||||||
{
|
|
||||||
auto res = map_pack(my_unwrapper{}, // ...
|
|
||||||
0, 1, make_ready_future(3),
|
|
||||||
make_tuple(make_ready_future(4), make_ready_future(5)));
|
|
||||||
|
|
||||||
auto expected = make_tuple(0, 1, 3, make_tuple(4, 5));
|
|
||||||
|
|
||||||
static_assert(std::is_same<decltype(res), decltype(expected)>::value,
|
|
||||||
"Type mismatch!");
|
|
||||||
EXPECT_TRUE((res == expected));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct my_allocator {
|
struct my_allocator {
|
||||||
using value_type = T;
|
using value_type = T;
|
||||||
@ -218,54 +194,48 @@ struct my_allocator {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void test_mixed_container_remap() {
|
// Traits
|
||||||
// Traits
|
TEST(traverse_mixed_container_remap, all_elements_traversed) {
|
||||||
|
// TODO Enable this
|
||||||
|
// using detail::container_remapping::has_push_back;
|
||||||
|
// EXPECT_EQ((has_push_back<std::vector<int>, int>::value), true);
|
||||||
|
// EXPECT_EQ((has_push_back<int, int>::value), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned long int_remapper(unsigned short i) {
|
||||||
|
return i - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rebinds the values
|
||||||
|
TEST(traverse_rebind_allocator, maps_values) {
|
||||||
|
std::vector<unsigned short> source = {1, 2, 3};
|
||||||
|
std::vector<unsigned long> dest = map_pack(int_remapper, source);
|
||||||
|
|
||||||
|
EXPECT_TRUE((dest == decltype(dest){0, 1, 2}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rebinds the allocator
|
||||||
|
TEST(traverse_rebind_allocator, converts_allocator) {
|
||||||
|
static unsigned const canary = 78787;
|
||||||
|
|
||||||
|
my_allocator<unsigned short> allocator(canary);
|
||||||
|
std::vector<unsigned short, my_allocator<unsigned short>> source(allocator);
|
||||||
|
|
||||||
|
// Empty
|
||||||
{
|
{
|
||||||
// TODO Enable this
|
std::vector<unsigned long, my_allocator<unsigned long>> remapped =
|
||||||
// using detail::container_remapping::has_push_back;
|
map_pack(int_remapper, source);
|
||||||
// EXPECT_EQ((has_push_back<std::vector<int>, int>::value), true);
|
|
||||||
// EXPECT_EQ((has_push_back<int, int>::value), false);
|
EXPECT_EQ((remapped.get_allocator().state_), (canary));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rebind
|
// Non empty
|
||||||
|
source.push_back(1);
|
||||||
{
|
{
|
||||||
auto const remapper = [](unsigned short i) -> unsigned long {
|
std::vector<unsigned long, my_allocator<unsigned long>> remapped =
|
||||||
return i - 1;
|
map_pack(int_remapper, source);
|
||||||
};
|
|
||||||
|
|
||||||
// Rebinds the values
|
EXPECT_EQ((remapped.get_allocator().state_), (canary));
|
||||||
{
|
|
||||||
std::vector<unsigned short> source = {1, 2, 3};
|
|
||||||
std::vector<unsigned long> dest = map_pack(remapper, source);
|
|
||||||
|
|
||||||
EXPECT_TRUE((dest == decltype(dest){0, 1, 2}));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rebinds the allocator
|
|
||||||
{
|
|
||||||
static unsigned const canary = 78787;
|
|
||||||
|
|
||||||
my_allocator<unsigned short> allocator(canary);
|
|
||||||
std::vector<unsigned short, my_allocator<unsigned short>> source(
|
|
||||||
allocator);
|
|
||||||
|
|
||||||
// Empty
|
|
||||||
{
|
|
||||||
std::vector<unsigned long, my_allocator<unsigned long>> remapped =
|
|
||||||
map_pack(remapper, source);
|
|
||||||
|
|
||||||
EXPECT_EQ((remapped.get_allocator().state_), (canary));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Non empty
|
|
||||||
source.push_back(1);
|
|
||||||
{
|
|
||||||
std::vector<unsigned long, my_allocator<unsigned long>> remapped =
|
|
||||||
map_pack(remapper, source);
|
|
||||||
|
|
||||||
EXPECT_EQ((remapped.get_allocator().state_), (canary));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -285,7 +255,8 @@ struct my_int_mapper {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void test_mixed_fall_through() {
|
// TODO Take a look at this... what it was supposed to test
|
||||||
|
TEST(traverse_mixed_fall_through, misc) {
|
||||||
traverse_pack(my_int_mapper{}, int(0),
|
traverse_pack(my_int_mapper{}, int(0),
|
||||||
std::vector<tuple<float, float>>{make_tuple(1.f, 2.f)},
|
std::vector<tuple<float, float>>{make_tuple(1.f, 2.f)},
|
||||||
make_tuple(std::vector<float>{1.f, 2.f}));
|
make_tuple(std::vector<float>{1.f, 2.f}));
|
||||||
@ -298,12 +269,15 @@ void test_mixed_fall_through() {
|
|||||||
std::vector<std::vector<float>>{{1.f, 2.f}},
|
std::vector<std::vector<float>>{{1.f, 2.f}},
|
||||||
make_tuple(77.f, 2));
|
make_tuple(77.f, 2));
|
||||||
|
|
||||||
|
(void)res1;
|
||||||
|
|
||||||
auto res2 = map_pack(
|
auto res2 = map_pack(
|
||||||
[](int) {
|
[](int) {
|
||||||
// ...
|
// ...
|
||||||
return 0;
|
return 0;
|
||||||
},
|
},
|
||||||
1, std::vector<int>{2, 3});
|
1, std::vector<int>{2, 3});
|
||||||
|
(void)res2;
|
||||||
}
|
}
|
||||||
|
|
||||||
class counter_mapper {
|
class counter_mapper {
|
||||||
@ -370,276 +344,270 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void test_strategic_traverse() {
|
// Every element in the pack is visited
|
||||||
// Every element in the pack is visited
|
TEST(traverse_strategic_traverse, visit_all_elements) {
|
||||||
{
|
int counter = 0;
|
||||||
int counter = 0;
|
counter_mapper mapper(counter);
|
||||||
counter_mapper mapper(counter);
|
traverse_pack(mapper, test_tag_1{}, test_tag_2{}, test_tag_3{});
|
||||||
traverse_pack(mapper, test_tag_1{}, test_tag_2{}, test_tag_3{});
|
EXPECT_EQ(counter, 3);
|
||||||
EXPECT_EQ(counter, 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Every element in the pack is visited from left to right
|
|
||||||
{
|
|
||||||
int counter = 0;
|
|
||||||
traverse_pack(
|
|
||||||
[&](int el) {
|
|
||||||
EXPECT_EQ(counter, el);
|
|
||||||
++counter;
|
|
||||||
},
|
|
||||||
0, 1, 2, 3);
|
|
||||||
EXPECT_EQ(counter, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Elements accepted by the mapper aren't traversed:
|
|
||||||
// - Signature
|
|
||||||
{
|
|
||||||
int counter = 0;
|
|
||||||
counter_mapper_rejecting_non_tag_1 mapper(counter);
|
|
||||||
traverse_pack(mapper, test_tag_1{}, test_tag_2{}, test_tag_3{});
|
|
||||||
EXPECT_EQ(counter, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// - SFINAE
|
|
||||||
{
|
|
||||||
int counter = 0;
|
|
||||||
counter_mapper_rejecting_non_tag_1_sfinae mapper(counter);
|
|
||||||
traverse_pack(mapper, test_tag_1{}, test_tag_2{}, test_tag_3{});
|
|
||||||
EXPECT_EQ(counter, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remapping works across values
|
|
||||||
{
|
|
||||||
tuple<int, int, int> res = map_pack([](int i) { return i + 1; }, 0, 1, 2);
|
|
||||||
|
|
||||||
auto expected = make_tuple(1, 2, 3);
|
|
||||||
EXPECT_TRUE((res == expected));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remapping works across types
|
|
||||||
{
|
|
||||||
tag_shift_mapper mapper;
|
|
||||||
tuple<float, test_tag_2, test_tag_3, test_tag_1> res =
|
|
||||||
map_pack(mapper, 1, test_tag_1{}, test_tag_2{}, test_tag_3{});
|
|
||||||
|
|
||||||
EXPECT_EQ(get<0>(res), 0.f);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remapping works with move-only objects
|
|
||||||
{
|
|
||||||
std::unique_ptr<int> p1(new int(1));
|
|
||||||
std::unique_ptr<int> p2(new int(2));
|
|
||||||
std::unique_ptr<int> p3(new int(3));
|
|
||||||
|
|
||||||
tuple<std::unique_ptr<unsigned>, std::unique_ptr<unsigned>,
|
|
||||||
std::unique_ptr<unsigned>>
|
|
||||||
res = map_pack(
|
|
||||||
// Since we pass the unique_ptr's as r-value,
|
|
||||||
// those should be passed as r-values to the mapper.
|
|
||||||
[](std::unique_ptr<int>&& ptr) {
|
|
||||||
// We explicitly move the ownership here
|
|
||||||
std::unique_ptr<int> owned = std::move(ptr);
|
|
||||||
return std::unique_ptr<unsigned>(new unsigned(*owned + 1));
|
|
||||||
},
|
|
||||||
std::move(p1), std::move(p2), std::move(p3));
|
|
||||||
|
|
||||||
// We expect the ownership of p1 - p3 to be invalid
|
|
||||||
EXPECT_TRUE((!bool(p1)));
|
|
||||||
EXPECT_TRUE((!bool(p2)));
|
|
||||||
EXPECT_TRUE((!bool(p3)));
|
|
||||||
|
|
||||||
EXPECT_EQ((*get<0>(res)), 2U);
|
|
||||||
EXPECT_EQ((*get<1>(res)), 3U);
|
|
||||||
EXPECT_EQ((*get<2>(res)), 4U);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move only types contained in a pack which was passed as l-value
|
|
||||||
// reference is forwarded to the mapper as reference too.
|
|
||||||
{
|
|
||||||
std::vector<std::unique_ptr<int>> container;
|
|
||||||
container.push_back(std::unique_ptr<int>(new int(3)));
|
|
||||||
|
|
||||||
std::vector<int> res =
|
|
||||||
map_pack([](std::unique_ptr<int>& p) { return *p; }, container);
|
|
||||||
|
|
||||||
EXPECT_EQ(res.size(), 1U);
|
|
||||||
EXPECT_EQ(res[0], 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Single object remapping returns the value itself without any boxing
|
|
||||||
{
|
|
||||||
int res = map_pack([](int i) { return i; }, 1);
|
|
||||||
EXPECT_EQ(res, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make it possible to pass move only objects in as reference,
|
|
||||||
// while returning those as reference.
|
|
||||||
{
|
|
||||||
std::unique_ptr<int> ptr(new int(7));
|
|
||||||
|
|
||||||
std::unique_ptr<int> const& ref = map_pack(
|
|
||||||
[](std::unique_ptr<int> const& ref) -> std::unique_ptr<int> const& {
|
|
||||||
// ...
|
|
||||||
return ref;
|
|
||||||
},
|
|
||||||
ptr);
|
|
||||||
|
|
||||||
EXPECT_EQ(*ref, 7);
|
|
||||||
*ptr = 0;
|
|
||||||
EXPECT_EQ(*ref, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Multiple args: Make it possible to pass move only objects in
|
|
||||||
// as reference, while returning those as reference.
|
|
||||||
{
|
|
||||||
std::unique_ptr<int> ptr1(new int(6));
|
|
||||||
std::unique_ptr<int> ptr2(new int(7));
|
|
||||||
|
|
||||||
tuple<std::unique_ptr<int> const&, std::unique_ptr<int> const&> ref =
|
|
||||||
map_pack(
|
|
||||||
[](std::unique_ptr<int> const& ref) -> std::unique_ptr<int> const& {
|
|
||||||
// ...
|
|
||||||
return ref;
|
|
||||||
},
|
|
||||||
ptr1, ptr2);
|
|
||||||
|
|
||||||
EXPECT_EQ((*get<0>(ref)), 6);
|
|
||||||
EXPECT_EQ((*get<1>(ref)), 7);
|
|
||||||
*ptr1 = 1;
|
|
||||||
*ptr2 = 2;
|
|
||||||
EXPECT_EQ((*get<0>(ref)), 1);
|
|
||||||
EXPECT_EQ((*get<1>(ref)), 2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_strategic_container_traverse() {
|
// Every element in the pack is visited from left to right
|
||||||
// Every element in the container is visited
|
TEST(traverse_strategic_traverse, visit_left_to_right) {
|
||||||
// - Plain container
|
int counter = 0;
|
||||||
{
|
traverse_pack(
|
||||||
int counter = 0;
|
[&](int el) {
|
||||||
counter_mapper mapper(counter);
|
EXPECT_EQ(counter, el);
|
||||||
std::vector<int> container;
|
++counter;
|
||||||
container.resize(100);
|
},
|
||||||
traverse_pack(mapper, std::move(container));
|
0, 1, 2, 3);
|
||||||
EXPECT_EQ(counter, 100);
|
EXPECT_EQ(counter, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
// - Nested container
|
// Elements accepted by the mapper aren't traversed:
|
||||||
{
|
// - Signature
|
||||||
int counter = 0;
|
TEST(traverse_strategic_traverse, visit_non_accepted) {
|
||||||
counter_mapper mapper(counter);
|
int counter = 0;
|
||||||
std::vector<std::vector<int>> container;
|
counter_mapper_rejecting_non_tag_1 mapper(counter);
|
||||||
for (unsigned i = 0; i < 10; ++i) {
|
traverse_pack(mapper, test_tag_1{}, test_tag_2{}, test_tag_3{});
|
||||||
std::vector<int> nested;
|
EXPECT_EQ(counter, 1);
|
||||||
nested.resize(10);
|
}
|
||||||
container.push_back(nested);
|
|
||||||
}
|
|
||||||
|
|
||||||
traverse_pack(mapper, std::move(container));
|
// - SFINAE
|
||||||
EXPECT_EQ(counter, 100);
|
TEST(traverse_strategic_traverse, visit_not_finaed) {
|
||||||
}
|
int counter = 0;
|
||||||
|
counter_mapper_rejecting_non_tag_1_sfinae mapper(counter);
|
||||||
|
traverse_pack(mapper, test_tag_1{}, test_tag_2{}, test_tag_3{});
|
||||||
|
EXPECT_EQ(counter, 1);
|
||||||
|
}
|
||||||
|
|
||||||
// Every element in the container is visited from left to right
|
// Remapping works across values
|
||||||
{
|
TEST(traverse_strategic_traverse, remap_across_values) {
|
||||||
int counter = 0;
|
tuple<int, int, int> res = map_pack([](int i) { return i + 1; }, 0, 1, 2);
|
||||||
traverse_pack(
|
|
||||||
[&](int el) {
|
|
||||||
EXPECT_EQ(counter, el);
|
|
||||||
++counter;
|
|
||||||
},
|
|
||||||
std::vector<int>{0, 1}, std::vector<std::vector<int>>{{2, 3}, {4, 5}});
|
|
||||||
EXPECT_EQ(counter, 6);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The container type itself is changed
|
auto expected = make_tuple(1, 2, 3);
|
||||||
// - Plain container
|
EXPECT_TRUE((res == expected));
|
||||||
{
|
}
|
||||||
std::vector<int> container{1, 2, 3};
|
|
||||||
std::vector<float> res =
|
|
||||||
map_pack([](int) { return 0.f; }, std::move(container));
|
|
||||||
EXPECT_EQ(res.size(), 3U);
|
|
||||||
}
|
|
||||||
|
|
||||||
// - Nested container
|
// Remapping works across types
|
||||||
{
|
TEST(traverse_strategic_traverse, remap_across_types) {
|
||||||
std::vector<std::vector<int>> container;
|
tag_shift_mapper mapper;
|
||||||
std::vector<std::vector<float>> res =
|
tuple<float, test_tag_2, test_tag_3, test_tag_1> res =
|
||||||
map_pack([](int) { return 0.f; }, std::move(container));
|
map_pack(mapper, 1, test_tag_1{}, test_tag_2{}, test_tag_3{});
|
||||||
}
|
|
||||||
|
|
||||||
// - Move only container
|
EXPECT_EQ(get<0>(res), 0.f);
|
||||||
{
|
}
|
||||||
std::vector<std::unique_ptr<int>> container;
|
|
||||||
container.push_back(std::unique_ptr<int>(new int(5)));
|
|
||||||
std::vector<int> res = map_pack(
|
|
||||||
[](std::unique_ptr<int>&& ptr) { return *ptr; }, std::move(container));
|
|
||||||
|
|
||||||
EXPECT_EQ(res.size(), 1U);
|
// Remapping works with move-only objects
|
||||||
EXPECT_EQ(res[0], 5);
|
TEST(traverse_strategic_traverse, remap_move_only) {
|
||||||
}
|
std::unique_ptr<int> p1(new int(1));
|
||||||
|
std::unique_ptr<int> p2(new int(2));
|
||||||
|
std::unique_ptr<int> p3(new int(3));
|
||||||
|
|
||||||
// Every element in the container is remapped
|
tuple<std::unique_ptr<unsigned>, std::unique_ptr<unsigned>,
|
||||||
// - Plain container
|
std::unique_ptr<unsigned>>
|
||||||
{
|
res = map_pack(
|
||||||
std::vector<int> container(100, 1);
|
// Since we pass the unique_ptr's as r-value,
|
||||||
auto res = map_pack([](int) { return 2; }, std::move(container));
|
// those should be passed as r-values to the mapper.
|
||||||
|
[](std::unique_ptr<int>&& ptr) {
|
||||||
EXPECT_TRUE(
|
// We explicitly move the ownership here
|
||||||
(std::all_of(res.begin(), res.end(), [](int i) { return i == 2; })));
|
std::unique_ptr<int> owned = std::move(ptr);
|
||||||
}
|
return std::unique_ptr<unsigned>(new unsigned(*owned + 1));
|
||||||
|
|
||||||
// - Nested container
|
|
||||||
{
|
|
||||||
std::vector<std::list<int>> container;
|
|
||||||
for (unsigned i = 0; i < 10; ++i) {
|
|
||||||
std::list<int> nested(10, 1);
|
|
||||||
container.push_back(nested);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto res = map_pack([](int) { return 2; }, std::move(container));
|
|
||||||
EXPECT_TRUE(
|
|
||||||
(std::all_of(res.begin(), res.end(), [](std::list<int> const& nested) {
|
|
||||||
return std::all_of(nested.begin(), nested.end(),
|
|
||||||
[](int i) { return i == 2; });
|
|
||||||
})));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// - Ensure correct container remapping when returning references
|
|
||||||
{
|
|
||||||
// l-value references
|
|
||||||
{
|
|
||||||
std::vector<std::unique_ptr<int>> container;
|
|
||||||
container.push_back(std::unique_ptr<int>(new int(7)));
|
|
||||||
|
|
||||||
std::vector<int> res = map_pack(
|
|
||||||
[](std::unique_ptr<int> const& ref) -> int const& {
|
|
||||||
// ...
|
|
||||||
return *ref;
|
|
||||||
},
|
},
|
||||||
container);
|
std::move(p1), std::move(p2), std::move(p3));
|
||||||
|
|
||||||
EXPECT_EQ(res.size(), 1U);
|
// We expect the ownership of p1 - p3 to be invalid
|
||||||
EXPECT_EQ(res[0], 7);
|
EXPECT_TRUE((!bool(p1)));
|
||||||
}
|
EXPECT_TRUE((!bool(p2)));
|
||||||
|
EXPECT_TRUE((!bool(p3)));
|
||||||
|
|
||||||
// r-value references
|
EXPECT_EQ((*get<0>(res)), 2U);
|
||||||
{
|
EXPECT_EQ((*get<1>(res)), 3U);
|
||||||
std::vector<std::unique_ptr<std::unique_ptr<int>>> container;
|
EXPECT_EQ((*get<2>(res)), 4U);
|
||||||
container.push_back(std::unique_ptr<std::unique_ptr<int>>(
|
}
|
||||||
new std::unique_ptr<int>(new int(7))));
|
|
||||||
|
|
||||||
std::vector<std::unique_ptr<int>> res = map_pack(
|
// Move only types contained in a pack which was passed as l-value
|
||||||
[](std::unique_ptr<std::unique_ptr<int>> &
|
// reference is forwarded to the mapper as reference too.
|
||||||
ref) -> std::unique_ptr<int>&& {
|
TEST(traverse_strategic_traverse, remap_references) {
|
||||||
|
std::vector<std::unique_ptr<int>> container;
|
||||||
|
container.push_back(std::unique_ptr<int>(new int(3)));
|
||||||
|
|
||||||
|
std::vector<int> res =
|
||||||
|
map_pack([](std::unique_ptr<int>& p) { return *p; }, container);
|
||||||
|
|
||||||
|
EXPECT_EQ(res.size(), 1U);
|
||||||
|
EXPECT_EQ(res[0], 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Single object remapping returns the value itself without any boxing
|
||||||
|
TEST(traverse_strategic_traverse, remap_single_values) {
|
||||||
|
int res = map_pack([](int i) { return i; }, 1);
|
||||||
|
EXPECT_EQ(res, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make it possible to pass move only objects in as reference,
|
||||||
|
// while returning those as reference.
|
||||||
|
TEST(traverse_strategic_traverse, remap_move_only_as_ref) {
|
||||||
|
std::unique_ptr<int> ptr(new int(7));
|
||||||
|
|
||||||
|
std::unique_ptr<int> const& ref = map_pack(
|
||||||
|
[](std::unique_ptr<int> const& ref) -> std::unique_ptr<int> const& {
|
||||||
|
// ...
|
||||||
|
return ref;
|
||||||
|
},
|
||||||
|
ptr);
|
||||||
|
|
||||||
|
EXPECT_EQ(*ref, 7);
|
||||||
|
*ptr = 0;
|
||||||
|
EXPECT_EQ(*ref, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multiple args: Make it possible to pass move only objects in
|
||||||
|
// as reference, while returning those as reference.
|
||||||
|
TEST(traverse_strategic_traverse, remap_multiple_move_only_as_ref) {
|
||||||
|
std::unique_ptr<int> ptr1(new int(6));
|
||||||
|
std::unique_ptr<int> ptr2(new int(7));
|
||||||
|
|
||||||
|
tuple<std::unique_ptr<int> const&, std::unique_ptr<int> const&> ref =
|
||||||
|
map_pack(
|
||||||
|
[](std::unique_ptr<int> const& ref) -> std::unique_ptr<int> const& {
|
||||||
// ...
|
// ...
|
||||||
return std::move(*ref);
|
return ref;
|
||||||
},
|
},
|
||||||
container);
|
ptr1, ptr2);
|
||||||
|
|
||||||
EXPECT_EQ(res.size(), 1U);
|
EXPECT_EQ((*get<0>(ref)), 6);
|
||||||
EXPECT_EQ((*res[0]), 7);
|
EXPECT_EQ((*get<1>(ref)), 7);
|
||||||
}
|
*ptr1 = 1;
|
||||||
|
*ptr2 = 2;
|
||||||
|
EXPECT_EQ((*get<0>(ref)), 1);
|
||||||
|
EXPECT_EQ((*get<1>(ref)), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Every element in the container is visited
|
||||||
|
// - Plain container
|
||||||
|
TEST(test_strategic_container_traverse, plain_container) {
|
||||||
|
int counter = 0;
|
||||||
|
counter_mapper mapper(counter);
|
||||||
|
std::vector<int> container;
|
||||||
|
container.resize(100);
|
||||||
|
traverse_pack(mapper, std::move(container));
|
||||||
|
EXPECT_EQ(counter, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
// - Nested container
|
||||||
|
TEST(test_strategic_container_traverse, nested_container) {
|
||||||
|
int counter = 0;
|
||||||
|
counter_mapper mapper(counter);
|
||||||
|
std::vector<std::vector<int>> container;
|
||||||
|
for (unsigned i = 0; i < 10; ++i) {
|
||||||
|
std::vector<int> nested;
|
||||||
|
nested.resize(10);
|
||||||
|
container.push_back(nested);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
traverse_pack(mapper, std::move(container));
|
||||||
|
EXPECT_EQ(counter, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Every element in the container is visited from left to right
|
||||||
|
TEST(test_strategic_container_traverse, left_to_right) {
|
||||||
|
int counter = 0;
|
||||||
|
traverse_pack(
|
||||||
|
[&](int el) {
|
||||||
|
EXPECT_EQ(counter, el);
|
||||||
|
++counter;
|
||||||
|
},
|
||||||
|
std::vector<int>{0, 1}, std::vector<std::vector<int>>{{2, 3}, {4, 5}});
|
||||||
|
EXPECT_EQ(counter, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The container type itself is changed
|
||||||
|
// - Plain container
|
||||||
|
TEST(test_strategic_container_traverse, type_changed_plain) {
|
||||||
|
std::vector<int> container{1, 2, 3};
|
||||||
|
std::vector<float> res =
|
||||||
|
map_pack([](int) { return 0.f; }, std::move(container));
|
||||||
|
EXPECT_EQ(res.size(), 3U);
|
||||||
|
}
|
||||||
|
|
||||||
|
// - Nested container
|
||||||
|
TEST(test_strategic_container_traverse, type_changed_nested) {
|
||||||
|
std::vector<std::vector<int>> container;
|
||||||
|
std::vector<std::vector<float>> res =
|
||||||
|
map_pack([](int) { return 0.f; }, std::move(container));
|
||||||
|
}
|
||||||
|
|
||||||
|
// - Move only container
|
||||||
|
TEST(test_strategic_container_traverse, type_changed_move_only) {
|
||||||
|
std::vector<std::unique_ptr<int>> container;
|
||||||
|
container.push_back(std::unique_ptr<int>(new int(5)));
|
||||||
|
std::vector<int> res = map_pack(
|
||||||
|
[](std::unique_ptr<int>&& ptr) { return *ptr; }, std::move(container));
|
||||||
|
|
||||||
|
EXPECT_EQ(res.size(), 1U);
|
||||||
|
EXPECT_EQ(res[0], 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Every element in the container is remapped
|
||||||
|
// - Plain container
|
||||||
|
TEST(test_strategic_container_traverse, every_element_remapped_plain) {
|
||||||
|
std::vector<int> container(100, 1);
|
||||||
|
auto res = map_pack([](int) { return 2; }, std::move(container));
|
||||||
|
|
||||||
|
EXPECT_TRUE(
|
||||||
|
(std::all_of(res.begin(), res.end(), [](int i) { return i == 2; })));
|
||||||
|
}
|
||||||
|
|
||||||
|
// - Nested container
|
||||||
|
TEST(test_strategic_container_traverse, every_element_remapped_nested) {
|
||||||
|
std::vector<std::list<int>> container;
|
||||||
|
for (unsigned i = 0; i < 10; ++i) {
|
||||||
|
std::list<int> nested(10, 1);
|
||||||
|
container.push_back(nested);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto res = map_pack([](int) { return 2; }, std::move(container));
|
||||||
|
EXPECT_TRUE(
|
||||||
|
(std::all_of(res.begin(), res.end(), [](std::list<int> const& nested) {
|
||||||
|
return std::all_of(nested.begin(), nested.end(),
|
||||||
|
[](int i) { return i == 2; });
|
||||||
|
})));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// - Ensure correct container remapping when returning references
|
||||||
|
// l-value references
|
||||||
|
TEST(test_strategic_container_traverse, every_element_remapped_lvalue) {
|
||||||
|
std::vector<std::unique_ptr<int>> container;
|
||||||
|
container.push_back(std::unique_ptr<int>(new int(7)));
|
||||||
|
|
||||||
|
std::vector<int> res = map_pack(
|
||||||
|
[](std::unique_ptr<int> const& ref) -> int const& {
|
||||||
|
// ...
|
||||||
|
return *ref;
|
||||||
|
},
|
||||||
|
container);
|
||||||
|
|
||||||
|
EXPECT_EQ(res.size(), 1U);
|
||||||
|
EXPECT_EQ(res[0], 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
// r-value references
|
||||||
|
TEST(test_strategic_container_traverse, every_element_remapped_rvalue) {
|
||||||
|
std::vector<std::unique_ptr<std::unique_ptr<int>>> container;
|
||||||
|
container.push_back(std::unique_ptr<std::unique_ptr<int>>(
|
||||||
|
new std::unique_ptr<int>(new int(7))));
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<int>> res = map_pack(
|
||||||
|
[](std::unique_ptr<std::unique_ptr<int>> &
|
||||||
|
ref) -> std::unique_ptr<int>&& {
|
||||||
|
// ...
|
||||||
|
return std::move(*ref);
|
||||||
|
},
|
||||||
|
container);
|
||||||
|
|
||||||
|
EXPECT_EQ(res.size(), 1U);
|
||||||
|
EXPECT_EQ((*res[0]), 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(traverse_single_test, test_strategic_tuple_like_traverse_homogeneous) {
|
TEST(traverse_single_test, test_strategic_tuple_like_traverse_homogeneous) {
|
||||||
@ -650,70 +618,68 @@ TEST(traverse_single_test, test_strategic_tuple_like_traverse_homogeneous) {
|
|||||||
EXPECT_TRUE((res == std::array<float, 3>{{1.f, 1.f, 1.f}}));
|
EXPECT_TRUE((res == std::array<float, 3>{{1.f, 1.f, 1.f}}));
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_strategic_tuple_like_traverse() {
|
// Every element in the tuple like type is visited
|
||||||
// Every element in the tuple like type is visited
|
TEST(traverse_strategic_tuple_like_traverse, all_elements_visited) {
|
||||||
{
|
int counter = 0;
|
||||||
int counter = 0;
|
counter_mapper mapper(counter);
|
||||||
counter_mapper mapper(counter);
|
traverse_pack(mapper, make_tuple(test_tag_1{}, test_tag_2{}, test_tag_3{}));
|
||||||
traverse_pack(mapper, make_tuple(test_tag_1{}, test_tag_2{}, test_tag_3{}));
|
EXPECT_EQ(counter, 3);
|
||||||
EXPECT_EQ(counter, 3);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Every element in the tuple like type is visited from left to right
|
// Every element in the tuple like type is visited from left to right
|
||||||
{
|
TEST(traverse_strategic_tuple_like_traverse, visited_left_to_right) {
|
||||||
int counter = 0;
|
int counter = 0;
|
||||||
traverse_pack(
|
traverse_pack(
|
||||||
[&](int el) {
|
[&](int el) {
|
||||||
EXPECT_EQ(counter, el);
|
EXPECT_EQ(counter, el);
|
||||||
++counter;
|
++counter;
|
||||||
},
|
},
|
||||||
make_tuple(0, 1), make_tuple(make_tuple(2, 3), make_tuple(4, 5)),
|
make_tuple(0, 1), make_tuple(make_tuple(2, 3), make_tuple(4, 5)),
|
||||||
make_tuple(make_tuple(make_tuple(6, 7))));
|
make_tuple(make_tuple(make_tuple(6, 7))));
|
||||||
EXPECT_EQ(counter, 8);
|
EXPECT_EQ(counter, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The container tuple like type itself is changed
|
// The container tuple like type itself is changed
|
||||||
{
|
TEST(traverse_strategic_tuple_like_traverse, type_is_remapped) {
|
||||||
tag_shift_mapper mapper;
|
tag_shift_mapper mapper;
|
||||||
tuple<float, test_tag_2, test_tag_3, test_tag_1> res = map_pack(
|
tuple<float, test_tag_2, test_tag_3, test_tag_1> res =
|
||||||
mapper, make_tuple(1, test_tag_1{}, test_tag_2{}, test_tag_3{}));
|
map_pack(mapper, make_tuple(1, test_tag_1{}, test_tag_2{}, test_tag_3{}));
|
||||||
|
|
||||||
EXPECT_EQ(get<0>(res), 0.f);
|
EXPECT_EQ(get<0>(res), 0.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Every element in the tuple like type is remapped
|
// Every element in the tuple like type is remapped
|
||||||
{
|
TEST(traverse_strategic_tuple_like_traverse, all_elements_remapped) {
|
||||||
tuple<float, float, float> res =
|
tuple<float, float, float> res =
|
||||||
map_pack([](int) { return 1.f; }, make_tuple(0, 0, 0));
|
map_pack([](int) { return 1.f; }, make_tuple(0, 0, 0));
|
||||||
|
|
||||||
auto expected = make_tuple(1.f, 1.f, 1.f);
|
auto expected = make_tuple(1.f, 1.f, 1.f);
|
||||||
|
|
||||||
static_assert(std::is_same<decltype(res), decltype(expected)>::value,
|
static_assert(std::is_same<decltype(res), decltype(expected)>::value,
|
||||||
"Type mismatch!");
|
"Type mismatch!");
|
||||||
EXPECT_TRUE((res == expected));
|
EXPECT_TRUE((res == expected));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make it possible to pass tuples containing move only objects
|
// Make it possible to pass tuples containing move only objects
|
||||||
// in as reference, while returning those as reference.
|
// in as reference, while returning those as reference.
|
||||||
{
|
TEST(traverse_strategic_tuple_like_traverse, remap_references) {
|
||||||
auto value = make_tuple(std::unique_ptr<int>(new int(6)),
|
auto value = make_tuple(std::unique_ptr<int>(new int(6)),
|
||||||
std::unique_ptr<int>(new int(7)));
|
std::unique_ptr<int>(new int(7)));
|
||||||
|
|
||||||
tuple<std::unique_ptr<int> const&, std::unique_ptr<int> const&> ref =
|
tuple<std::unique_ptr<int> const&, std::unique_ptr<int> const&> ref =
|
||||||
map_pack(
|
map_pack(
|
||||||
[](std::unique_ptr<int> const& ref) -> std::unique_ptr<int> const& {
|
[](std::unique_ptr<int> const& ref) -> std::unique_ptr<int> const& {
|
||||||
// ...
|
// ...
|
||||||
return ref;
|
return ref;
|
||||||
},
|
},
|
||||||
value);
|
value);
|
||||||
|
|
||||||
EXPECT_EQ((*get<0>(ref)), 6);
|
EXPECT_EQ((*get<0>(ref)), 6);
|
||||||
EXPECT_EQ((*get<1>(ref)), 7);
|
EXPECT_EQ((*get<1>(ref)), 7);
|
||||||
(*get<0>(ref)) = 1;
|
(*get<0>(ref)) = 1;
|
||||||
(*get<1>(ref)) = 2;
|
(*get<1>(ref)) = 2;
|
||||||
EXPECT_EQ((*get<0>(ref)), 1);
|
EXPECT_EQ((*get<0>(ref)), 1);
|
||||||
EXPECT_EQ((*get<1>(ref)), 2);
|
EXPECT_EQ((*get<1>(ref)), 2);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A mapper which duplicates the given element
|
/// A mapper which duplicates the given element
|
||||||
@ -732,44 +698,40 @@ struct zero_mapper {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void test_spread_traverse() {
|
// 1:2 mappings (multiple arguments)
|
||||||
// 1:2 mappings (multiple arguments)
|
TEST(traverse_spread_traverse, one_to_two_mapping) {
|
||||||
{
|
tuple<int, int, int, int> res = map_pack(duplicate_mapper{}, 1, 2);
|
||||||
tuple<int, int, int, int> res = map_pack(duplicate_mapper{}, 1, 2);
|
|
||||||
|
|
||||||
auto expected = make_tuple(1, 1, 2, 2);
|
auto expected = make_tuple(1, 1, 2, 2);
|
||||||
|
|
||||||
EXPECT_TRUE((res == expected));
|
EXPECT_TRUE((res == expected));
|
||||||
}
|
|
||||||
|
|
||||||
// 1:0 mappings
|
|
||||||
{
|
|
||||||
using Result = decltype(map_pack(zero_mapper{}, 0, 1, 2));
|
|
||||||
static_assert(std::is_void<Result>::value, "Failed...");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_spread_container_traverse() {
|
// 1:0 mappings
|
||||||
// 1:2 mappings (multiple arguments)
|
TEST(traverse_spread_traverse, one_to_zero_mapping) {
|
||||||
{
|
using Result = decltype(map_pack(zero_mapper{}, 0, 1, 2));
|
||||||
std::vector<tuple<int, int>> res =
|
static_assert(std::is_void<Result>::value, "Failed...");
|
||||||
map_pack(duplicate_mapper{}, std::vector<int>{1});
|
|
||||||
|
|
||||||
std::vector<tuple<int, int>> expected;
|
|
||||||
expected.push_back(make_tuple(1, 1));
|
|
||||||
|
|
||||||
EXPECT_TRUE((res == expected));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1:0 mappings
|
|
||||||
{
|
|
||||||
using Result = decltype(map_pack(zero_mapper{}, std::vector<int>{1}));
|
|
||||||
static_assert(std::is_void<Result>::value, "Failed...");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1:2 mappings (multiple arguments)
|
// 1:2 mappings (multiple arguments)
|
||||||
TEST(traverse_single_test, test_spread_container_traverse_multiple_args) {
|
TEST(traverse_spread_container_traverse, one_to_two_mapping) {
|
||||||
|
std::vector<tuple<int, int>> res =
|
||||||
|
map_pack(duplicate_mapper{}, std::vector<int>{1});
|
||||||
|
|
||||||
|
std::vector<tuple<int, int>> expected;
|
||||||
|
expected.push_back(make_tuple(1, 1));
|
||||||
|
|
||||||
|
EXPECT_TRUE((res == expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1:0 mappings
|
||||||
|
TEST(traverse_spread_container_traverse, one_to_zero_mapping) {
|
||||||
|
using Result = decltype(map_pack(zero_mapper{}, std::vector<int>{1}));
|
||||||
|
static_assert(std::is_void<Result>::value, "Failed...");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1:2 mappings (multiple arguments)
|
||||||
|
TEST(traverse_spread_container_traverse, multiple_args) {
|
||||||
auto res = map_pack(duplicate_mapper{}, std::array<int, 2>{{1, 2}});
|
auto res = map_pack(duplicate_mapper{}, std::array<int, 2>{{1, 2}});
|
||||||
|
|
||||||
std::array<int, 4> expected{{1, 1, 2, 2}};
|
std::array<int, 4> expected{{1, 1, 2, 2}};
|
||||||
@ -777,29 +739,26 @@ TEST(traverse_single_test, test_spread_container_traverse_multiple_args) {
|
|||||||
EXPECT_TRUE((res == expected));
|
EXPECT_TRUE((res == expected));
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_spread_tuple_like_traverse() {
|
// 1:2 mappings (multiple arguments)
|
||||||
// 1:2 mappings (multiple arguments)
|
TEST(traverse_spread_tuple_like_traverse, multiple_args) {
|
||||||
{
|
tuple<tuple<int, int, int, int>> res =
|
||||||
tuple<tuple<int, int, int, int>> res =
|
map_pack(duplicate_mapper{}, make_tuple(make_tuple(1, 2)));
|
||||||
map_pack(duplicate_mapper{}, make_tuple(make_tuple(1, 2)));
|
|
||||||
|
|
||||||
tuple<tuple<int, int, int, int>> expected =
|
tuple<tuple<int, int, int, int>> expected =
|
||||||
make_tuple(make_tuple(1, 1, 2, 2));
|
make_tuple(make_tuple(1, 1, 2, 2));
|
||||||
|
|
||||||
EXPECT_TRUE((res == expected));
|
EXPECT_TRUE((res == expected));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1:0 mappings
|
// 1:0 mappings
|
||||||
{
|
TEST(traverse_spread_tuple_like_traverse, one_to_zero_mapping_tuple) {
|
||||||
using Result =
|
using Result =
|
||||||
decltype(map_pack(zero_mapper{}, make_tuple(make_tuple(1, 2), 1), 1));
|
decltype(map_pack(zero_mapper{}, make_tuple(make_tuple(1, 2), 1), 1));
|
||||||
static_assert(std::is_void<Result>::value, "Failed...");
|
static_assert(std::is_void<Result>::value, "Failed...");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1:0 mappings
|
// 1:0 mappings
|
||||||
{
|
TEST(traverse_spread_tuple_like_traverse, one_to_zero_mapping_array) {
|
||||||
using Result =
|
using Result = decltype(map_pack(zero_mapper{}, std::array<int, 2>{{1, 2}}));
|
||||||
decltype(map_pack(zero_mapper{}, std::array<int, 2>{{1, 2}}));
|
static_assert(std::is_void<Result>::value, "Failed...");
|
||||||
static_assert(std::is_void<Result>::value, "Failed...");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user