// 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(HPX_HAVE_CXX11_STD_ARRAY) #include #endif using hpx::util::async_traverse_complete_tag; using hpx::util::async_traverse_detach_tag; using hpx::util::async_traverse_visit_tag; using hpx::util::make_tuple; using hpx::util::traverse_pack_async; using hpx::util::tuple; /// A tag which isn't accepted by any mapper 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(static_cast(counter)); } static void increment(hpx::util::atomic_count& counter) noexcept { ++counter; } static unsigned int decrement(hpx::util::atomic_count& counter) noexcept { return static_cast(--counter); } }; template class intrusive_ref_counter; template void intrusive_ptr_add_ref( intrusive_ref_counter const* p) noexcept; template void intrusive_ptr_release( intrusive_ref_counter const* p) noexcept; template 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( intrusive_ref_counter const* p) noexcept; friend void intrusive_ptr_release( intrusive_ref_counter const* p) noexcept; }; template inline void intrusive_ptr_add_ref( intrusive_ref_counter const* p) noexcept { CounterPolicy::increment(p->ref_counter); } template inline void intrusive_ptr_release( intrusive_ref_counter const* p) noexcept { if (CounterPolicy::decrement(p->ref_counter) == 0) delete static_cast(p); } template class async_counter_base : public intrusive_ref_counter { std::size_t counter_ = 0; public: async_counter_base() = default; virtual ~async_counter_base() {} std::size_t const& counter() const noexcept { return counter_; } std::size_t& counter() noexcept { return counter_; } }; template struct async_increasing_int_sync_visitor : async_counter_base> { explicit async_increasing_int_sync_visitor(int dummy) {} bool operator()(async_traverse_visit_tag, std::size_t i) { HPX_TEST_EQ(i, this->counter()); ++this->counter(); return true; } template void operator()(async_traverse_detach_tag, std::size_t i, N&& next) { HPX_UNUSED(i); HPX_UNUSED(next); // Should never be called! HPX_TEST(false); } template void operator()(async_traverse_complete_tag, T&& pack) { HPX_UNUSED(pack); HPX_TEST_EQ(this->counter(), ArgCount); ++this->counter(); } }; template struct async_increasing_int_visitor : async_counter_base> { explicit async_increasing_int_visitor(int dummy) {} bool operator()(async_traverse_visit_tag, std::size_t i) const { HPX_TEST_EQ(i, this->counter()); return false; } template void operator()(async_traverse_detach_tag, std::size_t i, N&& next) { HPX_UNUSED(i); ++this->counter(); std::forward(next)(); } template void operator()(async_traverse_complete_tag, T&& pack) { HPX_UNUSED(pack); HPX_TEST_EQ(this->counter(), ArgCount); ++this->counter(); } }; template void test_async_traversal_base(Args&&... args) { // Test that every element is traversed in the correct order // when we detach the control flow on every visit. { auto result = traverse_pack_async( hpx::util::async_traverse_in_place_tag< async_increasing_int_sync_visitor>{}, 42, args...); HPX_TEST_EQ(result->counter(), ArgCount + 1U); } // Test that every element is traversed in the correct order // when we detach the control flow on every visit. { auto result = traverse_pack_async( hpx::util::async_traverse_in_place_tag< async_increasing_int_visitor>{}, 42, args...); HPX_TEST_EQ(result->counter(), ArgCount + 1U); } } static void test_async_traversal() { // Just test everything using a casual int pack test_async_traversal_base<4U>(not_accepted_tag{}, 0U, 1U, not_accepted_tag{}, 2U, 3U, not_accepted_tag{}); } template void test_async_container_traversal_impl(ContainerFactory&& container_of) { // Test by passing a containers in the middle test_async_traversal_base<4U>(0U, container_of(1U, 2U), 3U); // Test by splitting the pack in two containers test_async_traversal_base<4U>(container_of(0U, 1U), container_of(2U, 3U)); // Test by passing a huge containers to the traversal test_async_traversal_base<4U>(container_of(0U, 1U, 2U, 3U)); } template struct common_container_factory { template T operator()(Args&&... args) { return T{std::forward(args)...}; } }; #if defined(HPX_HAVE_CXX11_STD_ARRAY) template struct array_container_factory { template > Array operator()(Args&&... args) { return Array{{std::forward(args)...}}; } }; #endif static void test_async_container_traversal() { { common_container_factory> factory; test_async_container_traversal_impl(factory); } { common_container_factory> factory; test_async_container_traversal_impl(factory); } { common_container_factory> factory; test_async_container_traversal_impl(factory); } #if defined(HPX_HAVE_CXX11_STD_ARRAY) { array_container_factory factory; test_async_container_traversal_impl(factory); } #endif } static void test_async_tuple_like_traversal() { // Test by passing a tuple in the middle test_async_traversal_base<4U>( not_accepted_tag{}, 0U, make_tuple(1U, not_accepted_tag{}, 2U), 3U); // Test by splitting the pack in two tuples test_async_traversal_base<4U>( make_tuple(0U, not_accepted_tag{}, 1U), make_tuple(2U, 3U)); // Test by passing a huge tuple to the traversal test_async_traversal_base<4U>(make_tuple(0U, 1U, 2U, 3U)); } template ::type>> Vector vector_of(T&& first, Args&&... args) { return Vector{std::forward(first), std::forward(args)...}; } static void test_async_mixed_traversal() { using container_t = std::vector; // Test hierarchies where container and tuple like types are mixed test_async_traversal_base<4U>( 0U, hpx::util::make_tuple(container_t{1U, 2U}), 3U); test_async_traversal_base<4U>( hpx::util::make_tuple( 0U, vector_of(not_accepted_tag{}), vector_of(vector_of(1U))), make_tuple(2U, 3U)); test_async_traversal_base<4U>( vector_of(vector_of(make_tuple(0U, 1U, 2U, 3U)))); } template struct async_unique_sync_visitor : async_counter_base> { explicit async_unique_sync_visitor(int dummy) {} bool operator()(async_traverse_visit_tag, std::unique_ptr& i) { HPX_TEST_EQ(*i, this->counter()); ++this->counter(); return true; } template void operator()(async_traverse_detach_tag, std::unique_ptr& i, N&& next) { HPX_UNUSED(i); HPX_UNUSED(next); // Should never be called! HPX_TEST(false); } template void operator()(async_traverse_complete_tag, T&& pack) { HPX_UNUSED(pack); HPX_TEST_EQ(this->counter(), ArgCount); ++this->counter(); } }; template struct async_unique_visitor : async_counter_base> { explicit async_unique_visitor(int dummy) {} bool operator()(async_traverse_visit_tag, std::unique_ptr& i) const { HPX_TEST_EQ(*i, this->counter()); return false; } template void operator()(async_traverse_detach_tag, std::unique_ptr& i, N&& next) { HPX_UNUSED(i); ++this->counter(); std::forward(next)(); } template void operator()(async_traverse_complete_tag, T&& pack) { HPX_UNUSED(pack); HPX_TEST_EQ(this->counter(), ArgCount); ++this->counter(); } }; static void test_async_move_only_traversal() { auto const of = [](std::size_t i) { return std::unique_ptr(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)); HPX_TEST_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)); HPX_TEST_EQ(result->counter(), 5U); } } struct invalidate_visitor : async_counter_base { explicit invalidate_visitor(int dummy) {} bool operator()(async_traverse_visit_tag, std::shared_ptr& i) const { HPX_TEST_EQ(*i, 22); return false; } template void operator()(async_traverse_detach_tag, std::shared_ptr& i, N&& next) { HPX_UNUSED(i); std::forward(next)(); } // Test whether the passed pack was passed as r-value reference void operator()(async_traverse_complete_tag, tuple>&& pack) const { // Invalidate the moved object tuple> moved = std::move(pack); HPX_UNUSED(moved); } }; // Check whether the arguments are invalidated (moved out) when called static void test_async_complete_invalidation() { auto value = std::make_shared(22); auto frame = traverse_pack_async( hpx::util::async_traverse_in_place_tag{}, 42, value); HPX_TEST_EQ(value.use_count(), 1U); } 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(); } */