Use new types instead of aliases for type erasures

* Makes compiler output much more readable
  This is configurateable through CONTINUABLE_WITH_IMMEDIATE_TYPES,
  and automatically enabled for debug builds but disabled
  for release builds.
* Remove the old continuable-trait.hpp header
* Make the signature of continuable not dependent anymore
  on any size of the arguments which fixes the compilation
  with forward declared types.
  Thanks Rogiel for the correspoding bug report.
  Closes #11
This commit is contained in:
Denis Blank 2019-01-04 00:09:26 +01:00
parent 2d5aa36b67
commit c066940d8d
32 changed files with 568 additions and 274 deletions

View File

@ -20,6 +20,7 @@ matrix:
- ninja-build - ninja-build
env: env:
- COMPILER=g++-6 - COMPILER=g++-6
- BUILD_CONFIG=Debug
- WITH_NO_EXCEPTIONS=OFF - WITH_NO_EXCEPTIONS=OFF
- WITH_AWAIT=OFF - WITH_AWAIT=OFF
- WITH_LIGHT_TESTS=ON - WITH_LIGHT_TESTS=ON
@ -36,6 +37,7 @@ matrix:
- ninja-build - ninja-build
env: env:
- COMPILER=clang++-5.0 - COMPILER=clang++-5.0
- BUILD_CONFIG=Release
- WITH_NO_EXCEPTIONS=OFF - WITH_NO_EXCEPTIONS=OFF
- WITH_AWAIT=OFF - WITH_AWAIT=OFF
- WITH_LIGHT_TESTS=OFF - WITH_LIGHT_TESTS=OFF
@ -52,6 +54,7 @@ matrix:
- ninja-build - ninja-build
env: env:
- COMPILER=clang++-5.0 - COMPILER=clang++-5.0
- BUILD_CONFIG=Debug
- WITH_NO_EXCEPTIONS=ON - WITH_NO_EXCEPTIONS=ON
- WITH_AWAIT=ON - WITH_AWAIT=ON
- WITH_LIGHT_TESTS=ON - WITH_LIGHT_TESTS=ON

View File

@ -3,11 +3,14 @@ image:
environment: environment:
matrix: matrix:
- WITH_NO_EXCEPTIONS: OFF - CONFIGURATION: Debug
WITH_NO_EXCEPTIONS: OFF
WITH_CPP_LATEST: OFF WITH_CPP_LATEST: OFF
- WITH_NO_EXCEPTIONS: ON - CONFIGURATION: Debug
WITH_NO_EXCEPTIONS: ON
WITH_CPP_LATEST: OFF WITH_CPP_LATEST: OFF
- WITH_NO_EXCEPTIONS: OFF - CONFIGURATION: Release
WITH_NO_EXCEPTIONS: OFF
WITH_CPP_LATEST: ON WITH_CPP_LATEST: ON
configuration: configuration:

View File

@ -38,13 +38,13 @@ PROJECT_NAME = Continuable
# could be handy for archiving the generated documentation or if some version # could be handy for archiving the generated documentation or if some version
# control system is used. # control system is used.
PROJECT_NUMBER = 3.0.0 PROJECT_NUMBER = 4.0.0
# Using the PROJECT_BRIEF tag one can provide an optional one line description # Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a # for a project that appears at the top of each page and should give viewer a
# quick idea about the purpose of the project. Keep the description short. # quick idea about the purpose of the project. Keep the description short.
PROJECT_BRIEF = PROJECT_BRIEF = "C++14 asynchronous allocation aware futures"
# With the PROJECT_LOGO tag one can specify a logo or an icon that is included # With the PROJECT_LOGO tag one can specify a logo or an icon that is included
# in the documentation. The maximum height of the logo should not exceed 55 # in the documentation. The maximum height of the logo should not exceed 55

View File

@ -41,7 +41,7 @@ New helper functions were added to create ready continuables:
The implementation of connections were rewritten entirely. The implementation of connections were rewritten entirely.
It is possible now to connect runtime sized containers as well as It is possible now to connect runtime sized containers as well as
deeply nested sequences. See \ref tutorial-connections for details. deeply nested sequences. See \ref tutorial-connecting-continuables for details.
Additionally connection overloads were added that accept two iterators Additionally connection overloads were added that accept two iterators
in order to come closer to the interface of the standard library. in order to come closer to the interface of the standard library.

View File

@ -34,6 +34,7 @@ in order to change the libraries behaviour:
| `CONTINUABLE_WITH_CUSTOM_ERROR_TYPE` | Exceptions are disabled and the type defined by `CONTINUABLE_WITH_CUSTOM_ERROR_TYPE` is used as \ref error_type . See \ref tutorial-chaining-continuables-fail for details. | | `CONTINUABLE_WITH_CUSTOM_ERROR_TYPE` | Exceptions are disabled and the type defined by `CONTINUABLE_WITH_CUSTOM_ERROR_TYPE` is used as \ref error_type . See \ref tutorial-chaining-continuables-fail for details. |
| `CONTINUABLE_WITH_UNHANDLED_EXCEPTIONS` | Allows unhandled exceptions in asynchronous call hierarchies. See \ref tutorial-chaining-continuables-fail for details. | | `CONTINUABLE_WITH_UNHANDLED_EXCEPTIONS` | Allows unhandled exceptions in asynchronous call hierarchies. See \ref tutorial-chaining-continuables-fail for details. |
| `CONTINUABLE_WITH_CUSTOM_FINAL_CALLBACK` | Allows to customize the final callback which can be used to implement custom unhandled asynchronous exception handlers. | | `CONTINUABLE_WITH_CUSTOM_FINAL_CALLBACK` | Allows to customize the final callback which can be used to implement custom unhandled asynchronous exception handlers. |
| `CONTINUABLE_WITH_IMMEDIATE_TYPES` | Don't decorate the used type erasure, which is done to keep type names minimal for better error messages in debug builds. |
| `CONTINUABLE_WITH_EXPERIMENTAL_COROUTINE` | Enables support for experimental coroutines and `co_await` expressions. See \ref continuable_base::operator co_await() for details. | | `CONTINUABLE_WITH_EXPERIMENTAL_COROUTINE` | Enables support for experimental coroutines and `co_await` expressions. See \ref continuable_base::operator co_await() for details. |
*/ */

View File

@ -123,19 +123,31 @@ public:
std::enable_if_t<detail::base::can_accept_continuation< std::enable_if_t<detail::base::can_accept_continuation<
Data, Annotation, Data, Annotation,
detail::traits::unrefcv_t<OtherData>>::value>* = nullptr> detail::traits::unrefcv_t<OtherData>>::value>* = nullptr>
continuable_base(OtherData&& data) /* implicit */ continuable_base(OtherData&& data)
: data_(detail::base::proxy_continuable< : data_(detail::base::proxy_continuable<
Annotation, detail::traits::unrefcv_t<OtherData>>( Annotation, detail::traits::unrefcv_t<OtherData>>(
std::forward<OtherData>(data))) { std::forward<OtherData>(data))) {
} }
/// Constructor taking the data of other continuable_base objects
/// while erasing the hint.
///
/// This constructor makes it possible to replace the internal data object of
/// the continuable by any object which is useful for type-erasure.
/*template <typename OData,
std::enable_if_t<std::is_convertible<
detail::traits::unrefcv_t<OData>, Data>::value>* = nullptr>
continuable_base(continuable_base<OData, Annotation>&& other)
: continuable_base(std::move(other).consume()) {
}*/
/// Constructor taking the data of other continuable_base objects /// Constructor taking the data of other continuable_base objects
/// while erasing the hint. /// while erasing the hint.
/// ///
/// This constructor makes it possible to replace the internal data object of /// This constructor makes it possible to replace the internal data object of
/// the continuable by any object which is useful for type-erasure. /// the continuable by any object which is useful for type-erasure.
template <typename OData, typename OAnnotation> template <typename OData, typename OAnnotation>
continuable_base(continuable_base<OData, OAnnotation>&& other) /* implicit */ continuable_base(continuable_base<OData, OAnnotation>&& other)
: continuable_base(std::move(other).finish().consume()) { : continuable_base(std::move(other).finish().consume()) {
} }
@ -853,7 +865,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)...},
@ -932,7 +944,7 @@ auto make_cancelling_continuable() {
/// // Recovered from the failure /// // Recovered from the failure
/// }) /// })
/// ``` /// ```
/// A corresponding \ref result is returned by \ref recover: /// A corresponding \ref result is returned by \ref recover
/// ```cpp /// ```cpp
/// http_request("example.com") /// http_request("example.com")
/// .then([](std::string content) -> cti::result<int, int> { /// .then([](std::string content) -> cti::result<int, int> {

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
@ -50,12 +51,19 @@ namespace cti {
/// ```cpp /// ```cpp
/// template<typename... Args> /// template<typename... Args>
/// struct callback { /// struct callback {
/// void operator() (Args...); /// void operator() (Args...) &&;
/// void operator() (cti::exception_arg_t, cti::exception_t); /// void operator() (cti::exception_arg_t, cti::exception_t) &&;
/// }; /// };
/// ``` /// ```
/// \{ /// \{
/// 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.
@ -69,7 +77,7 @@ struct is_ready_arg_t {};
/// It's required that the query of is_ready_arg_t returns true. /// It's required that the query of is_ready_arg_t returns true.
/// ///
/// \since 4.0.0 /// \since 4.0.0
struct query_arg_t {}; struct query_arg_t { };
/// Represents the tag type that is used to disambiguate the /// Represents the tag type that is used to disambiguate the
/// callback operator() in order to take the exception asynchronous chain. /// callback operator() in order to take the exception asynchronous chain.
@ -87,7 +95,7 @@ struct exception_arg_t {};
/// ///
[[deprecated("The dispatch_error_tag was replaced by exception_arg_t and will " [[deprecated("The dispatch_error_tag was replaced by exception_arg_t and will "
"be removed in a later major version!")]] // "be removed in a later major version!")]] //
typedef exception_arg_t dispatch_error_tag; typedef exception_arg_t dispatch_error_tag;
/// Represents the type that is used as exception type /// Represents the type that is used as exception type
/// ///
@ -108,7 +116,7 @@ using exception_t = detail::types::exception_t;
/// ///
[[deprecated("The error_type was replaced by exception_t and will " [[deprecated("The error_type was replaced by exception_t and will "
"be removed in a later major version!")]] // "be removed in a later major version!")]] //
typedef exception_t error_type; typedef exception_t error_type;
/// \} /// \}
} // namespace cti } // namespace cti

View File

@ -36,6 +36,7 @@
#include <continuable/continuable-primitives.hpp> #include <continuable/continuable-primitives.hpp>
#include <continuable/detail/core/annotation.hpp> #include <continuable/detail/core/annotation.hpp>
#include <continuable/detail/core/types.hpp> #include <continuable/detail/core/types.hpp>
#include <continuable/detail/utility/traits.hpp>
#include <continuable/detail/utility/util.hpp> #include <continuable/detail/utility/util.hpp>
namespace cti { namespace cti {
@ -62,7 +63,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
@ -83,8 +84,9 @@ public:
/// \endcond /// \endcond
/// Constructor accepting any object convertible to the data object /// Constructor accepting any object convertible to the data object
template <typename OData, std::enable_if_t<std::is_convertible< template <typename OData,
std::decay_t<OData>, Data>::value>* = nullptr> std::enable_if_t<std::is_convertible<
detail::traits::unrefcv_t<OData>, Data>::value>* = nullptr>
promise_base(OData&& data) : data_(std::forward<OData>(data)) { promise_base(OData&& data) : data_(std::forward<OData>(data)) {
} }

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

@ -1,89 +0,0 @@
/*
/~` _ _ _|_. _ _ |_ | _
\_,(_)| | | || ||_|(_||_)|(/_
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_TRAIT_HPP_INCLUDED
#define CONTINUABLE_TRAIT_HPP_INCLUDED
#include <cstddef>
#include <tuple>
#include <continuable/continuable-base.hpp>
#include <continuable/continuable-primitives.hpp>
#include <continuable/continuable-promise-base.hpp>
#include <continuable/detail/core/annotation.hpp>
#include <continuable/detail/core/types.hpp>
namespace cti {
/// \defgroup Types Types
/// provides the \link cti::continuable continuable\endlink and \link
/// cti::promise promise\endlink facility for type erasure.
/// \{
/// Trait to retrieve a continuable_base type with a given type-erasure backend.
///
/// Every object may me used as type-erasure backend as long as the
/// requirements of a `std::function` like wrapper are satisfied.
///
/// \tparam CallbackWrapper The type which is used to erase the callback.
///
/// \tparam ContinuationWrapper The type which is used to erase the
/// continuation data.
///
/// \tparam Args The current signature of the continuable.
template <template <std::size_t, typename...> class CallbackWrapper,
template <std::size_t, typename...> class ContinuationWrapper,
typename... Args>
class continuable_trait {
using callback = CallbackWrapper<0U, void(Args...)&&,
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.
using continuable = continuable_base<
ContinuationWrapper<
// Size the buffer for the small functor optimization so the
// result itself fits in and guarantee that a pointer can
// fit in as well.
(sizeof(detail::base::ready_continuation<Args...>) < sizeof(void*)
? sizeof(void*)
: sizeof(detail::base::ready_continuation<Args...>)),
void(promise), //
bool(is_ready_arg_t) const, //
std::tuple<Args...>(query_arg_t) //
>,
detail::traits::identity<Args...>>;
};
/// \}
} // namespace cti
#endif // CONTINUABLE_TRAIT_HPP_INCLUDED

View File

@ -31,9 +31,11 @@
#ifndef CONTINUABLE_TYPES_HPP_INCLUDED #ifndef CONTINUABLE_TYPES_HPP_INCLUDED
#define CONTINUABLE_TYPES_HPP_INCLUDED #define CONTINUABLE_TYPES_HPP_INCLUDED
#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,57 +43,65 @@ namespace cti {
/// cti::promise promise\endlink facility for type erasure. /// cti::promise promise\endlink facility for type erasure.
/// \{ /// \{
// clang-format off /// Deduces to the preferred continuation capacity for a possible
namespace detail { /// small functor optimization. The given capacity size is always enough to
/// A function which isn't size adjusted and move only /// to avoid any allocation when storing a ready continuable_base.
template<std::size_t, typename... Args> ///
using unique_function_adapter = fu2::unique_function<Args...>; /// \since 4.0.0
/// A function which is size adjusted and move only template <typename... Args>
template<std::size_t Size, typename... Args> using continuation_capacity = detail::erasure::continuation_capacity<Args...>;
using unique_function_adjustable = fu2::function_base<true, false, Size,
true, false, Args...>;
/// 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<
unique_function_adapter,
unique_function_adjustable,
Args...
>;
/// A type erasure for work objects
using work = fu2::unique_function<void()>;
} // 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>`
///
/// \note You can always define your own continuable with a type erasure of
/// choice, the type erasure wrapper just needs to accept a
/// callable object with a continuation signature as specified
/// in the Primitives section.
///
/// \since 1.0.0
template <typename... Args> template <typename... Args>
using continuable = typename detail::unique_trait_of< using continuable = continuable_base<detail::erasure::continuation<Args...>, //
Args... signature_arg_t<Args...>>;
>::continuable;
/// 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>`
///
/// \note You can always define your own promise with a type erasure of
/// choice, the type erasure wrapper just needs to accept a
/// callable object with a callback signature as specified
/// in the Primitives section.
///
/// \since 1.0.0
template <typename... Args> template <typename... Args>
using promise = typename detail::unique_trait_of< using promise = promise_base<detail::erasure::callback<Args...>, //
Args... signature_arg_t<Args...>>;
>::promise;
/// 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.
/// ///
/// \note You can always define your own work with a type erasure of
/// choice, the type erasure wrapper just needs to accept a
/// callable object which is callable with a `void()` signature.
///
/// \since 4.0.0 /// \since 4.0.0
using work = detail::work; class work : public fu2::unique_function<void()> {
public:
work() = default;
~work() = default;
work(work const&) = delete;
work(work&&) = default;
work& operator=(work const&) = delete;
work& operator=(work&&) = default;
// TODO channel using fu2::unique_function<void()>::unique_function;
// TODO sink using fu2::unique_function<void()>::operator=;
using fu2::unique_function<void()>::operator();
// clang-format on };
/// \} /// \}
} // namespace cti } // namespace cti

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,8 +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)
: Continuation(std::move(continuation)) { : Continuation(std::move(continuation)) {
@ -192,9 +191,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 +274,28 @@ 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(identity<continuable_base<Data, Annotation>>) {
invoker_of(traits::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 +314,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 +326,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 +359,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 +378,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 +413,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 +440,14 @@ 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(), identity<First, Second>{});
traits::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
@ -511,24 +507,20 @@ namespace proto {
template <handle_results HandleResults, typename Base, typename Hint> 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, identity<Args...>> {
traits::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)...);
} }
}; };
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, identity<Args...>> {
traits::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 = identify<decltype(decoration::invoke_callback(
traits::identify<decltype(decoration::invoke_callback( std::move(static_cast<Base*>(this)->callback_), std::move(args)...))>{};
std::move(static_cast<Base*>(this)->callback_),
std::move(args)...))>{};
// Pick the correct invoker that handles decorating of the result // Pick the correct invoker that handles decorating of the result
auto invoker = decoration::invoker_of(result); auto invoker = decoration::invoker_of(result);
@ -557,8 +549,7 @@ template <typename Base>
struct error_handler_base<handle_errors::forward, Base> { 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 = identify<decltype(decoration::invoke_callback(
traits::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)))>{};
@ -582,16 +573,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,
Callback, Executor, NextCallback> 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 {
@ -608,15 +599,15 @@ 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,
Callback, Executor, NextCallback>, 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,
Callback, Executor, NextCallback>>::operator(); Executor, NextCallback>>::operator();
/// Resolves the continuation with the given values /// Resolves the continuation with the given values
void set_value(Args... args) { void set_value(Args... args) {
@ -683,21 +674,19 @@ 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*/, identity<Args...> /*current*/) {
traits::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*/, identity<Args...> current) {
traits::identity<Args...> current) {
return current; return current;
} }
@ -729,9 +718,9 @@ 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...>, identity<NextArgs...>,
traits::identity<NextArgs...>, HandleResults, HandleResults, HandleErrors, Continuation, Callback,
HandleErrors, Continuation, Callback, Executor> { Executor> {
Continuation continuation_; Continuation continuation_;
Callback callback_; Callback callback_;
@ -760,8 +749,8 @@ 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,
HandleResults, HandleErrors>( 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));
@ -791,9 +780,9 @@ struct chained_continuation<traits::identity<Args...>,
// Specialization to unpack ready continuables directly // Specialization to unpack ready continuables directly
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<identity<Args...>, identity<NextArgs...>,
traits::identity<Args...>, traits::identity<NextArgs...>, HandleResults, HandleResults, HandleErrors,
HandleErrors, ready_continuation<Args...>, Callback, Executor> { ready_continuation<Args...>, Callback, Executor> {
ready_continuation<Args...> continuation_; ready_continuation<Args...> continuation_;
Callback callback_; Callback callback_;
@ -814,8 +803,8 @@ 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,
HandleResults, HandleErrors>( 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));
@ -850,10 +839,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 =
@ -875,7 +864,7 @@ auto chain_continuation(Continuation&& continuation, Callback&& callback,
/// - Continuation: continuation<[](auto&& callback) { callback("hi"); }> /// - Continuation: continuation<[](auto&& callback) { callback("hi"); }>
template <typename Data, typename... Args> template <typename Data, typename... Args>
void finalize_continuation( void finalize_continuation(
continuable_base<Data, traits::identity<Args...>>&& continuation) noexcept { continuable_base<Data, identity<Args...>>&& continuation) noexcept {
#ifdef CONTINUABLE_WITH_CUSTOM_FINAL_CALLBACK #ifdef CONTINUABLE_WITH_CUSTOM_FINAL_CALLBACK
invoke_continuation(std::move(continuation), invoke_continuation(std::move(continuation),
CONTINUABLE_WITH_CUSTOM_FINAL_CALLBACK<Args...>{}); CONTINUABLE_WITH_CUSTOM_FINAL_CALLBACK<Args...>{});
@ -890,13 +879,12 @@ void finalize_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, traits::is_invocable<Continuation,
callbacks::final_callback<Args...>>, callbacks::final_callback<Args...>>,
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:
/// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64095 /// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64095

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

@ -106,6 +106,18 @@
#else #else
#undef CONTINUABLE_HAS_EXCEPTIONS #undef CONTINUABLE_HAS_EXCEPTIONS
#endif #endif
/// Define CONTINUABLE_HAS_IMMEDIATE_TYPES when either
/// - CONTINUABLE_WITH_IMMEDIATE_TYPES is defined
/// - Building in release mode (NDEBUG is defined)
///
/// Build error messages will become more readable in debug mode while
/// we don't suffer any runtime penalty in release.
#if defined(CONTINUABLE_WITH_IMMEDIATE_TYPES) || defined(NDEBUG)
#define CONTINUABLE_HAS_IMMEDIATE_TYPES 1
#else
#undef CONTINUABLE_HAS_IMMEDIATE_TYPES
#endif
// clang-format on // clang-format on
#endif // CONTINUABLE_DETAIL_FEATURES_HPP_INCLUDED #endif // CONTINUABLE_DETAIL_FEATURES_HPP_INCLUDED

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,180 @@
/*
/~` _ _ _|_. _ _ |_ | _
\_,(_)| | | || ||_|(_||_)|(/_
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 <utility>
#include <function2/function2.hpp>
#include <continuable/detail/core/base.hpp>
#include <continuable/detail/features.hpp>
#include <continuable/detail/utility/traits.hpp>
namespace cti {
namespace detail {
namespace erasure {
template <typename... Args>
using callback_erasure_t =
fu2::function_base<true, false, fu2::capacity_none, true, false,
void(Args...)&&, void(exception_arg_t, exception_t) &&>;
#ifdef CONTINUABLE_HAS_IMMEDIATE_TYPES
template <typename... Args>
using callback = callback_erasure_t<Args...>;
#else
template <typename... Args>
class callback;
template <typename T>
struct is_callback : std::false_type {};
template <typename... Args>
struct is_callback<callback<Args...>> : std::true_type {};
template <typename... Args>
class callback : public callback_erasure_t<Args...> {
public:
using erasure_t = callback_erasure_t<Args...>;
erasure_t erasure_;
callback() = default;
~callback() = default;
callback(callback const&) = delete;
callback(callback&&) = default;
callback& operator=(callback const&) = delete;
callback& operator=(callback&&) = default;
template <
typename T,
std::enable_if_t<std::is_convertible<T, erasure_t>::value>* = nullptr,
std::enable_if_t<!is_callback<traits::unrefcv_t<T>>::value>* = nullptr>
/* implicit */ callback(T&& callable) : erasure_(std::forward<T>(callable)) {
}
template <
typename T,
std::enable_if_t<std::is_assignable<erasure_t, T>::value>* = nullptr,
std::enable_if_t<!is_callback<traits::unrefcv_t<T>>::value>* = nullptr>
callback& operator=(T&& callable) {
erasure_ = std::forward<T>(callable);
return *this;
}
void operator()(Args... args) && {
std::move(erasure_)(std::move(args)...);
}
void operator()(exception_arg_t exception_arg, exception_t exception) && {
std::move(erasure_)(exception_arg, std::move(exception));
}
};
#endif
template <typename... Args>
struct continuation_capacity {
using type = union {
void* pointer_;
base::ready_continuation<Args...> continuation_;
};
static constexpr std::size_t capacity = sizeof(type);
static constexpr std::size_t alignment = alignof(type);
};
template <typename... Args>
using continuation_erasure_t = fu2::function_base<
true, false, continuation_capacity<Args...>, true, false,
void(promise_base<callback<Args...>, signature_arg_t<Args...>>),
bool(is_ready_arg_t) const, std::tuple<Args...>(query_arg_t)>;
#ifdef CONTINUABLE_HAS_IMMEDIATE_TYPES
template <typename... Args>
using continuation = continuation_erasure_t<Args...>;
#else
template <typename... Args>
class continuation;
template <typename T>
struct is_continuation : std::false_type {};
template <typename... Args>
struct is_continuation<continuation<Args...>> : std::true_type {};
template <typename... Args>
class continuation {
using erasure_t = continuation_erasure_t<Args...>;
erasure_t erasure_;
public:
continuation() = default;
~continuation() = default;
continuation(continuation const&) = delete;
continuation(continuation&&) = default;
continuation& operator=(continuation const&) = delete;
continuation& operator=(continuation&&) = default;
template <
typename T,
std::enable_if_t<std::is_convertible<T, erasure_t>::value>* = nullptr,
std::enable_if_t<!is_continuation<traits::unrefcv_t<T>>::value>* =
nullptr>
/* implicit */ continuation(T&& callable)
: erasure_(std::forward<T>(callable)) {
}
template <
typename T,
std::enable_if_t<std::is_assignable<erasure_t, T>::value>* = nullptr,
std::enable_if_t<!is_continuation<traits::unrefcv_t<T>>::value>* =
nullptr>
continuation& operator=(T&& callable) {
erasure_ = std::forward<T>(callable);
return *this;
}
void operator()(promise_base<callback<Args...>, //
signature_arg_t<Args...>>
promise) {
erasure_(std::move(promise));
}
bool operator()(is_ready_arg_t is_ready_arg) const {
return erasure_(is_ready_arg);
}
std::tuple<Args...> operator()(query_arg_t query_arg) {
return erasure_(query_arg);
}
};
#endif
} // 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

@ -17,9 +17,11 @@ target_link_libraries(test-continuable-base
add_executable(test-continuable-single add_executable(test-continuable-single
${CMAKE_CURRENT_LIST_DIR}/single/test-continuable-connection-noinst ${CMAKE_CURRENT_LIST_DIR}/single/test-continuable-connection-noinst
${CMAKE_CURRENT_LIST_DIR}/single/test-continuable-forward-decl.cpp
${CMAKE_CURRENT_LIST_DIR}/single/test-continuable-flat-variant.cpp ${CMAKE_CURRENT_LIST_DIR}/single/test-continuable-flat-variant.cpp
${CMAKE_CURRENT_LIST_DIR}/single/test-continuable-result.cpp ${CMAKE_CURRENT_LIST_DIR}/single/test-continuable-result.cpp
${CMAKE_CURRENT_LIST_DIR}/single/test-continuable-promisify.cpp ${CMAKE_CURRENT_LIST_DIR}/single/test-continuable-promisify.cpp
${CMAKE_CURRENT_LIST_DIR}/single/test-continuable-erasure.cpp
${CMAKE_CURRENT_LIST_DIR}/single/test-continuable-traverse.cpp ${CMAKE_CURRENT_LIST_DIR}/single/test-continuable-traverse.cpp
${CMAKE_CURRENT_LIST_DIR}/single/test-continuable-traverse-async.cpp) ${CMAKE_CURRENT_LIST_DIR}/single/test-continuable-traverse-async.cpp)

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

@ -0,0 +1,89 @@
/*
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.
**/
#include <memory>
#include <utility>
#include <test-continuable.hpp>
using namespace cti;
struct mypromise {
void operator()() && {
}
void operator()(exception_arg_t, exception_t) && {
}
};
struct my_continuation {
template <typename Callback>
void operator()(Callback&&) {
}
bool operator()(is_ready_arg_t) const noexcept {
return true;
}
std::tuple<> operator()(query_arg_t) {
return std::make_tuple();
}
};
TEST(single_erasure_test, is_assignable_from_promise) {
detail::erasure::callback<> p(mypromise{});
std::move(p)();
}
TEST(single_erasure_test, is_assignable_from_continuation) {
detail::erasure::continuation<> c(my_continuation{});
ASSERT_TRUE(c(is_ready_arg_t{}));
c(mypromise{});
}
TEST(single_erasure_test, is_constructible_from_work) {
bool flag = false;
work mywork([&] {
EXPECT_FALSE(flag);
flag = true;
});
ASSERT_FALSE(flag);
mywork();
ASSERT_TRUE(flag);
}
TEST(single_erasure_test, is_assignable_from_work) {
bool flag = false;
work mywork;
mywork = [&] {
EXPECT_FALSE(flag);
flag = true;
};
ASSERT_FALSE(flag);
mywork();
ASSERT_TRUE(flag);
}

View File

@ -0,0 +1,31 @@
/*
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.
**/
#include <test-continuable.hpp>
struct forward_decl_type_0;
struct forward_decl_type_1;
cti::continuable<forward_decl_type_0> fails_not_with_forward_decls_1();
cti::continuable<forward_decl_type_0, forward_decl_type_1>
fails_not_with_forward_decls_2();

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*/) {
@ -113,9 +113,9 @@ 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)...);
}); });

View File

@ -56,7 +56,7 @@ function renew_build {
# Configure the project and build it # Configure the project and build it
cmake -GNinja -DCMAKE_CXX_FLAGS="$STD_CXX_FLAGS $CMAKE_CXX_FLAGS -Werror" -DCMAKE_EXE_LINKER_FLAGS="$STD_LINKER_FLAGS" \ cmake -GNinja -DCMAKE_CXX_FLAGS="$STD_CXX_FLAGS $CMAKE_CXX_FLAGS -Werror" -DCMAKE_EXE_LINKER_FLAGS="$STD_LINKER_FLAGS" \
-DCTI_CONTINUABLE_WITH_NO_EXCEPTIONS=$WITH_NO_EXCEPTIONS -DCTI_CONTINUABLE_WITH_EXPERIMENTAL_COROUTINE=$WITH_AWAIT -DCTI_CONTINUABLE_WITH_LIGHT_TESTS=$WITH_LIGHT_TESTS \ -DCTI_CONTINUABLE_WITH_NO_EXCEPTIONS=$WITH_NO_EXCEPTIONS -DCTI_CONTINUABLE_WITH_EXPERIMENTAL_COROUTINE=$WITH_AWAIT -DCTI_CONTINUABLE_WITH_LIGHT_TESTS=$WITH_LIGHT_TESTS \
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_BUILD_TYPE=Debug .. -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_BUILD_TYPE=$BUILD_CONFIG ..
} }
if [[ $CXX == *"clang"* ]]; then if [[ $CXX == *"clang"* ]]; then