mirror of
https://github.com/Naios/continuable.git
synced 2025-12-08 01:36:46 +08:00
Add a C++17 std::disjunction polyfill
This commit is contained in:
parent
6a8919c63d
commit
eafbe4b37d
@ -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
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -67,6 +67,9 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// TODO
|
||||
// #define CONTINUABLE_HAS_CXX17_DISJUNCTION
|
||||
|
||||
/// This is enabled by the CMake project
|
||||
// #undef CONTINUABLE_HAS_EXPERIMENTAL_COROUTINE
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user