This commit is contained in:
Denis Blank 2018-12-25 11:12:11 +01:00
parent 1cbfcbea6d
commit 96c9f7af99
22 changed files with 282 additions and 163 deletions

View File

@ -835,7 +835,7 @@ constexpr auto make_continuable(Continuation&& continuation) {
template <typename... Args> template <typename... Args>
auto make_ready_continuable(Args&&... args) { auto make_ready_continuable(Args&&... args) {
using detail::base::ready_continuation; using detail::base::ready_continuation;
using detail::traits::identity; using detail::identity;
using detail::traits::unrefcv_t; using detail::traits::unrefcv_t;
return detail::base::attorney::create_from_raw( return detail::base::attorney::create_from_raw(
ready_continuation<unrefcv_t<Args>...>{std::forward<Args>(args)...}, ready_continuation<unrefcv_t<Args>...>{std::forward<Args>(args)...},

View File

@ -51,7 +51,7 @@ namespace std {
namespace experimental { namespace experimental {
template <typename Data, typename... Args, typename... FunctionArgs> template <typename Data, typename... Args, typename... FunctionArgs>
struct coroutine_traits< struct coroutine_traits<
cti::continuable_base<Data, cti::detail::traits::identity<Args...>>, cti::continuable_base<Data, cti::detail::identity<Args...>>,
FunctionArgs...> { FunctionArgs...> {
using promise_type = using promise_type =

View File

@ -32,6 +32,7 @@
#define CONTINUABLE_PRIMITIVES_HPP_INCLUDED #define CONTINUABLE_PRIMITIVES_HPP_INCLUDED
#include <continuable/detail/core/types.hpp> #include <continuable/detail/core/types.hpp>
#include <continuable/detail/utility/identity.hpp>
namespace cti { namespace cti {
/// \defgroup Primitives Primitives /// \defgroup Primitives Primitives
@ -56,6 +57,13 @@ namespace cti {
/// ``` /// ```
/// \{ /// \{
/// Represents the tag type that is used to specify the signature hint
/// of a continuable_base or promise_base.
///
/// \since 4.0.0
template <typename... Args>
using signature_arg_t = detail::identity<Args...>;
/// Represents the tag type that is used to query the continuation /// Represents the tag type that is used to query the continuation
/// for whether it resolves the callback instantly with its arguments /// for whether it resolves the callback instantly with its arguments
/// without having side effects. /// without having side effects.

View File

@ -62,7 +62,7 @@ class promise_base
/// \cond false /// \cond false
; ;
template <typename Data, typename... Args> template <typename Data, typename... Args>
class promise_base<Data, detail::traits::identity<Args...>> class promise_base<Data, detail::identity<Args...>>
: detail::util::non_copyable : detail::util::non_copyable
/// \endcond /// \endcond
{ // clang-format on { // clang-format on

View File

@ -158,7 +158,7 @@
/// \since 1.0.0 /// \since 1.0.0
#define ASSERT_ASYNC_TYPES(CONTINUABLE, ...) \ #define ASSERT_ASYNC_TYPES(CONTINUABLE, ...) \
cti::detail::testing::assert_async_types( \ cti::detail::testing::assert_async_types( \
CONTINUABLE, cti::detail::traits::identity<__VA_ARGS__>{}) CONTINUABLE, cti::detail::identity<__VA_ARGS__>{})
/// Asserts that the continuable is finished with the given exception /// Asserts that the continuable is finished with the given exception
/// ///

View File

@ -59,17 +59,12 @@ namespace cti {
template <template <std::size_t, typename...> class CallbackWrapper, template <template <std::size_t, typename...> class CallbackWrapper,
template <std::size_t, typename...> class ContinuationWrapper, template <std::size_t, typename...> class ContinuationWrapper,
typename... Args> typename... Args>
class continuable_trait { struct continuable_trait {
using callback = CallbackWrapper<0U, void(Args...)&&, using callback = CallbackWrapper<0U, void(Args...)&&,
void(exception_arg_t, exception_t) &&>; void(exception_arg_t, exception_t) &&>;
public:
/// The promise type which is used to resolve continuations
using promise = promise_base<callback, detail::traits::identity<Args...>>;
/// The continuable type for the given parameters. /// The continuable type for the given parameters.
using continuable = continuable_base< using continuation = continuable_base<
ContinuationWrapper< ContinuationWrapper<
// Size the buffer for the small functor optimization so the // Size the buffer for the small functor optimization so the
// result itself fits in and guarantee that a pointer can // result itself fits in and guarantee that a pointer can
@ -81,7 +76,7 @@ public:
bool(is_ready_arg_t) const, // bool(is_ready_arg_t) const, //
std::tuple<Args...>(query_arg_t) // std::tuple<Args...>(query_arg_t) //
>, >,
detail::traits::identity<Args...>>; detail::identity<Args...>>;
}; };
/// \} /// \}
} // namespace cti } // namespace cti

View File

@ -33,7 +33,10 @@
#include <cstddef> #include <cstddef>
#include <function2/function2.hpp> #include <function2/function2.hpp>
#include <continuable/continuable-trait.hpp> #include <continuable/continuable-base.hpp>
#include <continuable/continuable-primitives.hpp>
#include <continuable/continuable-promise-base.hpp>
#include <continuable/detail/other/erasure.hpp>
namespace cti { namespace cti {
/// \defgroup Types Types /// \defgroup Types Types
@ -41,66 +44,40 @@ namespace cti {
/// cti::promise promise\endlink facility for type erasure. /// cti::promise promise\endlink facility for type erasure.
/// \{ /// \{
namespace detail { /// Deduces to the preferred continuation capacity for a possible
/// A type erasure which isn't size adjusted and move only /// small functor optimization. The given capacity size is always enough to
template <std::size_t, typename... Args> /// to avoid any allocation when storing ready a continuable_base.
class type_erasure : public fu2::unique_function<Args...> { ///
public: /// \since 4.0.0
using fu2::unique_function<Args...>::unique_function; // template <typename... Args>
using fu2::unique_function<Args...>::operator=; // using continuation_capacity = detail::erasure::continuation_capacity<Args...>;
using fu2::unique_function<Args...>::operator();
};
/// A function which is size adjusted and move only
template <std::size_t Size, typename... Args>
class sized_type_erasure
: public fu2::function_base<true, false, Size, true, false, Args...> {
public:
using fu2::function_base<true, false, Size, //
true, false, Args...>::function_base;
using fu2::function_base<true, false, Size, //
true, false, Args...>::operator=;
using fu2::function_base<true, false, Size, //
true, false, Args...>::operator();
};
/// We adjust the internal capacity of the outer function wrapper so
/// we don't have to allocate twice when using `continuable<...>`.
template <typename... Args>
using unique_trait_of = continuable_trait< //
type_erasure, sized_type_erasure,
Args... //
>;
/// A type erasure for work objects
class work_type_erasure : public fu2::unique_function<void()> {
public:
using fu2::unique_function<void()>::unique_function;
using fu2::unique_function<void()>::operator=;
using fu2::unique_function<void()>::operator();
};
} // namespace detail
/// Defines a non-copyable continuation type which uses the /// Defines a non-copyable continuation type which uses the
/// function2 backend for type erasure. /// function2 backend for type erasure.
/// ///
/// Usable like: `continuable<int, float>` /// Usable like: `continuable<int, float>`
template <typename... Args> template <typename... Args>
using continuable = typename detail::unique_trait_of<Args...>::continuable; using continuable = continuable_base<detail::erasure::continuation<Args...>, //
signature_arg_t<Args...>>;
/// Defines a non-copyable promise type which is using the /// Defines a non-copyable promise type which is using the
/// function2 backend for type erasure. /// function2 backend for type erasure.
/// ///
/// Usable like: `promise<int, float>` /// Usable like: `promise<int, float>`
template <typename... Args> template <typename... Args>
using promise = typename detail::unique_trait_of<Args...>::promise; using promise = promise_base<detail::erasure::callback<Args...>, //
signature_arg_t<Args...>>;
/// Defines a non-copyable type erasure which is capable of carrying /// Defines a non-copyable type erasure which is capable of carrying
/// callable objects passed to executors. /// callable objects passed to executors.
/// ///
/// \since 4.0.0 /// \since 4.0.0
using work = detail::work_type_erasure; class work : public fu2::unique_function<void()> {
public:
using fu2::unique_function<void()>::unique_function;
using fu2::unique_function<void()>::operator=;
using fu2::unique_function<void()>::operator();
};
// TODO channel // TODO channel
// TODO sink // TODO sink

View File

@ -52,7 +52,6 @@ namespace cti {}
#include <continuable/continuable-promise-base.hpp> #include <continuable/continuable-promise-base.hpp>
#include <continuable/continuable-promisify.hpp> #include <continuable/continuable-promisify.hpp>
#include <continuable/continuable-result.hpp> #include <continuable/continuable-result.hpp>
#include <continuable/continuable-trait.hpp>
#include <continuable/continuable-transforms.hpp> #include <continuable/continuable-transforms.hpp>
#include <continuable/continuable-traverse-async.hpp> #include <continuable/continuable-traverse-async.hpp>
#include <continuable/continuable-traverse.hpp> #include <continuable/continuable-traverse.hpp>

View File

@ -75,13 +75,13 @@ T&& unpack_lazy(container::flat_variant<T>&& value) {
template <typename Continuable> template <typename Continuable>
class continuable_box; class continuable_box;
template <typename Data> template <typename Data>
class continuable_box<continuable_base<Data, traits::identity<>>> { class continuable_box<continuable_base<Data, identity<>>> {
continuable_base<Data, traits::identity<>> continuable_; continuable_base<Data, identity<>> continuable_;
public: public:
explicit continuable_box( explicit continuable_box(
continuable_base<Data, traits::identity<>>&& continuable) continuable_base<Data, identity<>>&& continuable)
: continuable_(std::move(continuable)) { : continuable_(std::move(continuable)) {
} }
@ -101,14 +101,14 @@ public:
} }
}; };
template <typename Data, typename First> template <typename Data, typename First>
class continuable_box<continuable_base<Data, traits::identity<First>>> { class continuable_box<continuable_base<Data, identity<First>>> {
continuable_base<Data, traits::identity<First>> continuable_; continuable_base<Data, identity<First>> continuable_;
lazy_value_t<First> first_; lazy_value_t<First> first_;
public: public:
explicit continuable_box( explicit continuable_box(
continuable_base<Data, traits::identity<First>>&& continuable) continuable_base<Data, identity<First>>&& continuable)
: continuable_(std::move(continuable)) { : continuable_(std::move(continuable)) {
} }
@ -130,14 +130,14 @@ public:
}; };
template <typename Data, typename First, typename Second, typename... Rest> template <typename Data, typename First, typename Second, typename... Rest>
class continuable_box< class continuable_box<
continuable_base<Data, traits::identity<First, Second, Rest...>>> { continuable_base<Data, identity<First, Second, Rest...>>> {
continuable_base<Data, traits::identity<First, Second, Rest...>> continuable_; continuable_base<Data, identity<First, Second, Rest...>> continuable_;
lazy_value_t<std::tuple<First, Second, Rest...>> args_; lazy_value_t<std::tuple<First, Second, Rest...>> args_;
public: public:
explicit continuable_box( explicit continuable_box(
continuable_base<Data, traits::identity<First, Second, Rest...>>&& continuable_base<Data, identity<First, Second, Rest...>>&&
continuable) continuable)
: continuable_(std::move(continuable)) { : continuable_(std::move(continuable)) {
} }
@ -209,12 +209,12 @@ constexpr auto unbox_continuables(Args&&... args) {
namespace detail { namespace detail {
template <typename Callback, typename Data> template <typename Callback, typename Data>
constexpr auto finalize_impl(traits::identity<void>, Callback&& callback, constexpr auto finalize_impl(identity<void>, Callback&& callback,
Data&&) { Data&&) {
return std::forward<Callback>(callback)(); return std::forward<Callback>(callback)();
} }
template <typename... Args, typename Callback, typename Data> template <typename... Args, typename Callback, typename Data>
constexpr auto finalize_impl(traits::identity<std::tuple<Args...>>, constexpr auto finalize_impl(identity<std::tuple<Args...>>,
Callback&& callback, Data&& data) { Callback&& callback, Data&& data) {
// Call the final callback with the cleaned result // Call the final callback with the cleaned result
return traits::unpack(std::forward<Callback>(callback), return traits::unpack(std::forward<Callback>(callback),
@ -223,7 +223,7 @@ constexpr auto finalize_impl(traits::identity<std::tuple<Args...>>,
struct hint_mapper { struct hint_mapper {
template <typename... T> template <typename... T>
constexpr auto operator()(T...) -> traits::identity<T...> { constexpr auto operator()(T...) -> identity<T...> {
return {}; return {};
} }
}; };
@ -233,7 +233,7 @@ template <typename Callback, typename Data>
constexpr auto finalize_data(Callback&& callback, Data&& data) { constexpr auto finalize_data(Callback&& callback, Data&& data) {
using result_t = decltype(unbox_continuables(std::forward<Data>(data))); using result_t = decltype(unbox_continuables(std::forward<Data>(data)));
// Guard the final result against void // Guard the final result against void
return detail::finalize_impl(traits::identity<std::decay_t<result_t>>{}, return detail::finalize_impl(identity<std::decay_t<result_t>>{},
std::forward<Callback>(callback), std::forward<Callback>(callback),
std::forward<Data>(data)); std::forward<Data>(data));
} }

View File

@ -88,30 +88,30 @@ private:
struct result_deducer { struct result_deducer {
template <typename T> template <typename T>
static auto deduce_one(std::false_type, traits::identity<T>) { static auto deduce_one(std::false_type, identity<T>) {
static_assert(traits::fail<T>::value, static_assert(traits::fail<T>::value,
"Non continuable types except tuple like and homogeneous " "Non continuable types except tuple like and homogeneous "
"containers aren't allowed inside an any expression!"); "containers aren't allowed inside an any expression!");
} }
template <typename T> template <typename T>
static auto deduce_one(std::true_type, traits::identity<T> id) { static auto deduce_one(std::true_type, identity<T> id) {
return base::annotation_of(id); return base::annotation_of(id);
} }
template <typename T> template <typename T>
static auto deduce(traversal::container_category_tag<false, false>, static auto deduce(traversal::container_category_tag<false, false>,
traits::identity<T> id) { identity<T> id) {
return deduce_one<T>(base::is_continuable<T>{}, id); return deduce_one<T>(base::is_continuable<T>{}, id);
} }
/// Deduce a homogeneous container /// Deduce a homogeneous container
template <bool IsTupleLike, typename T> template <bool IsTupleLike, typename T>
static auto deduce(traversal::container_category_tag<true, IsTupleLike>, static auto deduce(traversal::container_category_tag<true, IsTupleLike>,
traits::identity<T>) { identity<T>) {
// Deduce the containing type // Deduce the containing type
using element_t = std::decay_t<decltype(*std::declval<T>().begin())>; using element_t = std::decay_t<decltype(*std::declval<T>().begin())>;
return deduce(traversal::container_category_of_t<element_t>{}, return deduce(traversal::container_category_of_t<element_t>{},
traits::identity<element_t>{}); identity<element_t>{});
} }
template <typename First, typename... T> template <typename First, typename... T>
@ -125,19 +125,19 @@ struct result_deducer {
template <std::size_t... I, typename T> template <std::size_t... I, typename T>
static auto deduce_tuple_like(std::integer_sequence<std::size_t, I...>, static auto deduce_tuple_like(std::integer_sequence<std::size_t, I...>,
traits::identity<T>) { identity<T>) {
return deduce_same_hints(deduce( return deduce_same_hints(deduce(
traversal::container_category_of_t< traversal::container_category_of_t<
std::decay_t<decltype(std::get<I>(std::declval<T>()))>>{}, std::decay_t<decltype(std::get<I>(std::declval<T>()))>>{},
traits::identity< identity<
std::decay_t<decltype(std::get<I>(std::declval<T>()))>>{})...); std::decay_t<decltype(std::get<I>(std::declval<T>()))>>{})...);
} }
/// Traverse tuple like container /// Traverse tuple like container
template <typename T> template <typename T>
static auto deduce(traversal::container_category_tag<false, true>, static auto deduce(traversal::container_category_tag<false, true>,
traits::identity<T> id) { identity<T> id) {
constexpr auto const size = std::tuple_size<T>::value; constexpr auto const size = std::tuple_size<T>::value;
return deduce_tuple_like(std::make_index_sequence<size>{}, id); return deduce_tuple_like(std::make_index_sequence<size>{}, id);
@ -172,7 +172,7 @@ struct connection_finalizer<connection_strategy_any_tag> {
static auto finalize(Connection&& connection, util::ownership ownership) { static auto finalize(Connection&& connection, util::ownership ownership) {
constexpr auto const signature = decltype(any::result_deducer::deduce( constexpr auto const signature = decltype(any::result_deducer::deduce(
traversal::container_category_of_t<std::decay_t<Connection>>{}, traversal::container_category_of_t<std::decay_t<Connection>>{},
traits::identity<std::decay_t<Connection>>{})){}; identity<std::decay_t<Connection>>{})){};
return base::attorney::create_from( return base::attorney::create_from(
[connection = [connection =

View File

@ -42,7 +42,7 @@ struct annotation_trait;
/// Specialization for a present signature hint /// Specialization for a present signature hint
template <typename... Args> template <typename... Args>
struct annotation_trait<traits::identity<Args...>> { struct annotation_trait<identity<Args...>> {
template <typename Continuable> template <typename Continuable>
static Continuable&& finish(Continuable&& continuable) { static Continuable&& finish(Continuable&& continuable) {
return std::forward<Continuable>(continuable); return std::forward<Continuable>(continuable);
@ -55,9 +55,9 @@ namespace hints {
/// ///
/// This is the overload taking an arbitrary amount of args /// This is the overload taking an arbitrary amount of args
template <typename... HintArgs> template <typename... HintArgs>
struct from_args : std::common_type<traits::identity<HintArgs...>> {}; struct from_args : std::common_type<identity<HintArgs...>> {};
template <> template <>
struct from_args<void> : std::common_type<traits::identity<>> {}; struct from_args<void> : std::common_type<identity<>> {};
} // namespace hints } // namespace hints
} // namespace detail } // namespace detail
} // namespace cti } // namespace cti

View File

@ -122,7 +122,7 @@ struct ready_continuation<> {
template <typename Hint, typename Continuation> template <typename Hint, typename Continuation>
struct proxy_continuable; struct proxy_continuable;
template <typename... Args, typename Continuation> template <typename... Args, typename Continuation>
struct proxy_continuable<traits::identity<Args...>, Continuation> struct proxy_continuable<identity<Args...>, Continuation>
: Continuation { : Continuation {
explicit proxy_continuable(Continuation continuation) explicit proxy_continuable(Continuation continuation)
@ -192,9 +192,9 @@ struct attorney {
/// Returns the signature hint of the given continuable /// Returns the signature hint of the given continuable
template <typename Data, typename... Args> template <typename Data, typename... Args>
constexpr traits::identity<Args...> constexpr identity<Args...>
annotation_of(traits::identity<continuable_base<Data, // annotation_of(identity<continuable_base<Data, //
traits::identity<Args...>>>) { identity<Args...>>>) {
return {}; return {};
} }
@ -275,30 +275,30 @@ constexpr void invoke_no_except(T&& callable, Args&&... args) noexcept {
} }
template <typename... Args, typename T> template <typename... Args, typename T>
void invoke_void_no_except(traits::identity<exception_arg_t, Args...>, void invoke_void_no_except(identity<exception_arg_t, Args...>,
T&& /*callable*/) noexcept { T&& /*callable*/) noexcept {
// Don't invoke the next failure handler when being in an exception handler // Don't invoke the next failure handler when being in an exception handler
} }
template <typename... Args, typename T> template <typename... Args, typename T>
void invoke_void_no_except(traits::identity<Args...>, T&& callable) noexcept { void invoke_void_no_except(identity<Args...>, T&& callable) noexcept {
std::forward<T>(callable)(); std::forward<T>(callable)();
} }
template <typename T, typename... Args> template <typename T, typename... Args>
constexpr auto make_invoker(T&& invoke, traits::identity<Args...>) { constexpr auto make_invoker(T&& invoke, identity<Args...>) {
return invoker<std::decay_t<T>, traits::identity<Args...>>( return invoker<std::decay_t<T>, identity<Args...>>(
std::forward<T>(invoke)); std::forward<T>(invoke));
} }
/// - continuable<?...> -> result(next_callback); /// - continuable<?...> -> result(next_callback);
template <typename Data, typename Annotation> template <typename Data, typename Annotation>
constexpr auto constexpr auto
invoker_of(traits::identity<continuable_base<Data, Annotation>>) { invoker_of(identity<continuable_base<Data, Annotation>>) {
/// Get the hint of the unwrapped returned continuable /// Get the hint of the unwrapped returned continuable
using Type = using Type =
decltype(std::declval<continuable_base<Data, Annotation>>().finish()); decltype(std::declval<continuable_base<Data, Annotation>>().finish());
auto constexpr const hint = base::annotation_of(traits::identify<Type>{}); auto constexpr const hint = base::annotation_of(identify<Type>{});
return make_invoker( return make_invoker(
[](auto&& callback, auto&& next_callback, auto&&... args) { [](auto&& callback, auto&& next_callback, auto&&... args) {
@ -317,7 +317,7 @@ invoker_of(traits::identity<continuable_base<Data, Annotation>>) {
/// - ? -> next_callback(?) /// - ? -> next_callback(?)
template <typename T> template <typename T>
constexpr auto invoker_of(traits::identity<T>) { constexpr auto invoker_of(identity<T>) {
return make_invoker( return make_invoker(
[](auto&& callback, auto&& next_callback, auto&&... args) { [](auto&& callback, auto&& next_callback, auto&&... args) {
CONTINUABLE_BLOCK_TRY_BEGIN CONTINUABLE_BLOCK_TRY_BEGIN
@ -329,26 +329,26 @@ constexpr auto invoker_of(traits::identity<T>) {
std::move(result)); std::move(result));
CONTINUABLE_BLOCK_TRY_END CONTINUABLE_BLOCK_TRY_END
}, },
traits::identify<T>{}); identify<T>{});
} }
/// - void -> next_callback() /// - void -> next_callback()
inline auto invoker_of(traits::identity<void>) { inline auto invoker_of(identity<void>) {
return make_invoker( return make_invoker(
[](auto&& callback, auto&& next_callback, auto&&... args) { [](auto&& callback, auto&& next_callback, auto&&... args) {
CONTINUABLE_BLOCK_TRY_BEGIN CONTINUABLE_BLOCK_TRY_BEGIN
invoke_callback(std::forward<decltype(callback)>(callback), invoke_callback(std::forward<decltype(callback)>(callback),
std::forward<decltype(args)>(args)...); std::forward<decltype(args)>(args)...);
invoke_void_no_except( invoke_void_no_except(
traits::identity<traits::unrefcv_t<decltype(args)>...>{}, identity<traits::unrefcv_t<decltype(args)>...>{},
std::forward<decltype(next_callback)>(next_callback)); std::forward<decltype(next_callback)>(next_callback));
CONTINUABLE_BLOCK_TRY_END CONTINUABLE_BLOCK_TRY_END
}, },
traits::identity<>{}); identity<>{});
} }
/// - empty_result -> <cancel> /// - empty_result -> <cancel>
inline auto invoker_of(traits::identity<empty_result>) { inline auto invoker_of(identity<empty_result>) {
return make_invoker( return make_invoker(
[](auto&& callback, auto&& next_callback, auto&&... args) { [](auto&& callback, auto&& next_callback, auto&&... args) {
(void)next_callback; (void)next_callback;
@ -362,11 +362,11 @@ inline auto invoker_of(traits::identity<empty_result>) {
(void)result; (void)result;
CONTINUABLE_BLOCK_TRY_END CONTINUABLE_BLOCK_TRY_END
}, },
traits::identity<>{}); identity<>{});
} }
/// - exceptional_result -> <throw> /// - exceptional_result -> <throw>
inline auto invoker_of(traits::identity<exceptional_result>) { inline auto invoker_of(identity<exceptional_result>) {
return make_invoker( return make_invoker(
[](auto&& callback, auto&& next_callback, auto&&... args) { [](auto&& callback, auto&& next_callback, auto&&... args) {
util::unused(callback, next_callback, args...); util::unused(callback, next_callback, args...);
@ -381,12 +381,12 @@ inline auto invoker_of(traits::identity<exceptional_result>) {
std::move(result).get_exception()); std::move(result).get_exception());
CONTINUABLE_BLOCK_TRY_END CONTINUABLE_BLOCK_TRY_END
}, },
traits::identity<>{}); identity<>{});
} }
/// - result<?...> -> next_callback(?...) /// - result<?...> -> next_callback(?...)
template <typename... Args> template <typename... Args>
auto invoker_of(traits::identity<result<Args...>>) { auto invoker_of(identity<result<Args...>>) {
return make_invoker( return make_invoker(
[](auto&& callback, auto&& next_callback, auto&&... args) { [](auto&& callback, auto&& next_callback, auto&&... args) {
CONTINUABLE_BLOCK_TRY_BEGIN CONTINUABLE_BLOCK_TRY_BEGIN
@ -416,7 +416,7 @@ auto invoker_of(traits::identity<result<Args...>>) {
// asynchronous chain. // asynchronous chain.
CONTINUABLE_BLOCK_TRY_END CONTINUABLE_BLOCK_TRY_END
}, },
traits::identity<Args...>{}); identity<Args...>{});
} }
/// Returns a sequenced invoker which is able to invoke /// Returns a sequenced invoker which is able to invoke
@ -443,15 +443,15 @@ inline auto sequenced_unpack_invoker() {
// - std::pair<?, ?> -> next_callback(?, ?) // - std::pair<?, ?> -> next_callback(?, ?)
template <typename First, typename Second> template <typename First, typename Second>
constexpr auto invoker_of(traits::identity<std::pair<First, Second>>) { constexpr auto invoker_of(identity<std::pair<First, Second>>) {
return make_invoker(sequenced_unpack_invoker(), return make_invoker(sequenced_unpack_invoker(),
traits::identity<First, Second>{}); identity<First, Second>{});
} }
// - std::tuple<?...> -> next_callback(?...) // - std::tuple<?...> -> next_callback(?...)
template <typename... Args> template <typename... Args>
constexpr auto invoker_of(traits::identity<std::tuple<Args...>>) { constexpr auto invoker_of(identity<std::tuple<Args...>>) {
return make_invoker(sequenced_unpack_invoker(), traits::identity<Args...>{}); return make_invoker(sequenced_unpack_invoker(), identity<Args...>{});
} }
#undef CONTINUABLE_BLOCK_TRY_BEGIN #undef CONTINUABLE_BLOCK_TRY_BEGIN
@ -510,7 +510,7 @@ template <handle_results HandleResults, typename Base, typename Hint>
struct result_handler_base; struct result_handler_base;
template <typename Base, typename... Args> template <typename Base, typename... Args>
struct result_handler_base<handle_results::no, Base, struct result_handler_base<handle_results::no, Base,
traits::identity<Args...>> { identity<Args...>> {
void operator()(Args... args) && { void operator()(Args... args) && {
// Forward the arguments to the next callback // Forward the arguments to the next callback
std::move(static_cast<Base*>(this)->next_callback_)(std::move(args)...); std::move(static_cast<Base*>(this)->next_callback_)(std::move(args)...);
@ -518,13 +518,13 @@ struct result_handler_base<handle_results::no, Base,
}; };
template <typename Base, typename... Args> template <typename Base, typename... Args>
struct result_handler_base<handle_results::yes, Base, struct result_handler_base<handle_results::yes, Base,
traits::identity<Args...>> { identity<Args...>> {
/// The operator which is called when the result was provided /// The operator which is called when the result was provided
void operator()(Args... args) && { void operator()(Args... args) && {
// In order to retrieve the correct decorator we must know what the // In order to retrieve the correct decorator we must know what the
// result type is. // result type is.
constexpr auto result = constexpr auto result =
traits::identify<decltype(decoration::invoke_callback( identify<decltype(decoration::invoke_callback(
std::move(static_cast<Base*>(this)->callback_), std::move(static_cast<Base*>(this)->callback_),
std::move(args)...))>{}; std::move(args)...))>{};
@ -556,7 +556,7 @@ struct error_handler_base<handle_errors::forward, Base> {
/// The operator which is called when an error occurred /// The operator which is called when an error occurred
void operator()(exception_arg_t, exception_t exception) && { void operator()(exception_arg_t, exception_t exception) && {
constexpr auto result = constexpr auto result =
traits::identify<decltype(decoration::invoke_callback( identify<decltype(decoration::invoke_callback(
std::move(static_cast<Base*>(this)->callback_), exception_arg_t{}, std::move(static_cast<Base*>(this)->callback_), exception_arg_t{},
std::move(exception)))>{}; std::move(exception)))>{};
@ -580,16 +580,16 @@ struct callback_base;
template <typename... Args, handle_results HandleResults, template <typename... Args, handle_results HandleResults,
handle_errors HandleErrors, typename Callback, typename Executor, handle_errors HandleErrors, typename Callback, typename Executor,
typename NextCallback> typename NextCallback>
struct callback_base<traits::identity<Args...>, HandleResults, HandleErrors, struct callback_base<identity<Args...>, HandleResults, HandleErrors,
Callback, Executor, NextCallback> Callback, Executor, NextCallback>
: proto::result_handler_base< : proto::result_handler_base<
HandleResults, HandleResults,
callback_base<traits::identity<Args...>, HandleResults, HandleErrors, callback_base<identity<Args...>, HandleResults, HandleErrors,
Callback, Executor, NextCallback>, Callback, Executor, NextCallback>,
traits::identity<Args...>>, identity<Args...>>,
proto::error_handler_base< proto::error_handler_base<
HandleErrors, HandleErrors,
callback_base<traits::identity<Args...>, HandleResults, HandleErrors, callback_base<identity<Args...>, HandleResults, HandleErrors,
Callback, Executor, NextCallback>>, Callback, Executor, NextCallback>>,
util::non_copyable { util::non_copyable {
@ -606,14 +606,14 @@ struct callback_base<traits::identity<Args...>, HandleResults, HandleErrors,
/// Pull the result handling operator() in /// Pull the result handling operator() in
using proto::result_handler_base< using proto::result_handler_base<
HandleResults, HandleResults,
callback_base<traits::identity<Args...>, HandleResults, HandleErrors, callback_base<identity<Args...>, HandleResults, HandleErrors,
Callback, Executor, NextCallback>, Callback, Executor, NextCallback>,
traits::identity<Args...>>::operator(); identity<Args...>>::operator();
/// Pull the error handling operator() in /// Pull the error handling operator() in
using proto::error_handler_base< using proto::error_handler_base<
HandleErrors, HandleErrors,
callback_base<traits::identity<Args...>, HandleResults, HandleErrors, callback_base<identity<Args...>, HandleResults, HandleErrors,
Callback, Executor, NextCallback>>::operator(); Callback, Executor, NextCallback>>::operator();
/// Resolves the continuation with the given values /// Resolves the continuation with the given values
@ -684,21 +684,21 @@ struct final_callback : util::non_copyable {
template <typename T, typename... Args> template <typename T, typename... Args>
constexpr auto constexpr auto
next_hint_of(std::integral_constant<handle_results, handle_results::yes>, next_hint_of(std::integral_constant<handle_results, handle_results::yes>,
traits::identity<T> /*callback*/, identity<T> /*callback*/,
traits::identity<Args...> /*current*/) { identity<Args...> /*current*/) {
// Partial Invoke the given callback // Partial Invoke the given callback
using Result = decltype( using Result = decltype(
decoration::invoke_callback(std::declval<T>(), std::declval<Args>()...)); decoration::invoke_callback(std::declval<T>(), std::declval<Args>()...));
// Return the hint of thr given invoker // Return the hint of thr given invoker
return decltype(decoration::invoker_of(traits::identify<Result>{}).hint()){}; return decltype(decoration::invoker_of(identify<Result>{}).hint()){};
} }
/// Don't progress the hint when we don't continue /// Don't progress the hint when we don't continue
template <typename T, typename... Args> template <typename T, typename... Args>
constexpr auto constexpr auto
next_hint_of(std::integral_constant<handle_results, handle_results::no>, next_hint_of(std::integral_constant<handle_results, handle_results::no>,
traits::identity<T> /*callback*/, identity<T> /*callback*/,
traits::identity<Args...> current) { identity<Args...> current) {
return current; return current;
} }
@ -730,8 +730,8 @@ struct chained_continuation;
template <typename... Args, typename... NextArgs, handle_results HandleResults, template <typename... Args, typename... NextArgs, handle_results HandleResults,
handle_errors HandleErrors, typename Continuation, typename Callback, handle_errors HandleErrors, typename Continuation, typename Callback,
typename Executor> typename Executor>
struct chained_continuation<traits::identity<Args...>, struct chained_continuation<identity<Args...>,
traits::identity<NextArgs...>, HandleResults, identity<NextArgs...>, HandleResults,
HandleErrors, Continuation, Callback, Executor> { HandleErrors, Continuation, Callback, Executor> {
Continuation continuation_; Continuation continuation_;
@ -761,7 +761,7 @@ struct chained_continuation<traits::identity<Args...>,
// - Continuation: continuation<[](auto&& callback) { callback("hi"); }> // - Continuation: continuation<[](auto&& callback) { callback("hi"); }>
// - Callback: [](std::string) { } // - Callback: [](std::string) { }
// - NextCallback: []() { } // - NextCallback: []() { }
auto proxy = callbacks::make_callback<traits::identity<Args...>, auto proxy = callbacks::make_callback<identity<Args...>,
HandleResults, HandleErrors>( HandleResults, HandleErrors>(
std::move(callback_), std::move(executor_), std::move(callback_), std::move(executor_),
std::forward<decltype(next_callback)>(next_callback)); std::forward<decltype(next_callback)>(next_callback));
@ -793,7 +793,7 @@ struct chained_continuation<traits::identity<Args...>,
template <typename... Args, typename... NextArgs, handle_results HandleResults, template <typename... Args, typename... NextArgs, handle_results HandleResults,
handle_errors HandleErrors, typename Callback, typename Executor> handle_errors HandleErrors, typename Callback, typename Executor>
struct chained_continuation< struct chained_continuation<
traits::identity<Args...>, traits::identity<NextArgs...>, HandleResults, identity<Args...>, identity<NextArgs...>, HandleResults,
HandleErrors, ready_continuation<Args...>, Callback, Executor> { HandleErrors, ready_continuation<Args...>, Callback, Executor> {
ready_continuation<Args...> continuation_; ready_continuation<Args...> continuation_;
@ -815,7 +815,7 @@ struct chained_continuation<
template <typename NextCallback> template <typename NextCallback>
void operator()(NextCallback&& next_callback) { void operator()(NextCallback&& next_callback) {
auto proxy = callbacks::make_callback<traits::identity<Args...>, auto proxy = callbacks::make_callback<identity<Args...>,
HandleResults, HandleErrors>( HandleResults, HandleErrors>(
std::move(callback_), std::move(executor_), std::move(callback_), std::move(executor_),
std::forward<decltype(next_callback)>(next_callback)); std::forward<decltype(next_callback)>(next_callback));
@ -851,10 +851,10 @@ auto chain_continuation(Continuation&& continuation, Callback&& callback,
static_assert(is_continuable<std::decay_t<Continuation>>{}, static_assert(is_continuable<std::decay_t<Continuation>>{},
"Expected a continuation!"); "Expected a continuation!");
using Hint = decltype(base::annotation_of(traits::identify<Continuation>())); using Hint = decltype(base::annotation_of(identify<Continuation>()));
constexpr auto next_hint = constexpr auto next_hint =
next_hint_of(std::integral_constant<handle_results, HandleResults>{}, next_hint_of(std::integral_constant<handle_results, HandleResults>{},
traits::identify<decltype(callback)>{}, Hint{}); identify<decltype(callback)>{}, Hint{});
auto ownership = attorney::ownership_of(continuation); auto ownership = attorney::ownership_of(continuation);
auto data = auto data =
@ -885,11 +885,11 @@ void finalize_continuation(Continuation&& continuation) {
template <typename Data, typename Annotation, typename Continuation> template <typename Data, typename Annotation, typename Continuation>
struct can_accept_continuation : std::false_type {}; struct can_accept_continuation : std::false_type {};
template <typename Data, typename... Args, typename Continuation> template <typename Data, typename... Args, typename Continuation>
struct can_accept_continuation<Data, traits::identity<Args...>, Continuation> struct can_accept_continuation<Data, identity<Args...>, Continuation>
: traits::conjunction< : traits::conjunction<
traits::is_invocable<Continuation, callbacks::final_callback>, traits::is_invocable<Continuation, callbacks::final_callback>,
std::is_convertible< std::is_convertible<
proxy_continuable<traits::identity<Args...>, Continuation>, proxy_continuable<identity<Args...>, Continuation>,
Data>> {}; Data>> {};
/// Workaround for GCC bug: /// Workaround for GCC bug:

View File

@ -33,6 +33,7 @@
#include <utility> #include <utility>
#include <continuable/detail/features.hpp> #include <continuable/detail/features.hpp>
#include <continuable/detail/utility/identity.hpp>
#ifndef CONTINUABLE_WITH_CUSTOM_ERROR_TYPE #ifndef CONTINUABLE_WITH_CUSTOM_ERROR_TYPE
#ifndef CONTINUABLE_WITH_NO_EXCEPTIONS #ifndef CONTINUABLE_WITH_NO_EXCEPTIONS

View File

@ -57,7 +57,7 @@ using std::experimental::coroutine_handle;
template <typename T> template <typename T>
struct result_from_identity; struct result_from_identity;
template <typename... T> template <typename... T>
struct result_from_identity<traits::identity<T...>> { struct result_from_identity<identity<T...>> {
using result_t = result<T...>; using result_t = result<T...>;
}; };
@ -65,7 +65,7 @@ struct result_from_identity<traits::identity<T...>> {
/// for waiting on a continuable in a stackless coroutine. /// for waiting on a continuable in a stackless coroutine.
template <typename Continuable> template <typename Continuable>
class awaitable { class awaitable {
using hint_t = decltype(base::annotation_of(traits::identify<Continuable>{})); using hint_t = decltype(base::annotation_of(identify<Continuable>{}));
using result_t = typename result_from_identity<hint_t>::result_t; using result_t = typename result_from_identity<hint_t>::result_t;
/// The continuable which is invoked upon suspension /// The continuable which is invoked upon suspension

View File

@ -0,0 +1,97 @@
/*
/~` _ _ _|_. _ _ |_ | _
\_,(_)| | | || ||_|(_||_)|(/_
https://github.com/Naios/continuable
v4.0.0
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files(the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions :
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
**/
#ifndef CONTINUABLE_DETAIL_ERASURE_HPP_INCLUDED
#define CONTINUABLE_DETAIL_ERASURE_HPP_INCLUDED
#include <type_traits>
#include <function2/function2.hpp>
#include <continuable/detail/core/base.hpp>
#include <continuable/detail/features.hpp>
#include <continuable/detail/utility/traits.hpp>
#include <continuable/detail/utility/util.hpp>
namespace cti {
namespace detail {
namespace erasure {
/*template <typename... Args>
using continuation_capacity = std::integral_constant<
std::size_t, (sizeof(base::ready_continuation<Args...>) < sizeof(void*)
? sizeof(void*)
: sizeof(base::ready_continuation<Args...>))>;*/
template <std::size_t Size>
struct sized {
template <typename... Args>
using erasure_base_t = //
fu2::function_base<true, false, Size, //
true, false, Args...>;
};
template <template <typename...> class Wrapper, typename... Args>
using callback_of_t = Wrapper<void(Args...)&&, //
void(exception_arg_t, exception_t) &&>;
template <typename... Args>
using callback_base_t = callback_of_t<sized<0>::erasure_base_t, Args...>;
template <typename... Args>
class callback : public callback_base_t<Args...> {
public:
using callback_base_t<Args...>::callback_base_t;
using callback_base_t<Args...>::operator=;
using callback_base_t<Args...>::operator();
};
template <template <typename...> class Wrapper, typename Promise,
typename... Args>
using continuation_of_t = Wrapper<void(Promise), //
bool(is_ready_arg_t) const, //
std::tuple<Args...>(query_arg_t)>;
template <typename... Args>
using continuation_base_t =
continuation_of_t<sized<0 /*
continuation_capacity<Args...>::value*/>::erasure_base_t,
promise_base<callback<Args...>, signature_arg_t<Args>...>,
Args...>;
template <typename... Args>
class continuation : public continuation_base_t<Args...> {
public:
using continuation_base_t<Args...>::callback_base_t;
using continuation_base_t<Args...>::operator=;
using continuation_base_t<Args...>::operator();
};
} // namespace erasure
} // namespace detail
} // namespace cti
#endif // CONTINUABLE_DETAIL_ERASURE_HPP_INCLUDED

View File

@ -179,15 +179,15 @@ template <typename... Expected>
struct assert_async_types_validator { struct assert_async_types_validator {
template <typename... Actual> template <typename... Actual>
void operator()(Actual...) { void operator()(Actual...) {
static_assert(std::is_same<traits::identity<Actual...>, static_assert(std::is_same<identity<Actual...>,
traits::identity<Expected...>>::value, identity<Expected...>>::value,
"The called arguments don't match with the expected ones!"); "The called arguments don't match with the expected ones!");
} }
}; };
template <typename C, typename... Args> template <typename C, typename... Args>
void assert_async_types(C&& continuable, void assert_async_types(C&& continuable,
traits::identity<Args...> /*expected*/) { identity<Args...> /*expected*/) {
assert_async_validation(std::forward<C>(continuable), assert_async_validation(std::forward<C>(continuable),
assert_async_types_validator<Args...>{}); assert_async_types_validator<Args...>{});
} }

View File

@ -77,7 +77,7 @@ template <typename Hint>
class promise_callback; class promise_callback;
template <typename... Args> template <typename... Args>
class promise_callback<traits::identity<Args...>> class promise_callback<identity<Args...>>
: public future_trait<Args...> { : public future_trait<Args...> {
typename future_trait<Args...>::promise_t promise_; typename future_trait<Args...>::promise_t promise_;
@ -119,7 +119,7 @@ template <typename Data, typename Annotation>
auto as_future(continuable_base<Data, Annotation>&& continuable) { auto as_future(continuable_base<Data, Annotation>&& continuable) {
// Create the promise which is able to supply the current arguments // Create the promise which is able to supply the current arguments
constexpr auto const hint = constexpr auto const hint =
base::annotation_of(traits::identify<decltype(continuable)>{}); base::annotation_of(identify<decltype(continuable)>{});
promise_callback<std::decay_t<decltype(hint)>> callback; promise_callback<std::decay_t<decltype(hint)>> callback;
(void)hint; (void)hint;

View File

@ -62,7 +62,7 @@ template <typename T>
using align_of_helper = std::integral_constant<std::size_t, alignof(T)>; using align_of_helper = std::integral_constant<std::size_t, alignof(T)>;
template <typename... T> template <typename... T>
constexpr auto storage_of_impl(traits::identity<T...>) { constexpr auto storage_of_impl(identity<T...>) {
constexpr auto size = max_element_of({(size_of_helper<T>::value)...}); constexpr auto size = max_element_of({(size_of_helper<T>::value)...});
constexpr auto align = max_element_of({(align_of_helper<T>::value)...}); constexpr auto align = max_element_of({(align_of_helper<T>::value)...});
return std::aligned_storage_t<size, align>{}; return std::aligned_storage_t<size, align>{};
@ -70,7 +70,7 @@ constexpr auto storage_of_impl(traits::identity<T...>) {
/// Declares the aligned storage union for the given types /// Declares the aligned storage union for the given types
template <typename... T> template <typename... T>
using storage_of_t = decltype(storage_of_impl(traits::identity<T...>{})); using storage_of_t = decltype(storage_of_impl(identity<T...>{}));
/// The value fpr the empty slot /// The value fpr the empty slot
using slot_t = std::uint8_t; using slot_t = std::uint8_t;

View File

@ -0,0 +1,54 @@
/*
/~` _ _ _|_. _ _ |_ | _
\_,(_)| | | || ||_|(_||_)|(/_
https://github.com/Naios/continuable
v4.0.0
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files(the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions :
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
**/
#ifndef CONTINUABLE_DETAIL_IDENTITY_HPP_INCLUDED
#define CONTINUABLE_DETAIL_IDENTITY_HPP_INCLUDED
#include <type_traits>
#include <continuable/detail/features.hpp>
namespace cti {
namespace detail {
/// A tagging type for wrapping other types
template <typename... T>
struct identity {};
template <typename>
struct is_identity : std::false_type {};
template <typename... Args>
struct is_identity<identity<Args...>> : std::true_type {};
template <typename T>
using identify = std::conditional_t<is_identity<std::decay_t<T>>::value, T,
identity<std::decay_t<T>>>;
} // namespace detail
} // namespace cti
#endif // CONTINUABLE_DETAIL_IDENTITY_HPP_INCLUDED

View File

@ -36,6 +36,7 @@
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#include <continuable/detail/features.hpp> #include <continuable/detail/features.hpp>
#include <continuable/detail/utility/identity.hpp>
namespace cti { namespace cti {
namespace detail { namespace detail {
@ -69,19 +70,6 @@ auto make_flat_tuple(T&&... args) {
return std::tuple<T...>{std::forward<T>(args)...}; return std::tuple<T...>{std::forward<T>(args)...};
} }
/// A tagging type for wrapping other types
template <typename... T>
struct identity {};
template <typename>
struct is_identity : std::false_type {};
template <typename... Args>
struct is_identity<identity<Args...>> : std::true_type {};
template <typename T>
using identify = std::conditional_t<is_identity<std::decay_t<T>>::value, T,
identity<std::decay_t<T>>>;
#if defined(CONTINUABLE_HAS_CXX17_VOID_T) #if defined(CONTINUABLE_HAS_CXX17_VOID_T)
using std::void_t; using std::void_t;
#else #else

View File

@ -134,7 +134,7 @@ TYPED_TEST(single_dimension_tests, are_exceptions_partial_applyable) {
handled = false; handled = false;
ASSERT_ASYNC_INCOMPLETION( ASSERT_ASYNC_INCOMPLETION(
this->supply_exception(supply_test_exception(), this->supply_exception(supply_test_exception(),
detail::traits::identity<int, int>{}) detail::identity<int, int>{})
.fail([&]() -> result<int, int> { .fail([&]() -> result<int, int> {
EXPECT_FALSE(handled); EXPECT_FALSE(handled);
handled = true; handled = true;

View File

@ -34,7 +34,7 @@
#include <continuable/continuable-testing.hpp> #include <continuable/continuable-testing.hpp>
#include <continuable/continuable.hpp> #include <continuable/continuable.hpp>
using cti::detail::traits::identity; using cti::detail::identity;
using cti::detail::util::unused; using cti::detail::util::unused;
inline auto to_hint(identity<> /*hint*/) { inline auto to_hint(identity<> /*hint*/) {
@ -48,7 +48,7 @@ auto to_hint(identity<Args...> hint) {
template <typename... Args> template <typename... Args>
auto supplier_of(Args&&... args) { auto supplier_of(Args&&... args) {
return [values = std::make_tuple(std::forward<Args>(args)...)]( return [values = std::make_tuple(std::forward<Args>(args)...)](
auto&& promise) mutable { auto&& promise) mutable {
cti::detail::traits::unpack( cti::detail::traits::unpack(
[&](auto&&... passed) { [&](auto&&... passed) {
promise.set_value(std::forward<decltype(passed)>(passed)...); promise.set_value(std::forward<decltype(passed)>(passed)...);
@ -113,12 +113,12 @@ struct provide_copyable {
struct provide_unique { struct provide_unique {
template <typename... Args, typename... Hint, typename T> template <typename... Args, typename... Hint, typename T>
auto make(identity<Args...>, identity<Hint...>, T&& callback) { auto make(identity<Args...>, identity<Hint...>, T&& callback) {
return cti::make_continuable<Hint...>( return cti::make_continuable<Hint...>([
[callback = std::forward<T>(callback), callback = std::forward<T>(callback), guard = std::make_unique<int>(0)
guard = std::make_unique<int>(0)](auto&&... args) mutable { ](auto&&... args) mutable {
(void)(*guard); (void)(*guard);
return std::move(callback)(std::forward<decltype(args)>(args)...); return std::move(callback)(std::forward<decltype(args)>(args)...);
}); });
} }
}; };