From bcea2c725835450e3888451d670d91647d2b3298 Mon Sep 17 00:00:00 2001 From: god Date: Wed, 14 Oct 2020 23:13:43 +0200 Subject: [PATCH 1/3] added pipeline reduction by value --- include/pipes/fork.hpp | 11 ++++++++ include/pipes/impl/concepts.hpp | 9 ++++++ include/pipes/impl/pipelines_reduction.hpp | 22 +++++++++++++++ include/pipes/impl/pipes_assembly.hpp | 6 ++++ include/pipes/operator.hpp | 13 +++++---- include/pipes/pipes.hpp | 1 + include/pipes/to_container.hpp | 32 ++++++++++++++++++++++ tests/CMakeLists.txt | 1 + tests/fork.cpp | 9 ++++-- tests/to_container.cpp | 32 ++++++++++++++++++++++ 10 files changed, 127 insertions(+), 9 deletions(-) create mode 100644 include/pipes/impl/pipelines_reduction.hpp create mode 100644 include/pipes/to_container.hpp create mode 100644 tests/to_container.cpp diff --git a/include/pipes/fork.hpp b/include/pipes/fork.hpp index fbf2356..3990a06 100644 --- a/include/pipes/fork.hpp +++ b/include/pipes/fork.hpp @@ -5,6 +5,7 @@ #include "pipes/helpers/meta.hpp" #include "pipes/base.hpp" +#include "pipes/impl/pipelines_reduction.hpp" namespace pipes { @@ -19,6 +20,16 @@ class fork_pipeline : public pipeline_base> detail::for_each(tailPipelines_, [&value](auto&& tailPipeline){ send(FWD(value), tailPipeline); }); } + template + auto move_reduced_value_from(std::index_sequence) + { + return std::make_tuple(detail::move_reduced_value_from(std::get(tailPipelines_))...); + } + auto move_reduced_value_from() + { + return move_reduced_value_from(std::make_index_sequence()); + } + explicit fork_pipeline(TailPipelines const&... tailPipelines) : tailPipelines_(tailPipelines...) {} private: diff --git a/include/pipes/impl/concepts.hpp b/include/pipes/impl/concepts.hpp index f6ce0f7..1494094 100644 --- a/include/pipes/impl/concepts.hpp +++ b/include/pipes/impl/concepts.hpp @@ -50,6 +50,15 @@ namespace pipes template using IsAPipeline = impl::IsAPipeline>; + template< class, class = void > + struct has_reduced_value : std::false_type {}; + template< class T > + struct has_reduced_value().move_reduced_value_from() )> > : std::true_type {}; + + template = true> + using IsANonReturningPipeline = std::enable_if_t::value, bool>; + template = true> + using IsAReturningPipeline = std::enable_if_t::value, bool>; } // namespace detail } // namespace pipes diff --git a/include/pipes/impl/pipelines_reduction.hpp b/include/pipes/impl/pipelines_reduction.hpp new file mode 100644 index 0000000..29a10e6 --- /dev/null +++ b/include/pipes/impl/pipelines_reduction.hpp @@ -0,0 +1,22 @@ +#ifndef PIPELINES_REDUCTION_HPP +#define PIPELINES_REDUCTION_HPP + +#include "pipes/impl/concepts.hpp" + +#include + +namespace pipes +{ + namespace detail{ + template = true> + auto move_reduced_value_from(Pipeline&&){return std::ignore;} + + template = true> + auto move_reduced_value_from(Pipeline&& pipeline) + { + return pipeline.move_reduced_value_from(); + } + } +} + +#endif /* PIPELINES_REDUCTION_HPP */ diff --git a/include/pipes/impl/pipes_assembly.hpp b/include/pipes/impl/pipes_assembly.hpp index 32440b8..b875b1a 100644 --- a/include/pipes/impl/pipes_assembly.hpp +++ b/include/pipes/impl/pipes_assembly.hpp @@ -1,6 +1,7 @@ #ifndef PIPES_PIPES_ASSEMBLY #define PIPES_PIPES_ASSEMBLY +#include "pipes/impl/pipelines_reduction.hpp" namespace pipes @@ -18,6 +19,11 @@ namespace pipes headPipe_.template onReceive(FWD(inputs)..., tailPipeline_); } + auto move_reduced_value_from() + { + return detail::move_reduced_value_from(tailPipeline_); + } + generic_pipeline(HeadPipe headPipe, TailPipeline tailPipeline) : headPipe_(headPipe), tailPipeline_(tailPipeline) {} private: diff --git a/include/pipes/operator.hpp b/include/pipes/operator.hpp index fbd3c73..31c0031 100644 --- a/include/pipes/operator.hpp +++ b/include/pipes/operator.hpp @@ -3,6 +3,7 @@ #include "pipes/impl/concepts.hpp" #include "pipes/impl/pipes_assembly.hpp" +#include "pipes/impl/pipelines_reduction.hpp" #include @@ -11,22 +12,22 @@ namespace pipes // range >>= pipeline (rvalue ranges) - template = true, detail::IsAPipeline = true> - std::enable_if_t::value> operator>>=(Range&& range, Pipeline&& pipeline) + template = true, detail::IsAPipeline = true, std::enable_if_t::value, int> = 0> + auto operator>>=(Range&& range, Pipeline&& pipeline) { using std::begin; using std::end; - std::copy(std::make_move_iterator(begin(range)), std::make_move_iterator(end(range)), pipeline); + return detail::move_reduced_value_from(std::copy(std::make_move_iterator(begin(range)), std::make_move_iterator(end(range)), pipeline)); } // range >>= pipeline (lvalue ranges) - template = true, detail::IsAPipeline = true> - std::enable_if_t::value> operator>>=(Range&& range, Pipeline&& pipeline) + template = true, detail::IsAPipeline = true, std::enable_if_t::value, int> = 0> + auto operator>>=(Range&& range, Pipeline&& pipeline) { using std::begin; using std::end; - std::copy(begin(range), end(range), pipeline); + return detail::move_reduced_value_from(std::copy(begin(range), end(range), pipeline)); } // pipe >>= pipe diff --git a/include/pipes/pipes.hpp b/include/pipes/pipes.hpp index c859810..7b61c1b 100644 --- a/include/pipes/pipes.hpp +++ b/include/pipes/pipes.hpp @@ -26,6 +26,7 @@ #include "pipes/take.hpp" #include "pipes/take_while.hpp" #include "pipes/tee.hpp" +#include "pipes/to_container.hpp" #include "pipes/to_out_stream.hpp" #include "pipes/transform.hpp" #include "pipes/unzip.hpp" diff --git a/include/pipes/to_container.hpp b/include/pipes/to_container.hpp new file mode 100644 index 0000000..0952c91 --- /dev/null +++ b/include/pipes/to_container.hpp @@ -0,0 +1,32 @@ +#ifndef TO_CONTAINER_HPP +#define TO_CONTAINER_HPP + +#include "pipes/base.hpp" +#include "pipes/helpers/FWD.hpp" + +#include +#include + +namespace pipes +{ + template + class to_ : public pipeline_base> + { + public: + template + void onReceive(T&& value) + { + container_.push_back(FWD(value)); + } + + auto move_reduced_value_from() + { + return std::exchange(container_, {}); + } + private: + Container container_; + }; + +} + +#endif /* TO_CONTAINER_HPP */ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index fc4ea83..552cfd2 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -26,6 +26,7 @@ add_executable(pipes_test tap.cpp tee.cpp transform.cpp + to_container.cpp unzip.cpp integration_tests.cpp) add_test(NAME pipes_test COMMAND pipes_test) diff --git a/tests/fork.cpp b/tests/fork.cpp index 875b3a2..8e2ead7 100644 --- a/tests/fork.cpp +++ b/tests/fork.cpp @@ -4,6 +4,7 @@ #include "pipes/override.hpp" #include "pipes/transform.hpp" #include "pipes/push_back.hpp" +#include "pipes/to_container.hpp" #include #include @@ -55,9 +56,11 @@ TEST_CASE("fork can send data to other pipes") std::vector multiplesOf2, multiplesOf3, multiplesOf4; - std::copy(begin(numbers), end(numbers), pipes::fork(pipes::filter([](int i){return i%2 == 0;}) >>= pipes::push_back(multiplesOf2), - pipes::filter([](int i){return i%3 == 0;}) >>= pipes::push_back(multiplesOf3), - pipes::filter([](int i){return i%4 == 0;}) >>= pipes::push_back(multiplesOf4))); + std::tie(std::ignore, multiplesOf3, multiplesOf4) = (numbers>>=pipes::fork( + pipes::filter([](int i){return i%2 == 0;}) >>= pipes::push_back(multiplesOf2), + pipes::filter([](int i){return i%3 == 0;}) >>= pipes::to_>(), + pipes::filter([](int i){return i%4 == 0;}) >>= pipes::to_>() + )); REQUIRE(multiplesOf2 == expectedMultiplesOf2); REQUIRE(multiplesOf3 == expectedMultiplesOf3); diff --git a/tests/to_container.cpp b/tests/to_container.cpp new file mode 100644 index 0000000..5525027 --- /dev/null +++ b/tests/to_container.cpp @@ -0,0 +1,32 @@ +#include "catch.hpp" +#include "pipes/pipes.hpp" + +#include +#include + +TEST_CASE("to_vector") +{ + std::vector input = {1, 2, 3, 4, 5, 6, 7 ,8, 9, 10}; + std::vector expected = input; + + REQUIRE(pipes::detail::IsAReturningPipeline< pipes::to_> >{true}); + + auto results=(input>>=pipes::to_>()); + + REQUIRE(results == expected); +} + +TEST_CASE("filter_to_vector") +{ + std::vector input = {1, 2, 3, 4, 5, 6, 7 ,8, 9, 10}; + std::vector expected = {4, 8}; + + REQUIRE(pipes::detail::IsAReturningPipeline< pipes::to_> >{true}); + + auto results=(input + >>=pipes::filter([](int i){return i%4 == 0;}) + >>=pipes::to_>() + ); + + REQUIRE(results == expected); +} From c18039b8ba9e16e03e7d601788f571c0466340b7 Mon Sep 17 00:00:00 2001 From: god Date: Thu, 15 Oct 2020 20:14:57 +0200 Subject: [PATCH 2/3] added custom void_t to be compatible with C++14 --- include/pipes/impl/concepts.hpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/include/pipes/impl/concepts.hpp b/include/pipes/impl/concepts.hpp index 1494094..3017e16 100644 --- a/include/pipes/impl/concepts.hpp +++ b/include/pipes/impl/concepts.hpp @@ -12,6 +12,11 @@ namespace pipes { namespace impl { + // definition of void_t from C++17 + + template< class... > + using void_t = void; + // definition of range namespace adl @@ -53,7 +58,7 @@ namespace pipes template< class, class = void > struct has_reduced_value : std::false_type {}; template< class T > - struct has_reduced_value().move_reduced_value_from() )> > : std::true_type {}; + struct has_reduced_value().move_reduced_value_from() )> > : std::true_type {}; template = true> using IsANonReturningPipeline = std::enable_if_t::value, bool>; From 2b6c6e8ed59a1763fd134b6de53ae747e5101259 Mon Sep 17 00:00:00 2001 From: god Date: Mon, 19 Oct 2020 00:15:32 +0200 Subject: [PATCH 3/3] PR #62 - return a custom type `no_reduced_value_t` instead of `std::ignore` --- include/pipes/impl/pipelines_reduction.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/pipes/impl/pipelines_reduction.hpp b/include/pipes/impl/pipelines_reduction.hpp index 29a10e6..cd4f1cf 100644 --- a/include/pipes/impl/pipelines_reduction.hpp +++ b/include/pipes/impl/pipelines_reduction.hpp @@ -8,8 +8,10 @@ namespace pipes { namespace detail{ + struct no_reduced_value_t{}; + template = true> - auto move_reduced_value_from(Pipeline&&){return std::ignore;} + auto move_reduced_value_from(Pipeline&&){return no_reduced_value_t{};} template = true> auto move_reduced_value_from(Pipeline&& pipeline)