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

View File

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

View File

@ -38,13 +38,13 @@ PROJECT_NAME = Continuable
# could be handy for archiving the generated documentation or if some version
# 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
# 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.
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
# 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.
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
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_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_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. |
*/

View File

@ -123,19 +123,31 @@ public:
std::enable_if_t<detail::base::can_accept_continuation<
Data, Annotation,
detail::traits::unrefcv_t<OtherData>>::value>* = nullptr>
continuable_base(OtherData&& data)
/* implicit */ continuable_base(OtherData&& data)
: data_(detail::base::proxy_continuable<
Annotation, detail::traits::unrefcv_t<OtherData>>(
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
/// 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, typename OAnnotation>
continuable_base(continuable_base<OData, OAnnotation>&& other)
/* implicit */ continuable_base(continuable_base<OData, OAnnotation>&& other)
: continuable_base(std::move(other).finish().consume()) {
}
@ -853,7 +865,7 @@ constexpr auto make_continuable(Continuation&& continuation) {
template <typename... Args>
auto make_ready_continuable(Args&&... args) {
using detail::base::ready_continuation;
using detail::traits::identity;
using detail::identity;
using detail::traits::unrefcv_t;
return detail::base::attorney::create_from_raw(
ready_continuation<unrefcv_t<Args>...>{std::forward<Args>(args)...},
@ -932,7 +944,7 @@ auto make_cancelling_continuable() {
/// // Recovered from the failure
/// })
/// ```
/// A corresponding \ref result is returned by \ref recover:
/// A corresponding \ref result is returned by \ref recover
/// ```cpp
/// http_request("example.com")
/// .then([](std::string content) -> cti::result<int, int> {

View File

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

View File

@ -32,6 +32,7 @@
#define CONTINUABLE_PRIMITIVES_HPP_INCLUDED
#include <continuable/detail/core/types.hpp>
#include <continuable/detail/utility/identity.hpp>
namespace cti {
/// \defgroup Primitives Primitives
@ -50,12 +51,19 @@ namespace cti {
/// ```cpp
/// template<typename... Args>
/// struct callback {
/// void operator() (Args...);
/// void operator() (cti::exception_arg_t, cti::exception_t);
/// void operator() (Args...) &&;
/// 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
/// for whether it resolves the callback instantly with its arguments
/// 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.
///
/// \since 4.0.0
struct query_arg_t {};
struct query_arg_t { };
/// Represents the tag type that is used to disambiguate the
/// 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 "
"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
///
@ -108,7 +116,7 @@ using exception_t = detail::types::exception_t;
///
[[deprecated("The error_type was replaced by exception_t and will "
"be removed in a later major version!")]] //
typedef exception_t error_type;
typedef exception_t error_type;
/// \}
} // namespace cti

View File

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

View File

@ -158,7 +158,7 @@
/// \since 1.0.0
#define ASSERT_ASYNC_TYPES(CONTINUABLE, ...) \
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
///

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
#define CONTINUABLE_TYPES_HPP_INCLUDED
#include <cstddef>
#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 {
/// \defgroup Types Types
@ -41,57 +43,65 @@ namespace cti {
/// cti::promise promise\endlink facility for type erasure.
/// \{
// clang-format off
namespace detail {
/// A function which isn't size adjusted and move only
template<std::size_t, typename... Args>
using unique_function_adapter = fu2::unique_function<Args...>;
/// A function which is size adjusted and move only
template<std::size_t Size, typename... 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
/// Deduces to the preferred continuation capacity for a possible
/// small functor optimization. The given capacity size is always enough to
/// to avoid any allocation when storing a ready continuable_base.
///
/// \since 4.0.0
template <typename... Args>
using continuation_capacity = detail::erasure::continuation_capacity<Args...>;
/// Defines a non-copyable continuation type which uses the
/// function2 backend for type erasure.
///
/// 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>
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
/// function2 backend for type erasure.
///
/// 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>
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
/// 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
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
// TODO sink
// clang-format on
using fu2::unique_function<void()>::unique_function;
using fu2::unique_function<void()>::operator=;
using fu2::unique_function<void()>::operator();
};
/// \}
} // namespace cti

View File

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

View File

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

View File

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

View File

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

View File

@ -122,8 +122,7 @@ struct ready_continuation<> {
template <typename Hint, typename Continuation>
struct proxy_continuable;
template <typename... Args, typename Continuation>
struct proxy_continuable<traits::identity<Args...>, Continuation>
: Continuation {
struct proxy_continuable<identity<Args...>, Continuation> : Continuation {
explicit proxy_continuable(Continuation continuation)
: Continuation(std::move(continuation)) {
@ -192,9 +191,9 @@ struct attorney {
/// Returns the signature hint of the given continuable
template <typename Data, typename... Args>
constexpr traits::identity<Args...>
annotation_of(traits::identity<continuable_base<Data, //
traits::identity<Args...>>>) {
constexpr identity<Args...>
annotation_of(identity<continuable_base<Data, //
identity<Args...>>>) {
return {};
}
@ -275,30 +274,28 @@ constexpr void invoke_no_except(T&& callable, Args&&... args) noexcept {
}
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 {
// Don't invoke the next failure handler when being in an exception handler
}
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)();
}
template <typename T, typename... Args>
constexpr auto make_invoker(T&& invoke, traits::identity<Args...>) {
return invoker<std::decay_t<T>, traits::identity<Args...>>(
std::forward<T>(invoke));
constexpr auto make_invoker(T&& invoke, identity<Args...>) {
return invoker<std::decay_t<T>, identity<Args...>>(std::forward<T>(invoke));
}
/// - continuable<?...> -> result(next_callback);
template <typename Data, typename Annotation>
constexpr auto
invoker_of(traits::identity<continuable_base<Data, Annotation>>) {
constexpr auto invoker_of(identity<continuable_base<Data, Annotation>>) {
/// Get the hint of the unwrapped returned continuable
using Type =
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(
[](auto&& callback, auto&& next_callback, auto&&... args) {
@ -317,7 +314,7 @@ invoker_of(traits::identity<continuable_base<Data, Annotation>>) {
/// - ? -> next_callback(?)
template <typename T>
constexpr auto invoker_of(traits::identity<T>) {
constexpr auto invoker_of(identity<T>) {
return make_invoker(
[](auto&& callback, auto&& next_callback, auto&&... args) {
CONTINUABLE_BLOCK_TRY_BEGIN
@ -329,26 +326,26 @@ constexpr auto invoker_of(traits::identity<T>) {
std::move(result));
CONTINUABLE_BLOCK_TRY_END
},
traits::identify<T>{});
identify<T>{});
}
/// - void -> next_callback()
inline auto invoker_of(traits::identity<void>) {
inline auto invoker_of(identity<void>) {
return make_invoker(
[](auto&& callback, auto&& next_callback, auto&&... args) {
CONTINUABLE_BLOCK_TRY_BEGIN
invoke_callback(std::forward<decltype(callback)>(callback),
std::forward<decltype(args)>(args)...);
invoke_void_no_except(
traits::identity<traits::unrefcv_t<decltype(args)>...>{},
identity<traits::unrefcv_t<decltype(args)>...>{},
std::forward<decltype(next_callback)>(next_callback));
CONTINUABLE_BLOCK_TRY_END
},
traits::identity<>{});
identity<>{});
}
/// - empty_result -> <cancel>
inline auto invoker_of(traits::identity<empty_result>) {
inline auto invoker_of(identity<empty_result>) {
return make_invoker(
[](auto&& callback, auto&& next_callback, auto&&... args) {
(void)next_callback;
@ -362,11 +359,11 @@ inline auto invoker_of(traits::identity<empty_result>) {
(void)result;
CONTINUABLE_BLOCK_TRY_END
},
traits::identity<>{});
identity<>{});
}
/// - exceptional_result -> <throw>
inline auto invoker_of(traits::identity<exceptional_result>) {
inline auto invoker_of(identity<exceptional_result>) {
return make_invoker(
[](auto&& callback, auto&& next_callback, auto&&... args) {
util::unused(callback, next_callback, args...);
@ -381,12 +378,12 @@ inline auto invoker_of(traits::identity<exceptional_result>) {
std::move(result).get_exception());
CONTINUABLE_BLOCK_TRY_END
},
traits::identity<>{});
identity<>{});
}
/// - result<?...> -> next_callback(?...)
template <typename... Args>
auto invoker_of(traits::identity<result<Args...>>) {
auto invoker_of(identity<result<Args...>>) {
return make_invoker(
[](auto&& callback, auto&& next_callback, auto&&... args) {
CONTINUABLE_BLOCK_TRY_BEGIN
@ -416,7 +413,7 @@ auto invoker_of(traits::identity<result<Args...>>) {
// asynchronous chain.
CONTINUABLE_BLOCK_TRY_END
},
traits::identity<Args...>{});
identity<Args...>{});
}
/// Returns a sequenced invoker which is able to invoke
@ -443,15 +440,14 @@ inline auto sequenced_unpack_invoker() {
// - std::pair<?, ?> -> next_callback(?, ?)
template <typename First, typename Second>
constexpr auto invoker_of(traits::identity<std::pair<First, Second>>) {
return make_invoker(sequenced_unpack_invoker(),
traits::identity<First, Second>{});
constexpr auto invoker_of(identity<std::pair<First, Second>>) {
return make_invoker(sequenced_unpack_invoker(), identity<First, Second>{});
}
// - std::tuple<?...> -> next_callback(?...)
template <typename... Args>
constexpr auto invoker_of(traits::identity<std::tuple<Args...>>) {
return make_invoker(sequenced_unpack_invoker(), traits::identity<Args...>{});
constexpr auto invoker_of(identity<std::tuple<Args...>>) {
return make_invoker(sequenced_unpack_invoker(), identity<Args...>{});
}
#undef CONTINUABLE_BLOCK_TRY_BEGIN
@ -511,24 +507,20 @@ namespace proto {
template <handle_results HandleResults, typename Base, typename Hint>
struct result_handler_base;
template <typename Base, typename... Args>
struct result_handler_base<handle_results::no, Base,
traits::identity<Args...>> {
struct result_handler_base<handle_results::no, Base, identity<Args...>> {
void operator()(Args... args) && {
// Forward the arguments to the next callback
std::move(static_cast<Base*>(this)->next_callback_)(std::move(args)...);
}
};
template <typename Base, typename... Args>
struct result_handler_base<handle_results::yes, Base,
traits::identity<Args...>> {
struct result_handler_base<handle_results::yes, Base, identity<Args...>> {
/// The operator which is called when the result was provided
void operator()(Args... args) && {
// In order to retrieve the correct decorator we must know what the
// result type is.
constexpr auto result =
traits::identify<decltype(decoration::invoke_callback(
std::move(static_cast<Base*>(this)->callback_),
std::move(args)...))>{};
constexpr auto result = identify<decltype(decoration::invoke_callback(
std::move(static_cast<Base*>(this)->callback_), std::move(args)...))>{};
// Pick the correct invoker that handles decorating of the result
auto invoker = decoration::invoker_of(result);
@ -557,10 +549,9 @@ template <typename Base>
struct error_handler_base<handle_errors::forward, Base> {
/// The operator which is called when an error occurred
void operator()(exception_arg_t, exception_t exception) && {
constexpr auto result =
traits::identify<decltype(decoration::invoke_callback(
std::move(static_cast<Base*>(this)->callback_), exception_arg_t{},
std::move(exception)))>{};
constexpr auto result = identify<decltype(decoration::invoke_callback(
std::move(static_cast<Base*>(this)->callback_), exception_arg_t{},
std::move(exception)))>{};
auto invoker = decoration::invoker_of(result);
@ -582,16 +573,16 @@ struct callback_base;
template <typename... Args, handle_results HandleResults,
handle_errors HandleErrors, typename Callback, typename Executor,
typename NextCallback>
struct callback_base<traits::identity<Args...>, HandleResults, HandleErrors,
Callback, Executor, NextCallback>
struct callback_base<identity<Args...>, HandleResults, HandleErrors, Callback,
Executor, NextCallback>
: proto::result_handler_base<
HandleResults,
callback_base<traits::identity<Args...>, HandleResults, HandleErrors,
callback_base<identity<Args...>, HandleResults, HandleErrors,
Callback, Executor, NextCallback>,
traits::identity<Args...>>,
identity<Args...>>,
proto::error_handler_base<
HandleErrors,
callback_base<traits::identity<Args...>, HandleResults, HandleErrors,
callback_base<identity<Args...>, HandleResults, HandleErrors,
Callback, Executor, NextCallback>>,
util::non_copyable {
@ -608,15 +599,15 @@ struct callback_base<traits::identity<Args...>, HandleResults, HandleErrors,
/// Pull the result handling operator() in
using proto::result_handler_base<
HandleResults,
callback_base<traits::identity<Args...>, HandleResults, HandleErrors,
Callback, Executor, NextCallback>,
traits::identity<Args...>>::operator();
callback_base<identity<Args...>, HandleResults, HandleErrors, Callback,
Executor, NextCallback>,
identity<Args...>>::operator();
/// Pull the error handling operator() in
using proto::error_handler_base<
HandleErrors,
callback_base<traits::identity<Args...>, HandleResults, HandleErrors,
Callback, Executor, NextCallback>>::operator();
callback_base<identity<Args...>, HandleResults, HandleErrors, Callback,
Executor, NextCallback>>::operator();
/// Resolves the continuation with the given values
void set_value(Args... args) {
@ -683,21 +674,19 @@ struct final_callback : util::non_copyable {
template <typename T, typename... Args>
constexpr auto
next_hint_of(std::integral_constant<handle_results, handle_results::yes>,
traits::identity<T> /*callback*/,
traits::identity<Args...> /*current*/) {
identity<T> /*callback*/, identity<Args...> /*current*/) {
// Partial Invoke the given callback
using Result = decltype(
decoration::invoke_callback(std::declval<T>(), std::declval<Args>()...));
// 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
template <typename T, typename... Args>
constexpr auto
next_hint_of(std::integral_constant<handle_results, handle_results::no>,
traits::identity<T> /*callback*/,
traits::identity<Args...> current) {
identity<T> /*callback*/, identity<Args...> current) {
return current;
}
@ -729,9 +718,9 @@ struct chained_continuation;
template <typename... Args, typename... NextArgs, handle_results HandleResults,
handle_errors HandleErrors, typename Continuation, typename Callback,
typename Executor>
struct chained_continuation<traits::identity<Args...>,
traits::identity<NextArgs...>, HandleResults,
HandleErrors, Continuation, Callback, Executor> {
struct chained_continuation<identity<Args...>, identity<NextArgs...>,
HandleResults, HandleErrors, Continuation, Callback,
Executor> {
Continuation continuation_;
Callback callback_;
@ -760,8 +749,8 @@ struct chained_continuation<traits::identity<Args...>,
// - Continuation: continuation<[](auto&& callback) { callback("hi"); }>
// - Callback: [](std::string) { }
// - NextCallback: []() { }
auto proxy = callbacks::make_callback<traits::identity<Args...>,
HandleResults, HandleErrors>(
auto proxy = callbacks::make_callback<identity<Args...>, HandleResults,
HandleErrors>(
std::move(callback_), std::move(executor_),
std::forward<decltype(next_callback)>(next_callback));
@ -791,9 +780,9 @@ struct chained_continuation<traits::identity<Args...>,
// Specialization to unpack ready continuables directly
template <typename... Args, typename... NextArgs, handle_results HandleResults,
handle_errors HandleErrors, typename Callback, typename Executor>
struct chained_continuation<
traits::identity<Args...>, traits::identity<NextArgs...>, HandleResults,
HandleErrors, ready_continuation<Args...>, Callback, Executor> {
struct chained_continuation<identity<Args...>, identity<NextArgs...>,
HandleResults, HandleErrors,
ready_continuation<Args...>, Callback, Executor> {
ready_continuation<Args...> continuation_;
Callback callback_;
@ -814,8 +803,8 @@ struct chained_continuation<
template <typename NextCallback>
void operator()(NextCallback&& next_callback) {
auto proxy = callbacks::make_callback<traits::identity<Args...>,
HandleResults, HandleErrors>(
auto proxy = callbacks::make_callback<identity<Args...>, HandleResults,
HandleErrors>(
std::move(callback_), std::move(executor_),
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>>{},
"Expected a continuation!");
using Hint = decltype(base::annotation_of(traits::identify<Continuation>()));
using Hint = decltype(base::annotation_of(identify<Continuation>()));
constexpr auto next_hint =
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 data =
@ -875,7 +864,7 @@ auto chain_continuation(Continuation&& continuation, Callback&& callback,
/// - Continuation: continuation<[](auto&& callback) { callback("hi"); }>
template <typename Data, typename... Args>
void finalize_continuation(
continuable_base<Data, traits::identity<Args...>>&& continuation) noexcept {
continuable_base<Data, identity<Args...>>&& continuation) noexcept {
#ifdef CONTINUABLE_WITH_CUSTOM_FINAL_CALLBACK
invoke_continuation(std::move(continuation),
CONTINUABLE_WITH_CUSTOM_FINAL_CALLBACK<Args...>{});
@ -890,13 +879,12 @@ void finalize_continuation(
template <typename Data, typename Annotation, typename Continuation>
struct can_accept_continuation : std::false_type {};
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::is_invocable<Continuation,
callbacks::final_callback<Args...>>,
std::is_convertible<
proxy_continuable<traits::identity<Args...>, Continuation>,
Data>> {};
proxy_continuable<identity<Args...>, Continuation>, Data>> {};
/// Workaround for GCC bug:
/// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64095

View File

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

View File

@ -106,6 +106,18 @@
#else
#undef CONTINUABLE_HAS_EXCEPTIONS
#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
#endif // CONTINUABLE_DETAIL_FEATURES_HPP_INCLUDED

View File

@ -57,7 +57,7 @@ using std::experimental::coroutine_handle;
template <typename T>
struct result_from_identity;
template <typename... T>
struct result_from_identity<traits::identity<T...>> {
struct result_from_identity<identity<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.
template <typename Continuable>
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;
/// 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 {
template <typename... Actual>
void operator()(Actual...) {
static_assert(std::is_same<traits::identity<Actual...>,
traits::identity<Expected...>>::value,
static_assert(std::is_same<identity<Actual...>,
identity<Expected...>>::value,
"The called arguments don't match with the expected ones!");
}
};
template <typename C, typename... Args>
void assert_async_types(C&& continuable,
traits::identity<Args...> /*expected*/) {
identity<Args...> /*expected*/) {
assert_async_validation(std::forward<C>(continuable),
assert_async_types_validator<Args...>{});
}

View File

@ -77,7 +77,7 @@ template <typename Hint>
class promise_callback;
template <typename... Args>
class promise_callback<traits::identity<Args...>>
class promise_callback<identity<Args...>>
: public future_trait<Args...> {
typename future_trait<Args...>::promise_t promise_;
@ -119,7 +119,7 @@ template <typename Data, typename Annotation>
auto as_future(continuable_base<Data, Annotation>&& continuable) {
// Create the promise which is able to supply the current arguments
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;
(void)hint;

View File

@ -62,7 +62,7 @@ template <typename T>
using align_of_helper = std::integral_constant<std::size_t, alignof(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 align = max_element_of({(align_of_helper<T>::value)...});
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
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
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 <utility>
#include <continuable/detail/features.hpp>
#include <continuable/detail/utility/identity.hpp>
namespace cti {
namespace detail {
@ -69,19 +70,6 @@ auto make_flat_tuple(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)
using std::void_t;
#else

View File

@ -17,9 +17,11 @@ target_link_libraries(test-continuable-base
add_executable(test-continuable-single
${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-result.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-async.cpp)

View File

@ -134,7 +134,7 @@ TYPED_TEST(single_dimension_tests, are_exceptions_partial_applyable) {
handled = false;
ASSERT_ASYNC_INCOMPLETION(
this->supply_exception(supply_test_exception(),
detail::traits::identity<int, int>{})
detail::identity<int, int>{})
.fail([&]() -> result<int, int> {
EXPECT_FALSE(handled);
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.hpp>
using cti::detail::traits::identity;
using cti::detail::identity;
using cti::detail::util::unused;
inline auto to_hint(identity<> /*hint*/) {
@ -48,7 +48,7 @@ auto to_hint(identity<Args...> hint) {
template <typename... Args>
auto supplier_of(Args&&... args) {
return [values = std::make_tuple(std::forward<Args>(args)...)](
auto&& promise) mutable {
auto&& promise) mutable {
cti::detail::traits::unpack(
[&](auto&&... passed) {
promise.set_value(std::forward<decltype(passed)>(passed)...);
@ -113,12 +113,12 @@ struct provide_copyable {
struct provide_unique {
template <typename... Args, typename... Hint, typename T>
auto make(identity<Args...>, identity<Hint...>, T&& callback) {
return cti::make_continuable<Hint...>(
[callback = std::forward<T>(callback),
guard = std::make_unique<int>(0)](auto&&... args) mutable {
(void)(*guard);
return std::move(callback)(std::forward<decltype(args)>(args)...);
});
return cti::make_continuable<Hint...>([
callback = std::forward<T>(callback), guard = std::make_unique<int>(0)
](auto&&... args) mutable {
(void)(*guard);
return std::move(callback)(std::forward<decltype(args)>(args)...);
});
}
};

View File

@ -56,7 +56,7 @@ function renew_build {
# 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" \
-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