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

View File

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

View File

@ -472,6 +472,23 @@ template <typename... Args>
using disjunction = typename detail::disjunction_impl<identity<Args...>>::type;
#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 detail
} // namespace cti

View File

@ -124,7 +124,7 @@ void old() {
int main(int, char**) {
using namespace cti::detail;
cti::when_seq(
/*cti::when_seq(
cti::make_ready_continuable(0, 1), 2, //< See this plain value
std::vector<cti::continuable<int>>{cti::make_ready_continuable(3),
cti::make_ready_continuable(4)},
@ -167,5 +167,12 @@ int main(int, char**) {
std::tuple<std::tuple<int>> 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);
}
{
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
unsigned i = 0;