Add a C++17 std::disjunction polyfill

This commit is contained in:
Denis Blank 2018-02-05 23:41:52 +01:00
parent 6a8919c63d
commit eafbe4b37d
5 changed files with 68 additions and 58 deletions

View File

@ -31,24 +31,24 @@
#ifndef CONTINUABLE_TRAVERSE_ASYNC_HPP_INCLUDED
#define CONTINUABLE_TRAVERSE_ASYNC_HPP_INCLUDED
#include <continuable/detail/traverse-async.hpp>
#include <utility>
#include <continuable/detail/traverse-async.hpp>
namespace cti {
/// A tag which is passed to the `operator()` of the visitor
/// if an element is visited synchronously.
using detail::async_traverse_visit_tag;
using detail::traversal::async_traverse_visit_tag;
/// A tag which is passed to the `operator()` of the visitor
/// if an element is visited after the traversal was detached.
using detail::async_traverse_detach_tag;
using detail::traversal::async_traverse_detach_tag;
/// A tag which is passed to the `operator()` of the visitor
/// if the asynchronous pack traversal was finished.
using detail::async_traverse_complete_tag;
using detail::traversal::async_traverse_complete_tag;
/// A tag to identify that a mapper shall be constructed in-place
/// from the first argument passed.
using detail::async_traverse_in_place_tag;
using detail::traversal::async_traverse_in_place_tag;
/// Traverses the pack with the given visitor in an asynchronous way.
///
@ -58,36 +58,32 @@ using detail::async_traverse_in_place_tag;
/// Thus we require a visitor callable object which provides three
/// `operator()` overloads as depicted by the code sample below:
/// ```cpp
/// struct my_async_visitor
/// {
/// /// The synchronous overload is called for each object,
/// /// it may return false to suspend the current control.
/// /// In that case the overload below is called.
/// template <typename T>
/// bool operator()(async_traverse_visit_tag, T&& element)
/// {
/// return true;
/// }
/// struct my_async_visitor {
/// /// The synchronous overload is called for each object,
/// /// it may return false to suspend the current control.
/// /// In that case the overload below is called.
/// template <typename T>
/// bool operator()(async_traverse_visit_tag, T&& element) {
/// return true;
/// }
///
/// /// The asynchronous overload this is called when the
/// /// synchronous overload returned false.
/// /// In addition to the current visited element the overload is
/// /// called with a contnuation callable object which resumes the
/// /// traversal when it's called later.
/// /// The continuation next may be stored and called later or
/// /// dropped completely to abort the traversal early.
/// template <typename T, typename N>
/// void operator()(async_traverse_detach_tag, T&& element, N&& next)
/// {
/// }
/// /// The asynchronous overload this is called when the
/// /// synchronous overload returned false.
/// /// In addition to the current visited element the overload is
/// /// called with a contnuation callable object which resumes the
/// /// traversal when it's called later.
/// /// The continuation next may be stored and called later or
/// /// dropped completely to abort the traversal early.
/// template <typename T, typename N>
/// void operator()(async_traverse_detach_tag, T&& element, N&& next) {
/// }
///
/// /// The overload is called when the traversal was finished.
/// /// As argument the whole pack is passed over which we
/// /// traversed asynchrnously.
/// template <typename T>
/// void operator()(async_traverse_complete_tag, T&& pack)
/// {
/// }
/// /// The overload is called when the traversal was finished.
/// /// As argument the whole pack is passed over which we
/// /// traversed asynchrnously.
/// template <typename T>
/// void operator()(async_traverse_complete_tag, T&& pack) {
/// }
/// };
/// ```
///
@ -108,11 +104,9 @@ using detail::async_traverse_in_place_tag;
/// traversal behaviour and capabilities.
///
template <typename Visitor, typename... T>
auto traverse_pack_async(Visitor&& visitor, T&&... pack)
-> decltype(detail::apply_pack_transform_async(
std::forward<Visitor>(visitor), std::forward<T>(pack)...)) {
return detail::apply_pack_transform_async(std::forward<Visitor>(visitor),
std::forward<T>(pack)...);
auto traverse_pack_async(Visitor&& visitor, T&&... pack) {
return detail::traversal::apply_pack_transform_async(
std::forward<Visitor>(visitor), std::forward<T>(pack)...);
}
} // namespace cti

View File

@ -42,7 +42,7 @@ namespace cti {
///
/// This function tries to visit all plain elements which may be wrapped in:
/// - homogeneous containers (`std::vector`, `std::list`)
/// - heterogenous containers `(hpx::tuple`, `std::pair`, `std::array`)
/// - heterogenous containers `(std::tuple`, `std::pair`, `std::array`)
/// and re-assembles the pack with the result of the mapper.
/// Mapping from one type to a different one is supported.
///
@ -52,9 +52,9 @@ namespace cti {
/// ```cpp
/// // Maps all integers to floats
/// map_pack([](int value) {
/// return float(value);
/// return float(value);
/// },
/// 1, hpx::util::make_tuple(2, std::vector<int>{3, 4}), 5);
/// 1, std::make_tuple(2, std::vector<int>{3, 4}), 5);
/// ```
///
/// \throws std::exception like objects which are thrown by an
@ -67,26 +67,23 @@ namespace cti {
///
/// \returns The mapped element or in case the pack contains
/// multiple elements, the pack is wrapped into
/// a `hpx::tuple`.
/// a `std::tuple`.
///
template <typename Mapper, typename... T>
auto map_pack(Mapper&& mapper, T&&... pack)
-> decltype(detail::apply_pack_transform(detail::strategy_remap_tag{},
std::forward<Mapper>(mapper),
std::forward<T>(pack)...)) {
return detail::apply_pack_transform(detail::strategy_remap_tag{},
std::forward<Mapper>(mapper),
std::forward<T>(pack)...);
auto map_pack(Mapper&& mapper, T&&... pack) {
return detail::traversal::apply_pack_transform(
detail::traversal::strategy_remap_tag{}, std::forward<Mapper>(mapper),
std::forward<T>(pack)...);
}
/// Indicate that the result shall be spread across the parent container
/// if possible. This can be used to create a mapper function used
/// in map_pack that maps one element to an arbitrary count (1:n).
template <typename... T>
constexpr detail::spreading::spread_box<typename std::decay<T>::type...>
spread_this(T&&... args) {
return detail::spreading::spread_box<typename std::decay<T>::type...>(
util::make_tuple(std::forward<T>(args)...));
constexpr auto spread_this(T&&... args) {
return detail::traversal::spreading::spread_box<
typename std::decay<T>::type...>(
std::make_tuple(std::forward<T>(args)...));
}
/// Traverses the pack with the given visitor.
@ -97,9 +94,9 @@ spread_this(T&&... args) {
/// See `map_pack` for a detailed description.
template <typename Mapper, typename... T>
void traverse_pack(Mapper&& mapper, T&&... pack) {
detail::apply_pack_transform(detail::strategy_traverse_tag{},
std::forward<Mapper>(mapper),
std::forward<T>(pack)...);
detail::traversal::apply_pack_transform(
detail::traversal::strategy_traverse_tag{}, std::forward<Mapper>(mapper),
std::forward<T>(pack)...);
}
} // namespace cti

View File

@ -67,6 +67,9 @@
#endif
#endif
// TODO
// #define CONTINUABLE_HAS_CXX17_DISJUNCTION
/// This is enabled by the CMake project
// #undef CONTINUABLE_HAS_EXPERIMENTAL_COROUTINE

View File

@ -411,6 +411,21 @@ constexpr auto merge(identity<LeftArgs...> /*left*/,
/// Deduces to a std::false_type
template <typename T>
using fail = std::integral_constant<bool, !std::is_same<T, T>::value>;
#ifdef CONTINUABLE_HAS_CXX17_DISJUNCTION
using std::disjunction;
#else
/// Declares a C++14 polyfill for C++17 std::disjunction.
template <typename Args, typename = void_t<>>
struct disjunction_impl : std::common_type<std::false_type> {};
template <typename... Args>
struct disjunction_impl<identity<Args...>,
void_t<std::enable_if_t<bool(Args::value)>...>>
: std::common_type<std::true_type> {};
template <typename... Args>
using disjunction = disjunction_impl<identity<Args...>>;
#endif // CONTINUABLE_HAS_CXX17_DISJUNCTION
} // namespace traits
} // namespace detail
} // namespace cti

View File

@ -39,6 +39,7 @@
#include <utility>
#include <continuable/detail/container-category.hpp>
#include <continuable/detail/traits.hpp>
namespace cti {
namespace detail {
@ -207,7 +208,7 @@ constexpr auto apply_spread_impl(std::false_type, C&& callable, T&&... args)
/// Deduces to a true_type if any of the given types marks
/// the underlying type to be spread into the current context.
template <typename... T>
using is_any_spread_t = any_of<is_spread<T>...>;
using is_any_spread_t = traits::disjunction<is_spread<T>...>;
template <typename C, typename... T>
constexpr auto map_spread(C&& callable, T&&... args)