Implement the new result deduction for when_any

* The logic requires now that all continuables yield the same
  types and amount of result objects.
This commit is contained in:
Denis Blank 2018-03-02 19:18:53 +01:00
parent 9891543b1f
commit cdbc332287
5 changed files with 80 additions and 48 deletions

View File

@ -40,6 +40,7 @@
#include <continuable/continuable-promise-base.hpp> #include <continuable/continuable-promise-base.hpp>
#include <continuable/detail/base.hpp> #include <continuable/detail/base.hpp>
#include <continuable/detail/container-category.hpp>
#include <continuable/detail/hints.hpp> #include <continuable/detail/hints.hpp>
#include <continuable/detail/traits.hpp> #include <continuable/detail/traits.hpp>
#include <continuable/detail/types.hpp> #include <continuable/detail/types.hpp>
@ -101,51 +102,61 @@ auto make_any_result_submitter(Callback&& callback) {
std::forward<decltype(callback)>(callback)); std::forward<decltype(callback)>(callback));
} }
template <typename T> struct result_deducer {
struct check_pack_empty { template <typename T>
static constexpr auto const is_empty = static auto deduce_one(std::false_type, traits::identity<T>) {
(decltype(traits::pack_size_of(std::declval<T>())){} == static_assert(traits::fail<T>::value,
traits::size_constant_of<0>()); "Non continuable types except tuple like and homogeneous "
static_assert(is_empty.value, "Expected all continuations to have the same" "containers aren't allowed inside an any expression!");
"count of arguments!"); }
}; template <typename T>
static auto deduce_one(std::true_type, traits::identity<T> id) {
/// A callable object to determine the shared result between all continuations return hints::hint_of(id);
struct determine_shared_result { }
template <typename... T> template <typename T>
constexpr auto operator()(T&&...) const noexcept { static auto deduce(traversal::container_category_tag<false, false>,
return common_result_of(hints::signature_hint_tag<>{}, traits::identity<T> id) {
hints::hint_of(traits::identify<T>())...); return deduce_one<T>(base::is_continuable<T>{}, id);
} }
private: /// Deduce a homogeneous container
template <typename Signature, typename... Args> template <bool IsTupleLike, typename T>
static constexpr auto common_result_of(Signature signature, static auto deduce(traversal::container_category_tag<true, IsTupleLike>,
hints::signature_hint_tag<>, traits::identity<T>) {
Args... /*args*/) {
/// Assert that the other signatures are empty too which means all // Deduce the containing type
/// signatures had the same size. using element_t = std::decay_t<decltype(*std::declval<T>().begin())>;
(void)std::initializer_list<int>{0, ((void)check_pack_empty<Args>{}, 0)...}; return deduce(traversal::container_category_of_t<element_t>{},
return signature; traits::identity<element_t>{});
} }
template <typename T, typename... Args> template <typename First, typename... T>
static constexpr T first_of(traits::identity<T, Args...>) noexcept; static auto deduce_same_hints(First first, T...) {
static_assert(traits::conjunction<std::is_same<First, T>...>::value,
"The continuables inside the given pack must have the "
"same signature hint!");
/// Determine the common result between all continuation which are chained return first;
/// with an `any` strategy, consider two continuations: }
/// c1 with `void(int)` and c2 with `void(float)`, the common result shared
/// between both continuations is `void(int)`.
template <typename Signature, typename First, typename... Args>
static constexpr auto common_result_of(Signature signature, First first,
Args... args) {
using common_type =
traits::identity<std::common_type_t<decltype(first_of(first)),
decltype(first_of(args))...>>;
return common_result_of(traits::push(signature, common_type{}), template <std::size_t... I, typename T>
traits::pop_first(first), static auto deduce_tuple_like(std::integer_sequence<std::size_t, I...>,
traits::pop_first(args)...); traits::identity<T>) {
return deduce_same_hints(deduce(
traversal::container_category_of_t<
std::decay_t<decltype(std::get<I>(std::declval<T>()))>>{},
traits::identity<
std::decay_t<decltype(std::get<I>(std::declval<T>()))>>{})...);
}
/// Traverse tuple like container
template <typename T>
static auto deduce(traversal::container_category_tag<false, true>,
traits::identity<T> id) {
std::make_index_sequence<std::tuple_size<T>::value> constexpr const i{};
return deduce_tuple_like(i, id);
} }
}; };
} // namespace any } // namespace any
@ -155,8 +166,9 @@ template <>
struct composition_finalizer<composition_strategy_any_tag> { struct composition_finalizer<composition_strategy_any_tag> {
template <typename Composition> template <typename Composition>
static constexpr auto hint() { static constexpr auto hint() {
return decltype(traits::unpack(std::declval<Composition>(), return decltype(any::result_deducer::deduce(
any::determine_shared_result{})){}; traversal::container_category_of_t<std::decay_t<Composition>>{},
traits::identity<std::decay_t<Composition>>{})){};
} }
template <typename Composition> template <typename Composition>

View File

@ -54,6 +54,7 @@
#define CONTINUABLE_HAS_CXX17_CONSTEXPR_IF #define CONTINUABLE_HAS_CXX17_CONSTEXPR_IF
#define CONTINUABLE_HAS_CXX17_FOLD_EXPRESSION #define CONTINUABLE_HAS_CXX17_FOLD_EXPRESSION
#define CONTINUABLE_HAS_CXX17_DISJUNCTION #define CONTINUABLE_HAS_CXX17_DISJUNCTION
#define CONTINUABLE_HAS_CXX17_CONJUNCTION
#else #else
// Generic feature detection based on __has_feature // Generic feature detection based on __has_feature
#if defined(__has_feature) #if defined(__has_feature)
@ -73,6 +74,7 @@
defined(__cpp_lib_experimental_logical_traits) && \ defined(__cpp_lib_experimental_logical_traits) && \
(__cpp_lib_experimental_logical_traits >= 201511) (__cpp_lib_experimental_logical_traits >= 201511)
#define CONTINUABLE_HAS_CXX17_DISJUNCTION #define CONTINUABLE_HAS_CXX17_DISJUNCTION
#define CONTINUABLE_HAS_CXX17_CONJUNCTION
#endif #endif
#endif #endif

View File

@ -472,6 +472,23 @@ template <typename... Args>
using disjunction = typename detail::disjunction_impl<identity<Args...>>::type; using disjunction = typename detail::disjunction_impl<identity<Args...>>::type;
#endif // CONTINUABLE_HAS_CXX17_DISJUNCTION #endif // CONTINUABLE_HAS_CXX17_DISJUNCTION
#ifdef CONTINUABLE_HAS_CXX17_CONJUNCTION
using std::conjunction;
#else
namespace detail {
/// Declares a C++14 polyfill for C++17 std::conjunction.
template <typename Args, typename = void_t<>>
struct conjunction_impl : std::common_type<std::false_type> {};
template <typename... Args>
struct conjunction_impl<identity<Args...>,
void_t<std::enable_if_t<bool(Args::value)>...>>
: std::common_type<std::true_type> {};
} // namespace detail
template <typename... Args>
using conjunction = typename detail::conjunction_impl<identity<Args...>>::type;
#endif // CONTINUABLE_HAS_CXX17_CONJUNCTION
} // namespace traits } // namespace traits
} // namespace detail } // namespace detail
} // namespace cti } // namespace cti

View File

@ -124,7 +124,7 @@ void old() {
int main(int, char**) { int main(int, char**) {
using namespace cti::detail; using namespace cti::detail;
cti::when_seq( /*cti::when_seq(
cti::make_ready_continuable(0, 1), 2, //< See this plain value cti::make_ready_continuable(0, 1), 2, //< See this plain value
std::vector<cti::continuable<int>>{cti::make_ready_continuable(3), std::vector<cti::continuable<int>>{cti::make_ready_continuable(3),
cti::make_ready_continuable(4)}, cti::make_ready_continuable(4)},
@ -167,5 +167,12 @@ int main(int, char**) {
std::tuple<std::tuple<int>> r5) { std::tuple<std::tuple<int>> r5) {
// ... // ...
util::unused(r0, r1, r2, r34, r5); util::unused(r0, r1, r2, r34, r5);
});*/
composition::apply_composition(composition::composition_strategy_any_tag{},
cti::make_ready_continuable(22),
cti::make_ready_continuable(44))
.then([](int) {
}); });
} }

View File

@ -57,12 +57,6 @@ TYPED_TEST(single_dimension_tests, is_logical_any_connectable) {
ASSERT_ASYNC_TYPES(std::move(chain), tag1, tag2, tag3); ASSERT_ASYNC_TYPES(std::move(chain), tag1, tag2, tag3);
} }
{
using common = std::common_type_t<char, int>;
auto chain = this->supply(char(0), int(0)) || this->supply(int(0), char(0));
ASSERT_ASYNC_TYPES(std::move(chain), common, common);
}
{ {
// Check the evaluation order // Check the evaluation order
unsigned i = 0; unsigned i = 0;