Add cti::populate and make use of it in tests

This commit is contained in:
Denis Blank 2018-03-09 09:43:58 +01:00
parent 86c3815ae0
commit de40af0927
5 changed files with 72 additions and 37 deletions

View File

@ -31,7 +31,10 @@
#ifndef CONTINUABLE_COMPOSITIONS_HPP_INCLUDED #ifndef CONTINUABLE_COMPOSITIONS_HPP_INCLUDED
#define CONTINUABLE_COMPOSITIONS_HPP_INCLUDED #define CONTINUABLE_COMPOSITIONS_HPP_INCLUDED
#include <initializer_list>
#include <memory>
#include <utility> #include <utility>
#include <vector>
#include <continuable/detail/composition-all.hpp> #include <continuable/detail/composition-all.hpp>
#include <continuable/detail/composition-any.hpp> #include <continuable/detail/composition-any.hpp>
@ -242,6 +245,49 @@ template <
auto when_any(Iterator begin, Iterator end) { auto when_any(Iterator begin, Iterator end) {
return when_any(detail::range::persist_range(begin, end)); return when_any(detail::range::persist_range(begin, end));
} }
/// Populates a homogeneous container from the given arguments.
/// All arguments need to be convertible to the first one,
/// by default std::vector is used as container type.
///
/// This method mainly helps to create a homogeneous container from
/// a runtime known count of continuables which type isn't exactly known.
/// All continuables which are passed to this function should be originating
/// from the same source or a method called with the same types of arguments:
/// ```cpp
/// auto container = cti::populate(cti::make_ready_continuable(0),
/// cti::make_ready_continuable(1)),
///
/// for (int i = 2; i < 5; ++i) {
/// // You may add more continuables to the container afterwards
/// container.emplace_back(cti::make_ready_continuable(i));
/// }
///
/// cti::when_any(std::move(container))
/// .then([](int) {
/// // ...
/// });
/// ```
/// Additionally it is possible to change the targeted container as below:
/// ```cpp
/// auto container = cti::populate<std::list>(cti::make_ready_continuable(0),
/// cti::make_ready_continuable(1)),
/// ```
///
/// \tparam C The container type which is used to store the arguments into.
///
/// \since 3.0.0
template <template <typename, typename> class C = std::vector, typename First,
typename... Args>
C<std::decay_t<First>, std::allocator<std::decay_t<First>>>
populate(First&& first, Args&&... args) {
C<std::decay_t<First>, std::allocator<std::decay_t<First>>> container;
container.reserve(1 + sizeof...(Args));
container.emplace_back(std::forward<First>(first));
(void)std::initializer_list<int>{
0, ((void)container.emplace_back(std::forward<Args>(args)), 0)...};
return container; // RVO
}
} // namespace cti } // namespace cti
#endif // CONTINUABLE_COMPOSITIONS_HPP_INCLUDED #endif // CONTINUABLE_COMPOSITIONS_HPP_INCLUDED

View File

@ -33,6 +33,7 @@
#include <iterator> #include <iterator>
#include <type_traits> #include <type_traits>
#include <utility>
#include <vector> #include <vector>
#include <continuable/detail/traits.hpp> #include <continuable/detail/traits.hpp>
@ -52,11 +53,11 @@ struct is_iterator<T,
template <typename Iterator> template <typename Iterator>
auto persist_range(Iterator begin, Iterator end) { auto persist_range(Iterator begin, Iterator end) {
std::vector<typename std::iterator_traits<Iterator>::value_type> storage; std::vector<typename std::iterator_traits<Iterator>::value_type> storage;
// TODO Find out why the superior idiom below has issues with move only types:
storage.insert(storage.end(), std::make_move_iterator(begin), // storage.insert(storage.end(), std::make_move_iterator(begin),
std::make_move_iterator(end)); // std::make_move_iterator(end));
std::move(begin, end, std::back_inserter(storage));
return storage; // RVO return storage;
} }
} // namespace range } // namespace range
} // namespace detail } // namespace detail

View File

@ -126,19 +126,21 @@ void old() {
int main(int, char**) { int main(int, char**) {
using namespace cti::detail; using namespace cti::detail;
cti::when_seq( {
cti::make_ready_continuable(0, 1), 2, //< See this plain value cti::when_seq(
std::vector<cti::continuable<int>>{cti::make_ready_continuable(3), cti::make_ready_continuable(0, 1), 2, //< See this plain value
cti::make_ready_continuable(4)}, cti::populate(cti::make_ready_continuable(3),
std::make_tuple(std::make_tuple(cti::make_ready_continuable(5)))) cti::make_ready_continuable(4)),
.then([](int r0, int r1, int r2, std::vector<int> r34, std::make_tuple(std::make_tuple(cti::make_ready_continuable(5))))
std::tuple<std::tuple<int>> r5) { .then([](int r0, int r1, int r2, std::vector<int> r34,
// ... std::tuple<std::tuple<int>> r5) {
util::unused(r0, r1, r2, r34, r5); // ...
}); util::unused(r0, r1, r2, r34, r5);
});
}
std::vector<cti::continuable<int>> v{cti::make_ready_continuable(8), auto v = cti::populate(cti::make_ready_continuable(8),
cti::make_ready_continuable(9)}; cti::make_ready_continuable(9));
cti::when_seq(v.begin(), v.end()).then([](auto o2) { cti::when_seq(v.begin(), v.end()).then([](auto o2) {
// ... // ...
@ -162,8 +164,8 @@ int main(int, char**) {
cti::when_all( cti::when_all(
cti::make_ready_continuable(0, 1), 2, //< See this plain value cti::make_ready_continuable(0, 1), 2, //< See this plain value
std::vector<cti::continuable<int>>{cti::make_ready_continuable(3), cti::populate(cti::make_ready_continuable(3),
cti::make_ready_continuable(4)}, cti::make_ready_continuable(4)),
std::make_tuple(std::make_tuple(cti::make_ready_continuable(5)))) std::make_tuple(std::make_tuple(cti::make_ready_continuable(5))))
.then([](int r0, int r1, int r2, std::vector<int> r34, .then([](int r0, int r1, int r2, std::vector<int> r34,
std::tuple<std::tuple<int>> r5) { std::tuple<std::tuple<int>> r5) {

View File

@ -75,15 +75,8 @@ void test_all_seq_aggregate(Supplier&& supply, AggregateConnector&& ag) {
} }
{ {
using type_t = std::decay_t<decltype( auto chain = ag(std::make_tuple(
std::declval<Supplier>()(std::declval<int>(), std::declval<int>()))>; cti::populate(supply(1, 2), supply(3, 4), supply(5, 6))));
std::vector<type_t> v;
v.push_back(supply(1, 2));
v.push_back(supply(3, 4));
v.push_back(supply(5, 6));
auto chain = ag(std::make_tuple(std::move(v)));
EXPECT_ASYNC_RESULT(std::move(chain), EXPECT_ASYNC_RESULT(std::move(chain),
std::make_tuple(std::vector<std::tuple<int, int>>{ std::make_tuple(std::vector<std::tuple<int, int>>{
{1, 2}, {3, 4}, {5, 6}})); {1, 2}, {3, 4}, {5, 6}}));

View File

@ -68,15 +68,8 @@ TYPED_TEST(single_dimension_tests, is_logical_any_connectable) {
} }
{ {
using type_t = std::decay_t<decltype(std::declval<TestFixture>().supply( auto chain = cti::when_any(std::make_tuple(std::move(cti::populate(
std::declval<int>(), std::declval<int>()))>; this->supply(1, 2), this->supply(3, 4), this->supply(5, 6)))));
std::vector<type_t> v;
v.push_back(this->supply(1, 2));
v.push_back(this->supply(3, 4));
v.push_back(this->supply(5, 6));
auto chain = cti::when_any(std::make_tuple(std::move(v)));
EXPECT_ASYNC_RESULT(std::move(chain), 1, 2); EXPECT_ASYNC_RESULT(std::move(chain), 1, 2);
} }