mirror of
https://github.com/Naios/continuable.git
synced 2026-02-07 18:26:40 +08:00
Start to implement the unit tests for loop and add range_loop
This commit is contained in:
parent
135ebfccf3
commit
ac175b4e57
@ -37,9 +37,14 @@
|
|||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <continuable/continuable-base.hpp>
|
#include <continuable/continuable-base.hpp>
|
||||||
#include <continuable/continuable-result.hpp>
|
#include <continuable/continuable-result.hpp>
|
||||||
|
#include <continuable/detail/features.hpp>
|
||||||
#include <continuable/detail/utility/traits.hpp>
|
#include <continuable/detail/utility/traits.hpp>
|
||||||
#include <continuable/detail/utility/util.hpp>
|
#include <continuable/detail/utility/util.hpp>
|
||||||
|
|
||||||
|
#if defined(CONTINUABLE_HAS_EXCEPTIONS)
|
||||||
|
#include <exception>
|
||||||
|
#endif // CONTINUABLE_HAS_EXCEPTIONS
|
||||||
|
|
||||||
namespace cti {
|
namespace cti {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -74,24 +79,52 @@ class loop_frame : public std::enable_shared_from_this<
|
|||||||
ArgsTuple args_;
|
ArgsTuple args_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
explicit loop_frame(Promise promise, Callable callable, ArgsTuple args)
|
||||||
|
: promise_(std::move(promise)), callable_(std::move(callable)),
|
||||||
|
args_(std::move(args)) {
|
||||||
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
|
// MSVC can't evaluate this inside the lambda capture
|
||||||
|
auto me = this->shared_from_this();
|
||||||
|
|
||||||
traits::unpack(
|
traits::unpack(
|
||||||
[&callable_](auto&&... args) {
|
[&](auto&&... args) mutable {
|
||||||
util::invoke(callable_, std::forward<decltype(args)>(args)...)
|
|
||||||
.then([me = this->shared_from_this()](auto&& result) {
|
#if defined(CONTINUABLE_HAS_EXCEPTIONS)
|
||||||
if (result.is_empty()) {
|
try {
|
||||||
me->loop();
|
#endif // CONTINUABLE_HAS_EXCEPTIONS
|
||||||
} else if (result.is_value()) {
|
|
||||||
traits::unpack(std::move(promise_), result);
|
util::invoke(callable_, std::forward<decltype(args)>(args)...)
|
||||||
} else {
|
.next([me = std::move(me)](auto&&... args) {
|
||||||
assert(result.is_exception());
|
me->resolve(std::forward<decltype(args)>(args)...);
|
||||||
traits::unpack(std::move(promise_), exception_arg_t{},
|
});
|
||||||
result.get_exception());
|
|
||||||
}
|
#if defined(CONTINUABLE_HAS_EXCEPTIONS)
|
||||||
});
|
} catch (...) {
|
||||||
|
resolve(exception_arg_t{}, std::current_exception());
|
||||||
|
}
|
||||||
|
#endif // CONTINUABLE_HAS_EXCEPTIONS
|
||||||
},
|
},
|
||||||
args_);
|
args_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Result>
|
||||||
|
void resolve(Result&& result) {
|
||||||
|
if (result.is_empty()) {
|
||||||
|
loop();
|
||||||
|
} else if (result.is_value()) {
|
||||||
|
traits::unpack(std::move(promise_), std::forward<Result>(result));
|
||||||
|
} else {
|
||||||
|
assert(result.is_exception());
|
||||||
|
std::move(promise_).set_exception(
|
||||||
|
std::forward<Result>(result).get_exception());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void resolve(exception_arg_t, exception_t exception) {
|
||||||
|
promise_.set_exception(std::move(exception));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Promise, typename Callable, typename ArgsTuple>
|
template <typename Promise, typename Callable, typename ArgsTuple>
|
||||||
@ -115,10 +148,27 @@ auto loop(Callable&& callable, Args&&... args) {
|
|||||||
args = std::make_tuple(std::forward<decltype(args)>(
|
args = std::make_tuple(std::forward<decltype(args)>(
|
||||||
args)...)](auto&& promise) mutable {
|
args)...)](auto&& promise) mutable {
|
||||||
// Do the actual looping
|
// Do the actual looping
|
||||||
auto frame = make_loop_frame(std::forward<decltype(promise)>(promise));
|
auto frame = make_loop_frame(std::forward<decltype(promise)>(promise),
|
||||||
|
std::move(callable), std::move(args));
|
||||||
frame->loop();
|
frame->loop();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Callable, typename Begin>
|
||||||
|
auto make_range_looper(Callable&& callable, Begin&& begin) {
|
||||||
|
return [callable = std::forward<Callable>(callable),
|
||||||
|
begin = std::forward<Begin>(begin)](auto&& end) mutable {
|
||||||
|
return util::invoke(callable, begin)
|
||||||
|
.then([&begin, // begin stays valid over the `then`.
|
||||||
|
end = std::forward<decltype(end)>(end)]() mutable -> result<> {
|
||||||
|
if (++begin != end) {
|
||||||
|
return empty_result{};
|
||||||
|
} else {
|
||||||
|
return make_result();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
} // namespace operations
|
} // namespace operations
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
} // namespace cti
|
} // namespace cti
|
||||||
|
|||||||
@ -37,12 +37,18 @@
|
|||||||
namespace cti {
|
namespace cti {
|
||||||
/// \ingroup Operations
|
/// \ingroup Operations
|
||||||
/// \{
|
/// \{
|
||||||
|
|
||||||
template <typename Callable, typename... Args>
|
template <typename Callable, typename... Args>
|
||||||
auto loop(Callable&& callable, Args&&... args) {
|
auto loop(Callable&& callable, Args&&... args) {
|
||||||
return detail::operations::loop(std::forward<Callable>(callable),
|
return detail::operations::loop(std::forward<Callable>(callable),
|
||||||
std::forward<Args>(args)...);
|
std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Callable, typename Iterator>
|
||||||
|
auto range_loop(Callable&& callable, Iterator begin, Iterator end) {
|
||||||
|
auto looper = detail::operations::make_range_looper(
|
||||||
|
std::forward<Callable>(callable), begin);
|
||||||
|
return detail::operations::loop(std::move(looper), end);
|
||||||
|
}
|
||||||
/// \}
|
/// \}
|
||||||
} // namespace cti
|
} // namespace cti
|
||||||
|
|
||||||
|
|||||||
@ -56,6 +56,8 @@ set(TEST_SOURCES
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-connection-all.cpp
|
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-connection-all.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-connection-any.cpp
|
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-connection-any.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-connection-seq.cpp
|
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-connection-seq.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-operations-async.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-operations-loop.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-erasure.cpp
|
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-erasure.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-regression.cpp
|
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-regression.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-transforms.cpp)
|
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-transforms.cpp)
|
||||||
|
|||||||
28
test/unit-test/multi/test-continuable-operations-async.cpp
Normal file
28
test/unit-test/multi/test-continuable-operations-async.cpp
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
Copyright(c) 2015 - 2019 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>
|
||||||
|
|
||||||
|
TYPED_TEST(single_dimension_tests, operations_async_) {
|
||||||
|
|
||||||
|
}
|
||||||
67
test/unit-test/multi/test-continuable-operations-loop.cpp
Normal file
67
test/unit-test/multi/test-continuable-operations-loop.cpp
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
Copyright(c) 2015 - 2019 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>
|
||||||
|
|
||||||
|
using namespace cti;
|
||||||
|
|
||||||
|
static int const CANARY = 39472;
|
||||||
|
|
||||||
|
TYPED_TEST(single_dimension_tests, operations_loop_completion) {
|
||||||
|
ASSERT_ASYNC_COMPLETION(loop([] {
|
||||||
|
//
|
||||||
|
return make_ready_continuable(make_result());
|
||||||
|
}));
|
||||||
|
|
||||||
|
ASSERT_ASYNC_RESULT(loop(
|
||||||
|
[](auto&&... args) {
|
||||||
|
//
|
||||||
|
return make_ready_continuable(make_result(
|
||||||
|
std::forward<decltype(args)>(args)...));
|
||||||
|
},
|
||||||
|
CANARY),
|
||||||
|
CANARY);
|
||||||
|
|
||||||
|
ASSERT_ASYNC_RESULT(loop(
|
||||||
|
[](auto&&... args) {
|
||||||
|
//
|
||||||
|
return make_ready_continuable(make_result(
|
||||||
|
std::forward<decltype(args)>(args)...));
|
||||||
|
},
|
||||||
|
CANARY, 2, CANARY),
|
||||||
|
CANARY, 2, CANARY);
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(single_dimension_tests, operations_loop_looping) {
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
ASSERT_ASYNC_COMPLETION(range_loop(
|
||||||
|
[&](int current) {
|
||||||
|
EXPECT_EQ(current, i);
|
||||||
|
++i;
|
||||||
|
return make_ready_continuable();
|
||||||
|
},
|
||||||
|
0, 10));
|
||||||
|
|
||||||
|
ASSERT_EQ(i, 10);
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user