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
#define CONTINUABLE_COMPOSITIONS_HPP_INCLUDED
#include <initializer_list>
#include <memory>
#include <utility>
#include <vector>
#include <continuable/detail/composition-all.hpp>
#include <continuable/detail/composition-any.hpp>
@ -242,6 +245,49 @@ template <
auto when_any(Iterator begin, Iterator 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
#endif // CONTINUABLE_COMPOSITIONS_HPP_INCLUDED

View File

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

View File

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