Partial conversion of the async traversal unit test

This commit is contained in:
Denis Blank 2018-02-10 01:37:38 +01:00
parent 4b00f5ff8a
commit f935d78c99

View File

@ -22,65 +22,6 @@
**/ **/
#include <array> #include <array>
#include <memory>
#include <tuple>
#include <type_traits>
#include <utility>
#include <vector>
#include <continuable/continuable-traverse-async.hpp>
#include "test-continuable.hpp"
using std::get;
using std::make_tuple;
using std::tuple;
using cti::async_traverse_complete_tag;
using cti::async_traverse_detach_tag;
using cti::async_traverse_visit_tag;
using cti::traverse_pack_async;
struct my_visitor : std::enable_shared_from_this<my_visitor> {
virtual ~my_visitor() = default;
bool operator()(async_traverse_visit_tag, std::size_t i) {
(void)i;
return false;
}
template <typename N>
void operator()(async_traverse_detach_tag, std::size_t i, N&& next) {
(void)i;
next();
}
template <typename T>
void operator()(async_traverse_complete_tag, T&& pack) {
(void)pack;
}
};
TEST(misc_as_test, my_test) {
cti::traverse_pack_async(my_visitor{}, 0, 1, 2);
}
// Copyright (c) 2017 Denis Blank
// Copyright Andrey Semashev 2007 - 2013.
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// TODO Remove the boost dependency
/*
#include <hpx/config.hpp>
#include <hpx/util/atomic_count.hpp>
#include <hpx/util/lightweight_test.hpp>
#include <hpx/util/pack_traversal_async.hpp>
#include <hpx/util/tuple.hpp>
#include <hpx/util/unused.hpp>
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
#include <list> #include <list>
@ -90,144 +31,69 @@ TEST(misc_as_test, my_test) {
#include <utility> #include <utility>
#include <vector> #include <vector>
#if defined(HPX_HAVE_CXX11_STD_ARRAY) #include <continuable/continuable-traverse-async.hpp>
#include <array> #include <continuable/detail/traits.hpp>
#endif #include <continuable/detail/util.hpp>
using hpx::util::async_traverse_complete_tag; #include "test-continuable.hpp"
using hpx::util::async_traverse_detach_tag;
using hpx::util::async_traverse_visit_tag; using std::get;
using hpx::util::make_tuple; using std::make_tuple;
using hpx::util::traverse_pack_async; using std::tuple;
using hpx::util::tuple;
using cti::async_traverse_complete_tag;
using cti::async_traverse_detach_tag;
using cti::async_traverse_in_place_tag;
using cti::async_traverse_visit_tag;
using cti::detail::util::unused;
using cti::traverse_pack_async;
/// A tag which isn't accepted by any mapper /// A tag which isn't accepted by any mapper
struct not_accepted_tag struct not_accepted_tag {};
{
};
struct thread_safe_counter
{
typedef hpx::util::atomic_count type;
static unsigned int load(hpx::util::atomic_count const& counter) noexcept
{
return static_cast<unsigned int>(static_cast<long>(counter));
}
static void increment(hpx::util::atomic_count& counter) noexcept
{
++counter;
}
static unsigned int decrement(hpx::util::atomic_count& counter) noexcept
{
return static_cast<unsigned int>(--counter);
}
};
template <typename Derived, typename CounterPolicy = thread_safe_counter>
class intrusive_ref_counter;
template <typename Derived, typename CounterPolicy>
void intrusive_ptr_add_ref(
intrusive_ref_counter<Derived, CounterPolicy> const* p) noexcept;
template <typename Derived, typename CounterPolicy>
void intrusive_ptr_release(
intrusive_ref_counter<Derived, CounterPolicy> const* p) noexcept;
template <typename Derived, typename CounterPolicy>
class intrusive_ref_counter
{
private:
typedef typename CounterPolicy::type counter_type;
mutable counter_type ref_counter;
public:
intrusive_ref_counter() noexcept : ref_counter(1) {}
unsigned int use_count() const noexcept
{
return CounterPolicy::load(ref_counter);
}
protected:
~intrusive_ref_counter() = default;
friend void intrusive_ptr_add_ref<Derived, CounterPolicy>(
intrusive_ref_counter<Derived, CounterPolicy> const* p)
noexcept;
friend void intrusive_ptr_release<Derived, CounterPolicy>(
intrusive_ref_counter<Derived, CounterPolicy> const* p)
noexcept;
};
template <typename Derived, typename CounterPolicy>
inline void intrusive_ptr_add_ref(
intrusive_ref_counter<Derived, CounterPolicy> const* p) noexcept
{
CounterPolicy::increment(p->ref_counter);
}
template <typename Derived, typename CounterPolicy>
inline void intrusive_ptr_release(
intrusive_ref_counter<Derived, CounterPolicy> const* p) noexcept
{
if (CounterPolicy::decrement(p->ref_counter) == 0)
delete static_cast<Derived const*>(p);
}
template <typename Child> template <typename Child>
class async_counter_base : public intrusive_ref_counter<Child> class async_counter_base : public std::enable_shared_from_this<Child> {
{
std::size_t counter_ = 0; std::size_t counter_ = 0;
public: public:
async_counter_base() = default; async_counter_base() = default;
virtual ~async_counter_base() {} virtual ~async_counter_base() {
}
std::size_t const& counter() const noexcept std::size_t const& counter() const noexcept {
{
return counter_; return counter_;
} }
std::size_t& counter() noexcept std::size_t& counter() noexcept {
{
return counter_; return counter_;
} }
}; };
template <std::size_t ArgCount> template <std::size_t ArgCount>
struct async_increasing_int_sync_visitor struct async_increasing_int_sync_visitor
: async_counter_base<async_increasing_int_sync_visitor<ArgCount>> : async_counter_base<async_increasing_int_sync_visitor<ArgCount>> {
{ explicit async_increasing_int_sync_visitor(int /*dummy*/) {
explicit async_increasing_int_sync_visitor(int dummy) {} }
bool operator()(async_traverse_visit_tag, std::size_t i) bool operator()(async_traverse_visit_tag, std::size_t i) {
{
EXPECT_EQ(i, this->counter()); EXPECT_EQ(i, this->counter());
++this->counter(); ++this->counter();
return true; return true;
} }
template <typename N> template <typename N>
void operator()(async_traverse_detach_tag, std::size_t i, N&& next) void operator()(async_traverse_detach_tag, std::size_t i, N&& next) {
{ unused(i);
HPX_UNUSED(i); unused(next);
HPX_UNUSED(next);
// Should never be called! // Should never be called!
HPX_TEST(false); EXPECT_TRUE(false);
} }
template <typename T> template <typename T>
void operator()(async_traverse_complete_tag, T&& pack) void operator()(async_traverse_complete_tag, T&& pack) {
{ unused(pack);
HPX_UNUSED(pack);
EXPECT_EQ(this->counter(), ArgCount); EXPECT_EQ(this->counter(), ArgCount);
++this->counter(); ++this->counter();
@ -236,29 +102,26 @@ struct async_increasing_int_sync_visitor
template <std::size_t ArgCount> template <std::size_t ArgCount>
struct async_increasing_int_visitor struct async_increasing_int_visitor
: async_counter_base<async_increasing_int_visitor<ArgCount>> : async_counter_base<async_increasing_int_visitor<ArgCount>> {
{ explicit async_increasing_int_visitor(int /*dummy*/) {
explicit async_increasing_int_visitor(int dummy) {} }
bool operator()(async_traverse_visit_tag, std::size_t i) const bool operator()(async_traverse_visit_tag, std::size_t i) const {
{
EXPECT_EQ(i, this->counter()); EXPECT_EQ(i, this->counter());
return false; return false;
} }
template <typename N> template <typename N>
void operator()(async_traverse_detach_tag, std::size_t i, N&& next) void operator()(async_traverse_detach_tag, std::size_t i, N&& next) {
{ unused(i);
HPX_UNUSED(i);
++this->counter(); ++this->counter();
std::forward<N>(next)(); std::forward<N>(next)();
} }
template <typename T> template <typename T>
void operator()(async_traverse_complete_tag, T&& pack) void operator()(async_traverse_complete_tag, T&& pack) {
{ unused(pack);
HPX_UNUSED(pack);
EXPECT_EQ(this->counter(), ArgCount); EXPECT_EQ(this->counter(), ArgCount);
++this->counter(); ++this->counter();
@ -266,13 +129,12 @@ struct async_increasing_int_visitor
}; };
template <std::size_t ArgCount, typename... Args> template <std::size_t ArgCount, typename... Args>
void test_async_traversal_base(Args&&... args) void test_async_traversal_base(Args&&... args) {
{
// Test that every element is traversed in the correct order // Test that every element is traversed in the correct order
// when we detach the control flow on every visit. // when we detach the control flow on every visit.
{ {
auto result = traverse_pack_async( auto result =
hpx::util::async_traverse_in_place_tag< traverse_pack_async(async_traverse_in_place_tag<
async_increasing_int_sync_visitor<ArgCount>>{}, async_increasing_int_sync_visitor<ArgCount>>{},
42, args...); 42, args...);
EXPECT_EQ(result->counter(), ArgCount + 1U); EXPECT_EQ(result->counter(), ArgCount + 1U);
@ -282,28 +144,20 @@ void test_async_traversal_base(Args&&... args)
// when we detach the control flow on every visit. // when we detach the control flow on every visit.
{ {
auto result = traverse_pack_async( auto result = traverse_pack_async(
hpx::util::async_traverse_in_place_tag< async_traverse_in_place_tag<async_increasing_int_visitor<ArgCount>>{},
async_increasing_int_visitor<ArgCount>>{},
42, args...); 42, args...);
EXPECT_EQ(result->counter(), ArgCount + 1U); EXPECT_EQ(result->counter(), ArgCount + 1U);
} }
} }
static void test_async_traversal() void test_async_traversal() {
{
// Just test everything using a casual int pack // Just test everything using a casual int pack
test_async_traversal_base<4U>(not_accepted_tag{}, test_async_traversal_base<4U>(not_accepted_tag{}, 0U, 1U, not_accepted_tag{},
0U, 2U, 3U, not_accepted_tag{});
1U,
not_accepted_tag{},
2U,
3U,
not_accepted_tag{});
} }
template <typename ContainerFactory> template <typename ContainerFactory>
void test_async_container_traversal_impl(ContainerFactory&& container_of) void test_async_container_traversal_impl(ContainerFactory&& container_of) {
{
// Test by passing a containers in the middle // Test by passing a containers in the middle
test_async_traversal_base<4U>(0U, container_of(1U, 2U), 3U); test_async_traversal_base<4U>(0U, container_of(1U, 2U), 3U);
// Test by splitting the pack in two containers // Test by splitting the pack in two containers
@ -313,29 +167,22 @@ void test_async_container_traversal_impl(ContainerFactory&& container_of)
} }
template <typename T> template <typename T>
struct common_container_factory struct common_container_factory {
{
template <typename... Args> template <typename... Args>
T operator()(Args&&... args) T operator()(Args&&... args) {
{
return T{std::forward<Args>(args)...}; return T{std::forward<Args>(args)...};
} }
}; };
#if defined(HPX_HAVE_CXX11_STD_ARRAY)
template <typename T> template <typename T>
struct array_container_factory struct array_container_factory {
{
template <typename... Args, typename Array = std::array<T, sizeof...(Args)>> template <typename... Args, typename Array = std::array<T, sizeof...(Args)>>
Array operator()(Args&&... args) Array operator()(Args&&... args) {
{
return Array{{std::forward<Args>(args)...}}; return Array{{std::forward<Args>(args)...}};
} }
}; };
#endif
static void test_async_container_traversal() void test_async_container_traversal() {
{
{ {
common_container_factory<std::vector<std::size_t>> factory; common_container_factory<std::vector<std::size_t>> factory;
test_async_container_traversal_impl(factory); test_async_container_traversal_impl(factory);
@ -351,45 +198,37 @@ static void test_async_container_traversal()
test_async_container_traversal_impl(factory); test_async_container_traversal_impl(factory);
} }
#if defined(HPX_HAVE_CXX11_STD_ARRAY)
{ {
array_container_factory<std::size_t> factory; array_container_factory<std::size_t> factory;
test_async_container_traversal_impl(factory); test_async_container_traversal_impl(factory);
} }
#endif
} }
static void test_async_tuple_like_traversal() void test_async_tuple_like_traversal() {
{
// Test by passing a tuple in the middle // Test by passing a tuple in the middle
test_async_traversal_base<4U>( test_async_traversal_base<4U>(not_accepted_tag{}, 0U,
not_accepted_tag{}, 0U, make_tuple(1U, not_accepted_tag{}, 2U), 3U); make_tuple(1U, not_accepted_tag{}, 2U), 3U);
// Test by splitting the pack in two tuples // Test by splitting the pack in two tuples
test_async_traversal_base<4U>( test_async_traversal_base<4U>(make_tuple(0U, not_accepted_tag{}, 1U),
make_tuple(0U, not_accepted_tag{}, 1U), make_tuple(2U, 3U)); make_tuple(2U, 3U));
// Test by passing a huge tuple to the traversal // Test by passing a huge tuple to the traversal
test_async_traversal_base<4U>(make_tuple(0U, 1U, 2U, 3U)); test_async_traversal_base<4U>(make_tuple(0U, 1U, 2U, 3U));
} }
template <typename T, template <typename T, typename... Args,
typename... Args,
typename Vector = std::vector<typename std::decay<T>::type>> typename Vector = std::vector<typename std::decay<T>::type>>
Vector vector_of(T&& first, Args&&... args) Vector vector_of(T&& first, Args&&... args) {
{
return Vector{std::forward<T>(first), std::forward<Args>(args)...}; return Vector{std::forward<T>(first), std::forward<Args>(args)...};
} }
static void test_async_mixed_traversal() void test_async_mixed_traversal() {
{
using container_t = std::vector<std::size_t>; using container_t = std::vector<std::size_t>;
// Test hierarchies where container and tuple like types are mixed // Test hierarchies where container and tuple like types are mixed
test_async_traversal_base<4U>( test_async_traversal_base<4U>(0U, make_tuple(container_t{1U, 2U}), 3U);
0U, hpx::util::make_tuple(container_t{1U, 2U}), 3U);
test_async_traversal_base<4U>( test_async_traversal_base<4U>(
hpx::util::make_tuple( make_tuple(0U, vector_of(not_accepted_tag{}), vector_of(vector_of(1U))),
0U, vector_of(not_accepted_tag{}), vector_of(vector_of(1U))),
make_tuple(2U, 3U)); make_tuple(2U, 3U));
test_async_traversal_base<4U>( test_async_traversal_base<4U>(
@ -398,33 +237,29 @@ static void test_async_mixed_traversal()
template <std::size_t ArgCount> template <std::size_t ArgCount>
struct async_unique_sync_visitor struct async_unique_sync_visitor
: async_counter_base<async_unique_sync_visitor<ArgCount>> : async_counter_base<async_unique_sync_visitor<ArgCount>> {
{ explicit async_unique_sync_visitor(int /*dummy*/) {
explicit async_unique_sync_visitor(int dummy) {} }
bool operator()(async_traverse_visit_tag, std::unique_ptr<std::size_t>& i) bool operator()(async_traverse_visit_tag, std::unique_ptr<std::size_t>& i) {
{
EXPECT_EQ(*i, this->counter()); EXPECT_EQ(*i, this->counter());
++this->counter(); ++this->counter();
return true; return true;
} }
template <typename N> template <typename N>
void operator()(async_traverse_detach_tag, void operator()(async_traverse_detach_tag, std::unique_ptr<std::size_t>& i,
std::unique_ptr<std::size_t>& i, N&& next) {
N&& next) unused(i);
{ unused(next);
HPX_UNUSED(i);
HPX_UNUSED(next);
// Should never be called! // Should never be called!
HPX_TEST(false); EXPECT_TRUE(false);
} }
template <typename T> template <typename T>
void operator()(async_traverse_complete_tag, T&& pack) void operator()(async_traverse_complete_tag, T&& pack) {
{ unused(pack);
HPX_UNUSED(pack);
EXPECT_EQ(this->counter(), ArgCount); EXPECT_EQ(this->counter(), ArgCount);
++this->counter(); ++this->counter();
@ -432,113 +267,87 @@ struct async_unique_sync_visitor
}; };
template <std::size_t ArgCount> template <std::size_t ArgCount>
struct async_unique_visitor : async_counter_base<async_unique_visitor<ArgCount>> struct async_unique_visitor
{ : async_counter_base<async_unique_visitor<ArgCount>> {
explicit async_unique_visitor(int dummy) {} explicit async_unique_visitor(int /*dummy*/) {
}
bool operator()(async_traverse_visit_tag, bool operator()(async_traverse_visit_tag,
std::unique_ptr<std::size_t>& i) const std::unique_ptr<std::size_t>& i) const {
{
EXPECT_EQ(*i, this->counter()); EXPECT_EQ(*i, this->counter());
return false; return false;
} }
template <typename N> template <typename N>
void operator()(async_traverse_detach_tag, void operator()(async_traverse_detach_tag, std::unique_ptr<std::size_t>& i,
std::unique_ptr<std::size_t>& i, N&& next) {
N&& next) unused(i);
{
HPX_UNUSED(i);
++this->counter(); ++this->counter();
std::forward<N>(next)(); std::forward<N>(next)();
} }
template <typename T> template <typename T>
void operator()(async_traverse_complete_tag, T&& pack) void operator()(async_traverse_complete_tag, T&& pack) {
{ unused(pack);
HPX_UNUSED(pack);
EXPECT_EQ(this->counter(), ArgCount); EXPECT_EQ(this->counter(), ArgCount);
++this->counter(); ++this->counter();
} }
}; };
static void test_async_move_only_traversal() template <typename T>
{ constexpr auto of(T i) {
auto const of = [](std::size_t i) { return std::make_unique<T>(i);
return std::unique_ptr<std::size_t>(new std::size_t(i));
};
{
auto result = traverse_pack_async(
hpx::util::async_traverse_in_place_tag<
async_unique_sync_visitor<4>>{},
42, of(0), of(1), of(2), of(3));
EXPECT_EQ(result->counter(), 5U);
}
{
auto result = traverse_pack_async(
hpx::util::async_traverse_in_place_tag<
async_unique_visitor<4>>{},
42, of(0), of(1), of(2), of(3));
EXPECT_EQ(result->counter(), 5U);
}
} }
struct invalidate_visitor : async_counter_base<invalidate_visitor> TEST(async_traverse_in_place, construct_inplace_sync) {
{ auto result = traverse_pack_async(
explicit invalidate_visitor(int dummy) {} async_traverse_in_place_tag<async_unique_sync_visitor<4>>{}, 42, of(0),
of(1), of(2), of(3));
EXPECT_EQ(result->counter(), 5U);
}
bool operator()(async_traverse_visit_tag, std::shared_ptr<int>& i) const TEST(async_traverse_in_place, construct_inplace_async) {
{ auto result = traverse_pack_async(
async_traverse_in_place_tag<async_unique_visitor<4>>{}, 42, of(0), of(1),
of(2), of(3));
EXPECT_EQ(result->counter(), 5U);
}
struct invalidate_visitor : async_counter_base<invalidate_visitor> {
explicit invalidate_visitor(int /*dummy*/) {
}
bool operator()(async_traverse_visit_tag, std::shared_ptr<int>& i) const {
EXPECT_EQ(*i, 22); EXPECT_EQ(*i, 22);
return false; return false;
} }
template <typename N> template <typename N>
void operator()(async_traverse_detach_tag, void operator()(async_traverse_detach_tag, std::shared_ptr<int>& i,
std::shared_ptr<int>& i, N&& next) {
N&& next) unused(i);
{
HPX_UNUSED(i);
std::forward<N>(next)(); std::forward<N>(next)();
} }
// Test whether the passed pack was passed as r-value reference // Test whether the passed pack was passed as r-value reference
void operator()(async_traverse_complete_tag, void operator()(async_traverse_complete_tag,
tuple<std::shared_ptr<int>>&& pack) const tuple<std::shared_ptr<int>>&& pack) const {
{
// Invalidate the moved object // Invalidate the moved object
tuple<std::shared_ptr<int>> moved = std::move(pack); tuple<std::shared_ptr<int>> moved = std::move(pack);
HPX_UNUSED(moved); unused(moved);
} }
}; };
// Check whether the arguments are invalidated (moved out) when called // Check whether the arguments are invalidated (moved out) when called
static void test_async_complete_invalidation() TEST(async_complete_invalidation, check_whether_frame_released) {
{
auto value = std::make_shared<int>(22); auto value = std::make_shared<int>(22);
auto frame = traverse_pack_async( auto frame = traverse_pack_async(
hpx::util::async_traverse_in_place_tag<invalidate_visitor>{}, async_traverse_in_place_tag<invalidate_visitor>{}, 42, value);
42, value);
EXPECT_EQ(value.use_count(), 1U); EXPECT_EQ(value.use_count(), 1L);
} }
int main(int, char**)
{
test_async_traversal();
test_async_container_traversal();
test_async_tuple_like_traversal();
test_async_mixed_traversal();
test_async_move_only_traversal();
test_async_complete_invalidation();
return hpx::util::report_errors();
}
*/