mirror of
https://github.com/Naios/continuable.git
synced 2025-12-06 08:46:44 +08:00
Fix a materialization error on futurization
* Add more documentation and tests
This commit is contained in:
parent
4448eb7351
commit
43a2c47a91
@ -4,7 +4,7 @@ This documentation covers the continuable library in detail
|
||||
|
||||
## Content
|
||||
|
||||
- Class cti::continuable_base - main class for continuation chaining
|
||||
- Class cti::continuable_base - main class for continuation chaining.
|
||||
- \link cti::continuable_base::then then\endlink - adds a callback or cti::continuable_base to the invocation chain.
|
||||
- \link cti::continuable_base::operator && operator&&\endlink - connects another cti::continuable_base with an *all* logic.
|
||||
- \link cti::continuable_base::operator|| operator||\endlink - connects another cti::continuable_base with an *any* logic.
|
||||
@ -13,4 +13,8 @@ This documentation covers the continuable library in detail
|
||||
- \link cti::make_continuable make_continuable\endlink - creates a cti::continuable_base from a callback tanking function.
|
||||
- \link cti::all_of all_of\endlink - connects all given cti::continuable_base objects with an *all* logic.
|
||||
- \link cti::any_of any_of\endlink - connects all given cti::continuable_base objects with an *any* logic.
|
||||
- GTest macros:
|
||||
- \link EXPECT_ASYNC_RESULT EXPECT_ASYNC_RESULT\endlink - Expects that the given continuable is finished with the given result.
|
||||
- \link ASSERT_ASYNC_RESULT ASSERT_ASYNC_RESULT\endlink - Asserts that the given continuable is finished with the given result.
|
||||
- \link ASSERT_ASYNC_TYPES ASSERT_ASYNC_TYPES\endlink - Asserts that the given continuable is finished with the given types without validating it against equality.
|
||||
|
||||
|
||||
@ -47,6 +47,7 @@ namespace detail {
|
||||
/// Utility namespace which provides useful meta-programming support
|
||||
namespace util {
|
||||
|
||||
/// \cond false
|
||||
#define CTI__FOR_EACH_BOOLEAN_BIN_OP(CTI__OP__) \
|
||||
CTI__OP__(==) \
|
||||
CTI__OP__(!=) CTI__OP__(<=) CTI__OP__(>=) CTI__OP__(<) CTI__OP__(>)
|
||||
@ -56,9 +57,11 @@ namespace util {
|
||||
CTI__OP__(/) CTI__OP__(+) CTI__OP__(-) CTI__FOR_EACH_BOOLEAN_BIN_OP(CTI__OP__)
|
||||
#define CTI__FOR_EACH_INTEGRAL_UNA_OP(CTI__OP__) \
|
||||
CTI__OP__(~) CTI__FOR_EACH_BOOLEAN_UNA_OP(CTI__OP__)
|
||||
/// \endcond
|
||||
|
||||
template <typename T, T Value>
|
||||
struct constant : std::integral_constant<T, Value> {
|
||||
/// \cond false
|
||||
#define CTI__INST(CTI__OP) \
|
||||
template <typename OT, OT OValue> \
|
||||
/*constexpr*/ auto operator CTI__OP(std::integral_constant<OT, OValue>) \
|
||||
@ -74,10 +77,12 @@ struct constant : std::integral_constant<T, Value> {
|
||||
}
|
||||
CTI__FOR_EACH_INTEGRAL_UNA_OP(CTI__INST)
|
||||
#undef CTI__INST
|
||||
/// \endcond
|
||||
};
|
||||
|
||||
template <bool Value>
|
||||
struct constant<bool, Value> : std::integral_constant<bool, Value> {
|
||||
/// \cond false
|
||||
#define CTI__INST(CTI__OP) \
|
||||
template <typename OT, OT OValue> \
|
||||
/*constexpr*/ auto operator CTI__OP(std::integral_constant<bool, OValue>) \
|
||||
@ -92,6 +97,7 @@ struct constant<bool, Value> : std::integral_constant<bool, Value> {
|
||||
}
|
||||
CTI__FOR_EACH_BOOLEAN_UNA_OP(CTI__INST)
|
||||
#undef CTI__INST
|
||||
/// \endcond
|
||||
};
|
||||
|
||||
template <bool Value> using bool_constant = constant<bool, Value>;
|
||||
@ -277,19 +283,6 @@ auto static_while(Value&& value, Predicate&& predicate, Handler&& handler) {
|
||||
});
|
||||
}
|
||||
|
||||
/// Iterates from the begin to the end, the handler is invoked
|
||||
/// with a constant representing the current position.
|
||||
/// The handler shall return a constant representing the next position.
|
||||
// template <std::size_t Begin, std::size_t End, typename Handler>
|
||||
// void static_for(size_constant<Begin> begin, size_constant<End> end, Handler&&
|
||||
// handler) {
|
||||
// auto delta = begin - end;
|
||||
// static_for_each_in(std::make_index_sequence<delta.value>{}, [&](auto pos)
|
||||
// mutable {
|
||||
// handler(pos + begin);
|
||||
// });
|
||||
//}
|
||||
|
||||
/// Returns a validator which checks whether the given sequenceable is empty
|
||||
inline auto is_empty() {
|
||||
return [](auto const& checkable) {
|
||||
@ -966,13 +959,6 @@ private:
|
||||
};
|
||||
} // end namespace detail
|
||||
|
||||
/// Adds the given continuation to the left composition
|
||||
/*template <typename... LeftArgs, typename Continuation>
|
||||
auto chain_composition(std::tuple<LeftArgs...> leftPack,
|
||||
Continuation&& continuation) {
|
||||
return util::push(std::move(leftPack),
|
||||
std::forward<Continuation>(continuation));
|
||||
}*/
|
||||
/// Adds the given continuation tuple to the left composition
|
||||
template <typename... LeftArgs, typename... RightArgs>
|
||||
auto chain_composition(std::tuple<LeftArgs...> leftPack,
|
||||
@ -1304,7 +1290,9 @@ public:
|
||||
std::move(*this), std::move(right));
|
||||
}
|
||||
|
||||
auto futurize() && { return detail::transforms::as_future(std::move(*this)); }
|
||||
auto futurize() && {
|
||||
return detail::transforms::as_future(std::move(*this).materialize());
|
||||
}
|
||||
|
||||
void done() && {
|
||||
assert(ownership_.has_ownership() &&
|
||||
|
||||
@ -58,8 +58,8 @@ void expect_async_validation(C&& continuable, V&& validator) {
|
||||
}
|
||||
|
||||
/// Expects that the continuable is finished with the given arguments
|
||||
template <typename C, typename V, typename... Args>
|
||||
void expect_async_binary_validation(C&& continuable, V&& validator,
|
||||
template <typename V, typename C, typename... Args>
|
||||
void expect_async_binary_validation(V&& validator, C&& continuable,
|
||||
Args&&... expected) {
|
||||
expect_async_validation(std::forward<C>(continuable), [
|
||||
expected_pack = std::make_tuple(std::forward<Args>(expected)...),
|
||||
@ -85,16 +85,16 @@ void expect_async_binary_validation(C&& continuable, V&& validator,
|
||||
});
|
||||
}
|
||||
|
||||
template <typename C, typename... Args>
|
||||
void expect_async_result(C&& continuable, Args&&... expected) {
|
||||
expect_async_binary_validation(
|
||||
std::forward<C>(continuable),
|
||||
[](auto&& expected, auto&& actual) { EXPECT_EQ(expected, actual); },
|
||||
std::forward<Args>(expected)...);
|
||||
inline auto expecting_eq_check() {
|
||||
return [](auto expected, auto actual) { EXPECT_EQ(expected, actual); };
|
||||
}
|
||||
|
||||
inline auto asserting_eq_check() {
|
||||
return [](auto expected, auto actual) { ASSERT_EQ(expected, actual); };
|
||||
}
|
||||
|
||||
template <typename C, typename... Args>
|
||||
void expect_async_types(C&& continuable, util::identity<Args...> expected) {
|
||||
void assert_async_types(C&& continuable, util::identity<Args...> expected) {
|
||||
expect_async_validation(
|
||||
std::forward<C>(continuable), [&](auto... actualPack) {
|
||||
auto actual = util::identity<decltype(actualPack)...>{};
|
||||
@ -116,6 +116,8 @@ void expect_async_types(C&& continuable, util::identity<Args...> expected) {
|
||||
|
||||
/// Expects the final callback of the given continuable to be called
|
||||
/// with any result.
|
||||
///
|
||||
/// \since version 1.0.0
|
||||
#define EXPECT_ASYNC_COMPLETION(CONTINUABLE) \
|
||||
cti::detail::testing::expect_async_completion(CONTINUABLE);
|
||||
|
||||
@ -125,25 +127,79 @@ void expect_async_types(C&& continuable, util::identity<Args...> expected) {
|
||||
cti::detail::testing::expect_async_validation(CONTINUABLE, VALIDATOR);
|
||||
|
||||
/// Expects the continuation to be called and forwards it's arguments to
|
||||
/// the given validator which can then do assertions on the result:
|
||||
/// the given validator which can then do assertions on the result.
|
||||
///
|
||||
/// auto validator = [](auto expected, auto actual) {
|
||||
/// // ...
|
||||
/// };
|
||||
/// A validator consists of a binary consumer with a signature as in
|
||||
/// in the example shown below:
|
||||
/// ```cpp
|
||||
/// auto validator = [](auto expected, auto actual) {
|
||||
/// EXPECT_EQ(expected, actual);
|
||||
/// };
|
||||
/// ```
|
||||
///
|
||||
/// The macro is usable as shown in the following example:
|
||||
/// ```cpp
|
||||
/// continuable<string> async_get(std::string);
|
||||
/// // ...
|
||||
/// auto validator = [](auto expected, auto actual) {
|
||||
/// EXPECT_EQ(expected, actual);
|
||||
/// };
|
||||
///
|
||||
/// EXPECT_ASYNC_BINARY_VALIDATION(validator, async_get("hello"), "hello")
|
||||
/// ```
|
||||
///
|
||||
/// The validator is called for every expecting and actual result.
|
||||
#define EXPECT_ASYNC_BINARY_VALIDATION(CONTINUABLE, ...) \
|
||||
cti::detail::testing::expect_async_binary_validation(CONTINUABLE, \
|
||||
__VA_ARGS__);
|
||||
///
|
||||
/// \note This macro is mainly present for building other assertions
|
||||
/// relying on custom validation logic.
|
||||
///
|
||||
/// \since version 1.0.0
|
||||
#define EXPECT_ASYNC_BINARY_VALIDATION(VALIDATOR, ...) \
|
||||
cti::detail::testing::expect_async_binary_validation(VALIDATOR, __VA_ARGS__);
|
||||
|
||||
/// Expects that the continuable is finished with the given result
|
||||
///
|
||||
/// ```cpp
|
||||
/// continuable<string> async_get(std::string);
|
||||
/// // ...
|
||||
///
|
||||
/// EXPECT_ASYNC_RESULT(async_get("hello"), "hello");
|
||||
/// ```
|
||||
///
|
||||
/// \since version 1.0.0
|
||||
#define EXPECT_ASYNC_RESULT(...) \
|
||||
cti::detail::testing::expect_async_result(__VA_ARGS__);
|
||||
EXPECT_ASYNC_BINARY_VALIDATION(cti::detail::testing::expecting_eq_check(), \
|
||||
__VA_ARGS__)
|
||||
|
||||
/// Expects that the continuable is finished with the given type of arguments
|
||||
/// Asserts that the continuable is finished with the given result
|
||||
///
|
||||
/// ```cpp
|
||||
/// continuable<string> async_get(std::string);
|
||||
/// // ...
|
||||
///
|
||||
/// ASSERT_ASYNC_RESULT(async_get("hello"), "hello");
|
||||
/// ```
|
||||
///
|
||||
/// \since version 1.0.0
|
||||
#define ASSERT_ASYNC_RESULT(...) \
|
||||
EXPECT_ASYNC_BINARY_VALIDATION(cti::detail::testing::asserting_eq_check(), \
|
||||
__VA_ARGS__)
|
||||
|
||||
/// Asserts that the continuable is finished with the given type of arguments
|
||||
/// without validating it against equality.
|
||||
#define EXPECT_ASYNC_TYPES(CONTINUABLE, ...) \
|
||||
cti::detail::testing::expect_async_types( \
|
||||
///
|
||||
/// ```cpp
|
||||
/// continuable<string> async_get(std::string);
|
||||
/// // ...
|
||||
///
|
||||
/// ASSERT_ASYNC_TYPES(async_get("hello"), std::string);
|
||||
/// ```
|
||||
///
|
||||
/// \note This is a compile-time assertion.
|
||||
///
|
||||
/// \since version 1.0.0
|
||||
#define ASSERT_ASYNC_TYPES(CONTINUABLE, ...) \
|
||||
cti::detail::testing::assert_async_types( \
|
||||
CONTINUABLE, cti::detail::util::identity<__VA_ARGS__>{})
|
||||
|
||||
#endif // CONTINUABLE_TESTING_HPP_INCLUDED__
|
||||
|
||||
@ -5,7 +5,7 @@ add_executable(test-continuable
|
||||
${CMAKE_CURRENT_LIST_DIR}/test-continuable.hpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/test-continuable-base.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/test-continuable-connection.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/test-continuable-transforms.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/test-continuable-erasure.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/test-continuable-recursion.cpp)
|
||||
|
||||
target_link_libraries(test-continuable
|
||||
|
||||
@ -42,7 +42,7 @@ TYPED_TEST(single_dimension_tests, are_supplyd_on_destruct) {
|
||||
|
||||
EXPECT_ASYNC_RESULT(this->supply(0xDA), 0xDA);
|
||||
|
||||
EXPECT_ASYNC_TYPES(this->supply(tag1{}), tag1);
|
||||
ASSERT_ASYNC_TYPES(this->supply(tag1{}), tag1);
|
||||
}
|
||||
|
||||
TYPED_TEST(single_dimension_tests, are_chainable) {
|
||||
@ -53,7 +53,7 @@ TYPED_TEST(single_dimension_tests, are_chainable) {
|
||||
// Type chain
|
||||
{
|
||||
auto chain = this->supply().then([] { return tag1{}; });
|
||||
EXPECT_ASYNC_TYPES(std::move(chain), tag1);
|
||||
ASSERT_ASYNC_TYPES(std::move(chain), tag1);
|
||||
}
|
||||
|
||||
// Pair chain
|
||||
@ -62,7 +62,7 @@ TYPED_TEST(single_dimension_tests, are_chainable) {
|
||||
// ...
|
||||
return std::make_pair(tag1{}, tag2{});
|
||||
});
|
||||
EXPECT_ASYNC_TYPES(std::move(chain), tag1, tag2);
|
||||
ASSERT_ASYNC_TYPES(std::move(chain), tag1, tag2);
|
||||
}
|
||||
|
||||
// Tuple chain
|
||||
@ -71,20 +71,20 @@ TYPED_TEST(single_dimension_tests, are_chainable) {
|
||||
// ...
|
||||
return std::make_tuple(tag1{}, tag2{}, tag3{});
|
||||
});
|
||||
EXPECT_ASYNC_TYPES(std::move(chain), tag1, tag2, tag3);
|
||||
ASSERT_ASYNC_TYPES(std::move(chain), tag1, tag2, tag3);
|
||||
}
|
||||
|
||||
// Erasing chain
|
||||
{
|
||||
auto chain = this->supply().then(this->supply(tag1{}));
|
||||
EXPECT_ASYNC_TYPES(std::move(chain), tag1);
|
||||
ASSERT_ASYNC_TYPES(std::move(chain), tag1);
|
||||
}
|
||||
|
||||
// Continuing chain
|
||||
{
|
||||
auto chain = this->supply().then([&] { return this->supply(tag1{}); });
|
||||
|
||||
EXPECT_ASYNC_TYPES(std::move(chain), tag1);
|
||||
ASSERT_ASYNC_TYPES(std::move(chain), tag1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -23,6 +23,13 @@
|
||||
|
||||
#include "test-continuable.hpp"
|
||||
|
||||
template <typename T> auto make_step(T* me, unsigned& current, unsigned step) {
|
||||
return me->invoke([=]() mutable {
|
||||
ASSERT_EQ(step, current);
|
||||
++current;
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST(single_dimension_tests, is_logical_and_connectable) {
|
||||
|
||||
{
|
||||
@ -42,8 +49,16 @@ TYPED_TEST(single_dimension_tests, is_logical_and_connectable) {
|
||||
|
||||
{
|
||||
auto chain = this->supply(tag1{}) && this->supply(tag2{}, tag3{});
|
||||
EXPECT_ASYNC_TYPES(std::move(chain), tag1, tag2, tag3);
|
||||
ASSERT_ASYNC_TYPES(std::move(chain), tag1, tag2, tag3);
|
||||
}
|
||||
|
||||
/*{
|
||||
// Check the evaluation order
|
||||
unsigned i = 0;
|
||||
auto composed =
|
||||
make_step(this, i, 0) && make_step(this, i, 1) && make_step(this, i, 2);
|
||||
EXPECT_ASYNC_RESULT(std::move(composed));
|
||||
}*/
|
||||
}
|
||||
|
||||
TYPED_TEST(single_dimension_tests, is_logical_or_connectable) {
|
||||
@ -65,18 +80,18 @@ TYPED_TEST(single_dimension_tests, is_logical_or_connectable) {
|
||||
|
||||
{
|
||||
auto chain = this->supply(tag1{}, tag2{}) || this->supply(tag1{}, tag2{});
|
||||
EXPECT_ASYNC_TYPES(std::move(chain), tag1, tag2);
|
||||
ASSERT_ASYNC_TYPES(std::move(chain), tag1, tag2);
|
||||
}
|
||||
|
||||
{
|
||||
auto chain = this->supply(tag1{}, tag2{}, tag3{}) ||
|
||||
this->supply(tag1{}, tag2{}, tag3{});
|
||||
EXPECT_ASYNC_TYPES(std::move(chain), tag1, tag2, tag3);
|
||||
ASSERT_ASYNC_TYPES(std::move(chain), tag1, tag2, tag3);
|
||||
}
|
||||
|
||||
{
|
||||
using common = std::common_type_t<char, int>;
|
||||
auto chain = this->supply(char(0), int(0)) || this->supply(int(0), char(0));
|
||||
EXPECT_ASYNC_TYPES(std::move(chain), common, common);
|
||||
ASSERT_ASYNC_TYPES(std::move(chain), common, common);
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,12 +23,18 @@
|
||||
|
||||
#include "test-continuable.hpp"
|
||||
|
||||
using namespace cti;
|
||||
TYPED_TEST(single_dimension_tests, is_eraseable) {
|
||||
|
||||
TEST(ContinuableErasureTests, FunctionsAreUnwrappable) {
|
||||
// ...
|
||||
{
|
||||
cti::unique_continuable<int> erasure =
|
||||
cti::make_continuable(supplier_of(0xDF));
|
||||
|
||||
// continuable<int> ss = supply(0);
|
||||
EXPECT_ASYNC_RESULT(std::move(erasure), 0xDF);
|
||||
}
|
||||
|
||||
// auto itm = std::move(ss).then(supply(2));
|
||||
{
|
||||
cti::unique_continuable<int> erasure = this->supply(0xDF);
|
||||
|
||||
EXPECT_ASYNC_RESULT(std::move(erasure), 0xDF);
|
||||
}
|
||||
}
|
||||
@ -31,26 +31,40 @@
|
||||
#include "continuable/continuable.hpp"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
using cti::detail::util::identity;
|
||||
|
||||
inline auto to_hint(identity<> /*hint*/) { return identity<void>{}; }
|
||||
template <typename... Args> auto to_hint(identity<Args...> hint) {
|
||||
return hint;
|
||||
}
|
||||
|
||||
template <typename... Args> auto supplier_of(Args&&... args) {
|
||||
return [values = std::make_tuple(std::forward<Args>(args)...)](
|
||||
auto&& callback) mutable {
|
||||
cti::detail::util::unpack(std::move(values), [&](auto&&... passed) {
|
||||
// ...
|
||||
std::forward<decltype(callback)>(callback)(
|
||||
std::forward<decltype(passed)>(passed)...);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
template <typename Provider>
|
||||
class continuation_provider : public ::testing::Test, public Provider {
|
||||
public:
|
||||
auto supply() {
|
||||
return this->makeVoid([](auto&& callback) mutable {
|
||||
// ...
|
||||
std::forward<decltype(callback)>(callback)();
|
||||
});
|
||||
};
|
||||
template <typename T> auto invoke(T&& type) {
|
||||
return this->make(identity<>{}, identity<void>{},
|
||||
[type = std::forward<T>(type)](auto&& callback) mutable {
|
||||
std::forward<decltype(callback)>(callback)();
|
||||
});
|
||||
}
|
||||
|
||||
template <typename... Args> auto supply(Args&&... args) {
|
||||
return this->template make<std::decay_t<Args>...>([values = std::make_tuple(
|
||||
std::forward<Args>(
|
||||
args)...)](
|
||||
auto&& callback) mutable {
|
||||
cti::detail::util::unpack(std::move(values), [&](auto&&... passed) {
|
||||
// ...
|
||||
std::forward<decltype(callback)>(callback)(
|
||||
std::forward<decltype(passed)>(passed)...);
|
||||
});
|
||||
});
|
||||
identity<std::decay_t<Args>...> arg_types;
|
||||
auto hint_types = to_hint(arg_types);
|
||||
|
||||
return this->make(arg_types, hint_types,
|
||||
supplier_of(std::forward<Args>(args)...));
|
||||
}
|
||||
};
|
||||
|
||||
@ -61,21 +75,21 @@ inline auto empty_caller() {
|
||||
};
|
||||
}
|
||||
|
||||
inline auto empty_continuable() {
|
||||
return cti::make_continuable<void>(empty_caller());
|
||||
}
|
||||
|
||||
struct provide_copyable {
|
||||
template <typename T> auto makeVoid(T&& callback) {
|
||||
return make<void>(std::forward<T>(callback));
|
||||
}
|
||||
template <typename... Args, typename T> auto make(T&& callback) {
|
||||
return cti::make_continuable<Args...>(std::forward<T>(callback));
|
||||
template <typename... Args, typename... Hint, typename T>
|
||||
auto make(identity<Args...>, identity<Hint...>, T&& callback) {
|
||||
return cti::make_continuable<Hint...>(std::forward<T>(callback));
|
||||
}
|
||||
};
|
||||
|
||||
struct provide_unique {
|
||||
template <typename T> auto makeVoid(T&& callback) {
|
||||
return make<void>(std::forward<T>(callback));
|
||||
}
|
||||
template <typename... Args, typename T> auto make(T&& callback) {
|
||||
return cti::make_continuable<Args...>([
|
||||
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);
|
||||
@ -85,68 +99,59 @@ struct provide_unique {
|
||||
};
|
||||
|
||||
struct provide_copyable_erasure {
|
||||
template <typename T> auto makeVoid(T&& callback) {
|
||||
return make(std::forward<T>(callback));
|
||||
}
|
||||
template <typename... Args, typename T>
|
||||
cti::continuable<Args...> make(T&& callback) {
|
||||
return cti::make_continuable(std::forward<T>(callback));
|
||||
template <typename... Args, typename... Hint, typename T>
|
||||
cti::continuable<Args...> make(identity<Args...>, identity<Hint...>,
|
||||
T&& callback) {
|
||||
return cti::make_continuable<Hint...>(std::forward<T>(callback));
|
||||
}
|
||||
};
|
||||
|
||||
struct provide_unique_erasure {
|
||||
template <typename T> auto makeVoid(T&& callback) {
|
||||
return make(std::forward<T>(callback));
|
||||
}
|
||||
template <typename... Args, typename T>
|
||||
cti::unique_continuable<Args...> make(T&& callback) {
|
||||
return cti::make_continuable(std::forward<T>(callback));
|
||||
template <typename... Args, typename... Hint, typename T>
|
||||
cti::unique_continuable<Args...> make(identity<Args...>, identity<Hint...>,
|
||||
T&& callback) {
|
||||
return cti::make_continuable<Hint...>(std::forward<T>(callback));
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
template <typename Left, typename Right> struct provide_continuation_or_left {
|
||||
Left left_;
|
||||
Right right_;
|
||||
template <typename Provider> struct provide_continuation_and_left {
|
||||
Provider provider_;
|
||||
|
||||
template <typename T> auto makeVoid(T&& callback) {
|
||||
return left_.template make<void>(std::forward<T>(callback)) ||
|
||||
right_.template make<void>(empty_caller());
|
||||
}
|
||||
template <typename... Args, typename T> auto make(T&& callback) {
|
||||
return left_.template make<Args...>(std::forward<T>(callback)) ||
|
||||
right_.template make<void>(empty_caller());
|
||||
template <typename... Args, typename... Hint, typename T>
|
||||
auto make(identity<Args...> args, identity<Hint...> hint, T&& callback) {
|
||||
return empty_continuable() &&
|
||||
provider_.make(args, hint, std::forward<T>(callback));
|
||||
}
|
||||
};
|
||||
*/
|
||||
|
||||
template <typename... Args> struct type_chainer {
|
||||
template <typename First> auto add() {
|
||||
return type_chainer<Args..., First>{};
|
||||
}
|
||||
template <template <typename> class T, typename First> auto add() {
|
||||
return type_chainer<Args..., T<First>>{};
|
||||
}
|
||||
template <template <typename, typename> class T, typename First,
|
||||
typename Second>
|
||||
auto add() {
|
||||
return type_chainer<Args..., T<First, Second>, T<First, Second>,
|
||||
T<Second, First>, T<Second, Second>>{};
|
||||
}
|
||||
template <typename Provider> struct provide_continuation_and_right {
|
||||
Provider provider_;
|
||||
|
||||
using type = testing::Types<Args...>;
|
||||
template <typename... Args, typename... Hint, typename T>
|
||||
auto make(identity<Args...> args, identity<Hint...> hint, T&& callback) {
|
||||
return provider_.make(args, hint, std::forward<T>(callback)) &&
|
||||
empty_continuable();
|
||||
}
|
||||
};
|
||||
|
||||
inline auto make_type() {
|
||||
type_chainer<> chainer{};
|
||||
return chainer // ...
|
||||
.add<provide_copyable>()
|
||||
.add<provide_unique>()
|
||||
.add<provide_copyable_erasure>()
|
||||
.add<provide_unique_erasure>();
|
||||
}
|
||||
|
||||
using single_types = decltype(make_type())::type;
|
||||
// clang-format off
|
||||
using single_types = ::testing::Types<
|
||||
provide_copyable,
|
||||
provide_unique,
|
||||
provide_copyable_erasure,
|
||||
provide_unique_erasure,
|
||||
// Some instantiations out commented for compilation speed reasons
|
||||
// provide_continuation_and_left<provide_copyable>,
|
||||
provide_continuation_and_left<provide_unique>,
|
||||
// provide_continuation_and_left<provide_copyable_erasure>,
|
||||
// provide_continuation_and_left<provide_unique_erasure>,
|
||||
// Some instantiations out commented for compilation speed reasons
|
||||
// provide_continuation_and_right<provide_copyable>,
|
||||
provide_continuation_and_right<provide_unique>
|
||||
// provide_continuation_and_left<provide_copyable_erasure>,
|
||||
// provide_continuation_and_left<provide_unique_erasure>
|
||||
>;
|
||||
// clang-format on
|
||||
|
||||
struct tag1 {};
|
||||
struct tag2 {};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user