For loops provide loop_result loop_break and loop_continue for better readability

This commit is contained in:
Denis Blank 2019-01-14 21:10:17 +01:00
parent 76ecc3d26d
commit 20cd0191fc
3 changed files with 73 additions and 3 deletions

View File

@ -31,6 +31,7 @@
#ifndef CONTINUABLE_DETAIL_TYPES_HPP_INCLUDED
#define CONTINUABLE_DETAIL_TYPES_HPP_INCLUDED
#include <type_traits>
#include <utility>
#include <continuable/detail/features.hpp>
#include <continuable/detail/utility/identity.hpp>
@ -84,6 +85,10 @@ class plain_tag {
T value_;
public:
template <typename O, std::enable_if_t<std::is_constructible<
T, std::decay_t<O>>::value>* = nullptr>
/* implicit */ plain_tag(O&& value) : value_(std::forward<O>(value)) {
}
explicit plain_tag(T value) : value_(std::move(value)) {
}

View File

@ -32,6 +32,7 @@
#define CONTINUABLE_OPERATIONS_LOOP_HPP_INCLUDED
#include <utility>
#include <continuable/continuable-primitives.hpp>
#include <continuable/continuable-result.hpp>
#include <continuable/detail/operations/loop.hpp>
@ -42,11 +43,30 @@ namespace cti {
/// Can be used to create an asynchronous loop.
///
/// The callable will be called repeatedly until it returns a
/// cti::continuable_base which then resolves to present cti::result.
/// cti::continuable_base which then resolves to a present cti::result.
///
/// For better readability cti::loop_result, cti::loop_break and
/// cti::loop_continue are provided which can be used as following:
/// ```cpp
/// auto while_answer_not_yes() {
/// return loop([] {
/// return ask_something().then([](std::string answer) -> loop_result<> {
/// if (answer == "yes") {
/// return loop_break();
/// } else {
/// return loop_continue();
/// }
/// });
/// });
/// }
/// ```
///
/// \param callable The callable type which must return a cti::continuable_base
/// which then resolves to a cti::result of arbitrary values.
///
/// \param args The arguments that are passed to the callable upon
/// each invocation.
///
/// \since 4.0.0
///
template <typename Callable, typename... Args>
@ -55,6 +75,34 @@ auto loop(Callable&& callable, Args&&... args) {
std::forward<Args>(args)...);
}
/// Can be used to indicate a specific result inside an asynchronous loop.
///
/// See cti::loop for details.
///
/// \since 4.0.0
template <typename... T>
using loop_result = plain_t<result<T...>>;
/// Can be used to create a loop_result which causes the loop to be
/// cancelled and resolved with the given arguments.
///
/// See cti::loop for details.
///
/// \since 4.0.0
template <typename... T>
auto loop_break(T&&... args) {
return make_plain(make_result(std::forward<T>(args)...));
}
/// Can be used to create a loop_result which causes the loop to be repeated.
///
/// See cti::loop for details.
///
/// \since 4.0.0
inline auto loop_continue() noexcept {
return empty_result{};
}
///
/// \since 4.0.0
///
@ -64,6 +112,7 @@ auto range_loop(Callable&& callable, Iterator begin, Iterator end) {
detail::operations::make_range_looper(std::forward<Callable>(callable),
begin, end));
}
/// \}
} // namespace cti

View File

@ -52,6 +52,22 @@ TYPED_TEST(single_dimension_tests, operations_loop_completion) {
CANARY, 2, CANARY);
}
TYPED_TEST(single_dimension_tests, operations_loop_until) {
int i = 0;
ASSERT_ASYNC_COMPLETION(loop([&i] {
return make_ready_continuable(++i).then([](int i) -> loop_result<> {
if (i == 3) {
return loop_break();
} else {
return loop_continue();
}
});
}));
ASSERT_EQ(i, 3);
}
TYPED_TEST(single_dimension_tests, operations_loop_looping) {
int i = 0;
@ -61,7 +77,7 @@ TYPED_TEST(single_dimension_tests, operations_loop_looping) {
++i;
return make_ready_continuable();
},
0, 10));
0, 3));
ASSERT_EQ(i, 10);
ASSERT_EQ(i, 3);
}