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

View File

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

View File

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

View File

@ -411,6 +411,21 @@ constexpr auto merge(identity<LeftArgs...> /*left*/,
/// Deduces to a std::false_type /// Deduces to a std::false_type
template <typename T> template <typename T>
using fail = std::integral_constant<bool, !std::is_same<T, T>::value>; 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 traits
} // namespace detail } // namespace detail
} // namespace cti } // namespace cti

View File

@ -39,6 +39,7 @@
#include <utility> #include <utility>
#include <continuable/detail/container-category.hpp> #include <continuable/detail/container-category.hpp>
#include <continuable/detail/traits.hpp>
namespace cti { namespace cti {
namespace detail { 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 /// Deduces to a true_type if any of the given types marks
/// the underlying type to be spread into the current context. /// the underlying type to be spread into the current context.
template <typename... T> 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> template <typename C, typename... T>
constexpr auto map_spread(C&& callable, T&&... args) constexpr auto map_spread(C&& callable, T&&... args)