mirror of
https://github.com/Naios/continuable.git
synced 2025-12-07 01:06: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
|
## 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::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 *all* logic.
|
||||||
- \link cti::continuable_base::operator|| operator||\endlink - connects another cti::continuable_base with an *any* 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::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::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.
|
- \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
|
/// Utility namespace which provides useful meta-programming support
|
||||||
namespace util {
|
namespace util {
|
||||||
|
|
||||||
|
/// \cond false
|
||||||
#define CTI__FOR_EACH_BOOLEAN_BIN_OP(CTI__OP__) \
|
#define CTI__FOR_EACH_BOOLEAN_BIN_OP(CTI__OP__) \
|
||||||
CTI__OP__(==) \
|
CTI__OP__(==) \
|
||||||
CTI__OP__(!=) CTI__OP__(<=) CTI__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__)
|
CTI__OP__(/) CTI__OP__(+) CTI__OP__(-) CTI__FOR_EACH_BOOLEAN_BIN_OP(CTI__OP__)
|
||||||
#define CTI__FOR_EACH_INTEGRAL_UNA_OP(CTI__OP__) \
|
#define CTI__FOR_EACH_INTEGRAL_UNA_OP(CTI__OP__) \
|
||||||
CTI__OP__(~) CTI__FOR_EACH_BOOLEAN_UNA_OP(CTI__OP__)
|
CTI__OP__(~) CTI__FOR_EACH_BOOLEAN_UNA_OP(CTI__OP__)
|
||||||
|
/// \endcond
|
||||||
|
|
||||||
template <typename T, T Value>
|
template <typename T, T Value>
|
||||||
struct constant : std::integral_constant<T, Value> {
|
struct constant : std::integral_constant<T, Value> {
|
||||||
|
/// \cond false
|
||||||
#define CTI__INST(CTI__OP) \
|
#define CTI__INST(CTI__OP) \
|
||||||
template <typename OT, OT OValue> \
|
template <typename OT, OT OValue> \
|
||||||
/*constexpr*/ auto operator CTI__OP(std::integral_constant<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)
|
CTI__FOR_EACH_INTEGRAL_UNA_OP(CTI__INST)
|
||||||
#undef CTI__INST
|
#undef CTI__INST
|
||||||
|
/// \endcond
|
||||||
};
|
};
|
||||||
|
|
||||||
template <bool Value>
|
template <bool Value>
|
||||||
struct constant<bool, Value> : std::integral_constant<bool, Value> {
|
struct constant<bool, Value> : std::integral_constant<bool, Value> {
|
||||||
|
/// \cond false
|
||||||
#define CTI__INST(CTI__OP) \
|
#define CTI__INST(CTI__OP) \
|
||||||
template <typename OT, OT OValue> \
|
template <typename OT, OT OValue> \
|
||||||
/*constexpr*/ auto operator CTI__OP(std::integral_constant<bool, 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)
|
CTI__FOR_EACH_BOOLEAN_UNA_OP(CTI__INST)
|
||||||
#undef CTI__INST
|
#undef CTI__INST
|
||||||
|
/// \endcond
|
||||||
};
|
};
|
||||||
|
|
||||||
template <bool Value> using bool_constant = constant<bool, Value>;
|
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
|
/// Returns a validator which checks whether the given sequenceable is empty
|
||||||
inline auto is_empty() {
|
inline auto is_empty() {
|
||||||
return [](auto const& checkable) {
|
return [](auto const& checkable) {
|
||||||
@ -966,13 +959,6 @@ private:
|
|||||||
};
|
};
|
||||||
} // end namespace detail
|
} // 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
|
/// Adds the given continuation tuple to the left composition
|
||||||
template <typename... LeftArgs, typename... RightArgs>
|
template <typename... LeftArgs, typename... RightArgs>
|
||||||
auto chain_composition(std::tuple<LeftArgs...> leftPack,
|
auto chain_composition(std::tuple<LeftArgs...> leftPack,
|
||||||
@ -1304,7 +1290,9 @@ public:
|
|||||||
std::move(*this), std::move(right));
|
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() && {
|
void done() && {
|
||||||
assert(ownership_.has_ownership() &&
|
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
|
/// Expects that the continuable is finished with the given arguments
|
||||||
template <typename C, typename V, typename... Args>
|
template <typename V, typename C, typename... Args>
|
||||||
void expect_async_binary_validation(C&& continuable, V&& validator,
|
void expect_async_binary_validation(V&& validator, C&& continuable,
|
||||||
Args&&... expected) {
|
Args&&... expected) {
|
||||||
expect_async_validation(std::forward<C>(continuable), [
|
expect_async_validation(std::forward<C>(continuable), [
|
||||||
expected_pack = std::make_tuple(std::forward<Args>(expected)...),
|
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>
|
inline auto expecting_eq_check() {
|
||||||
void expect_async_result(C&& continuable, Args&&... expected) {
|
return [](auto expected, auto actual) { EXPECT_EQ(expected, actual); };
|
||||||
expect_async_binary_validation(
|
}
|
||||||
std::forward<C>(continuable),
|
|
||||||
[](auto&& expected, auto&& actual) { EXPECT_EQ(expected, actual); },
|
inline auto asserting_eq_check() {
|
||||||
std::forward<Args>(expected)...);
|
return [](auto expected, auto actual) { ASSERT_EQ(expected, actual); };
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename C, typename... Args>
|
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(
|
expect_async_validation(
|
||||||
std::forward<C>(continuable), [&](auto... actualPack) {
|
std::forward<C>(continuable), [&](auto... actualPack) {
|
||||||
auto actual = util::identity<decltype(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
|
/// Expects the final callback of the given continuable to be called
|
||||||
/// with any result.
|
/// with any result.
|
||||||
|
///
|
||||||
|
/// \since version 1.0.0
|
||||||
#define EXPECT_ASYNC_COMPLETION(CONTINUABLE) \
|
#define EXPECT_ASYNC_COMPLETION(CONTINUABLE) \
|
||||||
cti::detail::testing::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);
|
cti::detail::testing::expect_async_validation(CONTINUABLE, VALIDATOR);
|
||||||
|
|
||||||
/// Expects the continuation to be called and forwards it's arguments to
|
/// 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.
|
||||||
///
|
///
|
||||||
|
/// A validator consists of a binary consumer with a signature as in
|
||||||
|
/// in the example shown below:
|
||||||
|
/// ```cpp
|
||||||
/// auto validator = [](auto expected, auto actual) {
|
/// 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.
|
/// The validator is called for every expecting and actual result.
|
||||||
#define EXPECT_ASYNC_BINARY_VALIDATION(CONTINUABLE, ...) \
|
///
|
||||||
cti::detail::testing::expect_async_binary_validation(CONTINUABLE, \
|
/// \note This macro is mainly present for building other assertions
|
||||||
__VA_ARGS__);
|
/// 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
|
/// 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(...) \
|
#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.
|
/// 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__>{})
|
CONTINUABLE, cti::detail::util::identity<__VA_ARGS__>{})
|
||||||
|
|
||||||
#endif // CONTINUABLE_TESTING_HPP_INCLUDED__
|
#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.hpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/test-continuable-base.cpp
|
${CMAKE_CURRENT_LIST_DIR}/test-continuable-base.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/test-continuable-connection.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)
|
${CMAKE_CURRENT_LIST_DIR}/test-continuable-recursion.cpp)
|
||||||
|
|
||||||
target_link_libraries(test-continuable
|
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_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) {
|
TYPED_TEST(single_dimension_tests, are_chainable) {
|
||||||
@ -53,7 +53,7 @@ TYPED_TEST(single_dimension_tests, are_chainable) {
|
|||||||
// Type chain
|
// Type chain
|
||||||
{
|
{
|
||||||
auto chain = this->supply().then([] { return tag1{}; });
|
auto chain = this->supply().then([] { return tag1{}; });
|
||||||
EXPECT_ASYNC_TYPES(std::move(chain), tag1);
|
ASSERT_ASYNC_TYPES(std::move(chain), tag1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pair chain
|
// Pair chain
|
||||||
@ -62,7 +62,7 @@ TYPED_TEST(single_dimension_tests, are_chainable) {
|
|||||||
// ...
|
// ...
|
||||||
return std::make_pair(tag1{}, tag2{});
|
return std::make_pair(tag1{}, tag2{});
|
||||||
});
|
});
|
||||||
EXPECT_ASYNC_TYPES(std::move(chain), tag1, tag2);
|
ASSERT_ASYNC_TYPES(std::move(chain), tag1, tag2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tuple chain
|
// Tuple chain
|
||||||
@ -71,20 +71,20 @@ TYPED_TEST(single_dimension_tests, are_chainable) {
|
|||||||
// ...
|
// ...
|
||||||
return std::make_tuple(tag1{}, tag2{}, tag3{});
|
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
|
// Erasing chain
|
||||||
{
|
{
|
||||||
auto chain = this->supply().then(this->supply(tag1{}));
|
auto chain = this->supply().then(this->supply(tag1{}));
|
||||||
EXPECT_ASYNC_TYPES(std::move(chain), tag1);
|
ASSERT_ASYNC_TYPES(std::move(chain), tag1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Continuing chain
|
// Continuing chain
|
||||||
{
|
{
|
||||||
auto chain = this->supply().then([&] { return this->supply(tag1{}); });
|
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"
|
#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) {
|
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{});
|
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) {
|
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{});
|
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{}) ||
|
auto chain = this->supply(tag1{}, tag2{}, tag3{}) ||
|
||||||
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>;
|
using common = std::common_type_t<char, int>;
|
||||||
auto chain = this->supply(char(0), int(0)) || this->supply(int(0), char(0));
|
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"
|
#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,27 +31,41 @@
|
|||||||
#include "continuable/continuable.hpp"
|
#include "continuable/continuable.hpp"
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
template <typename Provider>
|
using cti::detail::util::identity;
|
||||||
class continuation_provider : public ::testing::Test, public Provider {
|
|
||||||
public:
|
inline auto to_hint(identity<> /*hint*/) { return identity<void>{}; }
|
||||||
auto supply() {
|
template <typename... Args> auto to_hint(identity<Args...> hint) {
|
||||||
return this->makeVoid([](auto&& callback) mutable {
|
return hint;
|
||||||
// ...
|
}
|
||||||
std::forward<decltype(callback)>(callback)();
|
|
||||||
});
|
template <typename... Args> auto supplier_of(Args&&... args) {
|
||||||
};
|
return [values = std::make_tuple(std::forward<Args>(args)...)](
|
||||||
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 {
|
auto&& callback) mutable {
|
||||||
cti::detail::util::unpack(std::move(values), [&](auto&&... passed) {
|
cti::detail::util::unpack(std::move(values), [&](auto&&... passed) {
|
||||||
// ...
|
// ...
|
||||||
std::forward<decltype(callback)>(callback)(
|
std::forward<decltype(callback)>(callback)(
|
||||||
std::forward<decltype(passed)>(passed)...);
|
std::forward<decltype(passed)>(passed)...);
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Provider>
|
||||||
|
class continuation_provider : public ::testing::Test, public Provider {
|
||||||
|
public:
|
||||||
|
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) {
|
||||||
|
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)...));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
inline auto empty_caller() {
|
inline auto empty_caller() {
|
||||||
@ -61,21 +75,21 @@ inline auto empty_caller() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline auto empty_continuable() {
|
||||||
|
return cti::make_continuable<void>(empty_caller());
|
||||||
|
}
|
||||||
|
|
||||||
struct provide_copyable {
|
struct provide_copyable {
|
||||||
template <typename T> auto makeVoid(T&& callback) {
|
template <typename... Args, typename... Hint, typename T>
|
||||||
return make<void>(std::forward<T>(callback));
|
auto make(identity<Args...>, identity<Hint...>, T&& callback) {
|
||||||
}
|
return cti::make_continuable<Hint...>(std::forward<T>(callback));
|
||||||
template <typename... Args, typename T> auto make(T&& callback) {
|
|
||||||
return cti::make_continuable<Args...>(std::forward<T>(callback));
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct provide_unique {
|
struct provide_unique {
|
||||||
template <typename T> auto makeVoid(T&& callback) {
|
template <typename... Args, typename... Hint, typename T>
|
||||||
return make<void>(std::forward<T>(callback));
|
auto make(identity<Args...>, identity<Hint...>, T&& callback) {
|
||||||
}
|
return cti::make_continuable<Hint...>([
|
||||||
template <typename... Args, typename T> auto make(T&& callback) {
|
|
||||||
return cti::make_continuable<Args...>([
|
|
||||||
callback = std::forward<T>(callback), guard = std::make_unique<int>(0)
|
callback = std::forward<T>(callback), guard = std::make_unique<int>(0)
|
||||||
](auto&&... args) mutable {
|
](auto&&... args) mutable {
|
||||||
(void)(*guard);
|
(void)(*guard);
|
||||||
@ -85,68 +99,59 @@ struct provide_unique {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct provide_copyable_erasure {
|
struct provide_copyable_erasure {
|
||||||
template <typename T> auto makeVoid(T&& callback) {
|
template <typename... Args, typename... Hint, typename T>
|
||||||
return make(std::forward<T>(callback));
|
cti::continuable<Args...> make(identity<Args...>, identity<Hint...>,
|
||||||
}
|
T&& callback) {
|
||||||
template <typename... Args, typename T>
|
return cti::make_continuable<Hint...>(std::forward<T>(callback));
|
||||||
cti::continuable<Args...> make(T&& callback) {
|
|
||||||
return cti::make_continuable(std::forward<T>(callback));
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct provide_unique_erasure {
|
struct provide_unique_erasure {
|
||||||
template <typename T> auto makeVoid(T&& callback) {
|
template <typename... Args, typename... Hint, typename T>
|
||||||
return make(std::forward<T>(callback));
|
cti::unique_continuable<Args...> make(identity<Args...>, identity<Hint...>,
|
||||||
}
|
T&& callback) {
|
||||||
template <typename... Args, typename T>
|
return cti::make_continuable<Hint...>(std::forward<T>(callback));
|
||||||
cti::unique_continuable<Args...> make(T&& callback) {
|
|
||||||
return cti::make_continuable(std::forward<T>(callback));
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
template <typename Provider> struct provide_continuation_and_left {
|
||||||
template <typename Left, typename Right> struct provide_continuation_or_left {
|
Provider provider_;
|
||||||
Left left_;
|
|
||||||
Right right_;
|
|
||||||
|
|
||||||
template <typename T> auto makeVoid(T&& callback) {
|
template <typename... Args, typename... Hint, typename T>
|
||||||
return left_.template make<void>(std::forward<T>(callback)) ||
|
auto make(identity<Args...> args, identity<Hint...> hint, T&& callback) {
|
||||||
right_.template make<void>(empty_caller());
|
return empty_continuable() &&
|
||||||
}
|
provider_.make(args, hint, std::forward<T>(callback));
|
||||||
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> struct type_chainer {
|
template <typename Provider> struct provide_continuation_and_right {
|
||||||
template <typename First> auto add() {
|
Provider provider_;
|
||||||
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>>{};
|
|
||||||
}
|
|
||||||
|
|
||||||
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() {
|
// clang-format off
|
||||||
type_chainer<> chainer{};
|
using single_types = ::testing::Types<
|
||||||
return chainer // ...
|
provide_copyable,
|
||||||
.add<provide_copyable>()
|
provide_unique,
|
||||||
.add<provide_unique>()
|
provide_copyable_erasure,
|
||||||
.add<provide_copyable_erasure>()
|
provide_unique_erasure,
|
||||||
.add<provide_unique_erasure>();
|
// Some instantiations out commented for compilation speed reasons
|
||||||
}
|
// provide_continuation_and_left<provide_copyable>,
|
||||||
|
provide_continuation_and_left<provide_unique>,
|
||||||
using single_types = decltype(make_type())::type;
|
// 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 tag1 {};
|
||||||
struct tag2 {};
|
struct tag2 {};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user