diff --git a/include/pipes2/detail/api/ensureValidOutput.hpp b/include/pipes2/detail/api/ensureValidInputOutput.hpp similarity index 100% rename from include/pipes2/detail/api/ensureValidOutput.hpp rename to include/pipes2/detail/api/ensureValidInputOutput.hpp diff --git a/include/pipes2/detail/api/makePipes.hpp b/include/pipes2/detail/api/makePipes.hpp index 6979a49..1763157 100644 --- a/include/pipes2/detail/api/makePipes.hpp +++ b/include/pipes2/detail/api/makePipes.hpp @@ -11,7 +11,7 @@ #include "pipes2/detail/pipes/makeSource.hpp" #include "pipes2/detail/pipes/makeSink.hpp" -#include "pipes2/detail/api/ensureValidOutput.hpp" +#include "pipes2/detail/api/ensureValidInputOutput.hpp" // throughput pipes namespace tillh::pipes2 diff --git a/include/pipes2/detail/api/pipingOperator.hpp b/include/pipes2/detail/api/pipingOperator.hpp index 6331364..0f52e55 100644 --- a/include/pipes2/detail/api/pipingOperator.hpp +++ b/include/pipes2/detail/api/pipingOperator.hpp @@ -3,13 +3,11 @@ #include "pipes2/detail/core/connect.hpp" -#include "pipes2/detail/api/ensureValidOutput.hpp" - namespace tillh::pipes2 { template || detail::canSend) && (detail::receives || detail::canReceive), bool> = true> auto operator>>=(Lhs && lhs, Rhs && rhs) { - return connectPrimary(std::forward(lhs), std::forward(rhs)); + return connectPrimary(FWD(lhs), FWD(rhs)); } } diff --git a/include/pipes2/detail/core/Node.hpp b/include/pipes2/detail/core/Node.hpp index 289694f..f3be329 100644 --- a/include/pipes2/detail/core/Node.hpp +++ b/include/pipes2/detail/core/Node.hpp @@ -5,40 +5,43 @@ #include "pipes2/detail/util/metaprogramming.hpp" #include "pipes2/detail/util/ignoreWarning.hpp" +#include "pipes2/detail/util/FWD.hpp" #include "pipes2/detail/core/traits.hpp" namespace tillh::pipes2 { - template + template struct Node { using Op = OpT; using Connections = ConnectionsT; - using PrimaryConnection = PrimaryConnectionT; - template - Node(Connections_&& _connections, PrimaryConnection_&& _connectPrimaryion, - Op_&& _op): primaryConnection(std::forward(_connectPrimaryion)), connections( - std::forward(_connections)), - op(std::forward(_op)) + template + Node(Connections_&& _connections, Op_&& _op): + connections(std::forward(_connections)), op(std::forward(_op)) {} - PrimaryConnection primaryConnection; + template + auto operator()(Rhss&& ... rhss) const + { + return connectSecondary(*this, FWD(rhss)...); + } + Connections connections; Op op; }; - struct NoPrimary {}; struct OpenConnectionPlaceHolder {}; + struct PrimaryOpenConnectionPlaceHolder {}; } namespace tillh::pipes2 { - template - auto makeNode(Op op, Connections connections, PrimaryConnection primaryConnection) + template + auto makeNode(Op op, Connections connections) { - return Node(std::move(connections), std::move(primaryConnection), std::move(op)); + return Node(std::move(connections), std::move(op)); } @@ -58,7 +61,17 @@ namespace tillh::pipes2 template auto makeNode(Op op) { - constexpr auto makePrimary = [] {if constexpr(hasPrimaryConnection) { return OpenConnectionPlaceHolder(); } else { return NoPrimary(); }}; - return makeNode(op, makeOpenConnections(std::make_index_sequence()), makePrimary()); + constexpr auto makePrimary = [] + { + if constexpr(hasPrimaryConnection) + { + return std::make_tuple(PrimaryOpenConnectionPlaceHolder()); + } + else + { + return std::tuple<>(); + } + }; + return makeNode(op, std::tuple_cat(makeOpenConnections(std::make_index_sequence()), makePrimary())); } } diff --git a/include/pipes2/detail/core/connect.hpp b/include/pipes2/detail/core/connect.hpp index 7b1405a..e36e40d 100644 --- a/include/pipes2/detail/core/connect.hpp +++ b/include/pipes2/detail/core/connect.hpp @@ -20,8 +20,8 @@ namespace tillh::pipes2 template<> struct openCountT : int_constant<1> {}; - template - struct openCountT, Primary>> : sum...> {}; + template + struct openCountT>> : sum...> {}; template constexpr static std::size_t openCount = openCountT::value; @@ -77,15 +77,34 @@ namespace tillh::pipes2 )); } } + namespace tillh::pipes2 { - enum class ConnectMode{Primary, Secondary}; + enum class ConnectMode { Primary, Secondary, Any }; template using mode_constant = std::integral_constant; using primary_constant = mode_constant; using secondary_constant = mode_constant; + using any_constant = mode_constant; + + template + decltype(auto) clearPrimary(T&& t) + { + return FWD(t); + } + + inline auto clearPrimary(PrimaryOpenConnectionPlaceHolder) + { + return OpenConnectionPlaceHolder(); + } + + template + auto clearPrimary(Node&& node) + { + return makeNode(std::move(node.op), tuple_replace>(std::move(node.connections), clearPrimary(getLast(node.connections)))); + } template auto connectIndices(Connection&& connection, std::index_sequence, NewConnects newConnects) @@ -96,7 +115,7 @@ namespace tillh::pipes2 } else { - return connectImpl(secondary_constant(), std::forward(connection), std::get(newConnects)...); + return clearPrimary(connectImpl(secondary_constant(), std::forward(connection), std::get(newConnects)...)); } } @@ -114,6 +133,7 @@ namespace tillh::pipes2 return connectIndexWise_impl(std::forward(connections), indices, newConnects, std::make_index_sequence()); } } + namespace tillh::pipes2 { template @@ -122,37 +142,48 @@ namespace tillh::pipes2 static_assert(sizeof...(children) > 0); static_assert(sizeof...(children) <= openCount>); auto indices = getIndices>(); - return makeNode(std::forward(node).op, connectIndexWise(std::forward(node).connections, indices, std::forward_as_tuple(children...)), std::forward(node).primaryConnection); + return makeNode(std::forward(node).op, connectIndexWise(std::forward(node).connections, indices, std::forward_as_tuple(children...))); } template auto connectPrimaryImpl(Node&& node, Child&& child) { - return makeNode(FWD(node).op, FWD(node).connections, connectImpl(primary_constant(), FWD(node).primaryConnection, FWD(child))); + static_assert(canPrimaryConnect>); + constexpr std::size_t lastIndex = tuple_back::Connections>; + return makeNode(FWD(node).op, tuple_replace(FWD(node).connections, connectImpl(primary_constant(), getLast(FWD(node).connections), FWD(child)))); } - + template auto connectImpl(mode_constant, Lhs&& lhs, Rhss&& ... rhss) { static_assert(sizeof...(Rhss) > 0, "at least 1 rhs needed"); - if constexpr(std::is_same_v, OpenConnectionPlaceHolder>) + if constexpr(mode == ConnectMode::Secondary) { - static_assert(sizeof...(Rhss) == 1, "there should never be a call to connect one placeholder with multiple nodes"); - return getFirst(FWD(rhss)...); + if constexpr(std::is_same_v, OpenConnectionPlaceHolder>) + { + static_assert(sizeof...(Rhss) == 1, "there should never be a call to connect one placeholder with multiple nodes"); + return getFirst(FWD(rhss)...); + } + else + { + return evaluateIfFinished(connectSecondaryImpl(FWD(lhs), FWD(rhss)...)); + } } - else + else if(mode == ConnectMode::Primary) { - if constexpr(mode == ConnectMode::Secondary) + if constexpr(std::is_same_v, PrimaryOpenConnectionPlaceHolder>) { - return evaluateIfFinished(connectSecondaryImpl(FWD(lhs), FWD(rhss)...)); + static_assert(sizeof...(Rhss) == 1, "there should never be a call to connect one placeholder with multiple nodes"); + return getFirst(FWD(rhss)...); } - else if(mode == ConnectMode::Primary) + else { static_assert(sizeof...(Rhss) == 1, "can only primaryconnect 1 at a time"); return evaluateIfFinished(connectPrimaryImpl(FWD(lhs), FWD(rhss)...)); } } + } template diff --git a/include/pipes2/detail/core/evaluate.hpp b/include/pipes2/detail/core/evaluate.hpp index 578324c..1fe9983 100644 --- a/include/pipes2/detail/core/evaluate.hpp +++ b/include/pipes2/detail/core/evaluate.hpp @@ -7,21 +7,14 @@ namespace tillh::pipes2 { - template - auto evaluate(Node&& node) + template + auto evaluate(Node&& node) { - using NodeT = Node; + using NodeT = Node; static_assert(!canSecondaryConnect); static_assert(!canPrimaryConnect); - if constexpr(hasPrimary_v) - { - return makeOutput(std::move(node.op), std::tuple_cat(std::move(node.connections), std::make_tuple(std::move(node.primaryConnection)))); - } - else - { - return makeOutput(std::move(node.op), std::move(node.connections)); - } + return makeOutput(std::move(node.op), std::move(node.connections)); } template diff --git a/include/pipes2/detail/core/traits.hpp b/include/pipes2/detail/core/traits.hpp index 52388ea..1e978de 100644 --- a/include/pipes2/detail/core/traits.hpp +++ b/include/pipes2/detail/core/traits.hpp @@ -57,15 +57,3 @@ namespace tillh::pipes2 template constexpr static bool canSecondaryConnect = canSecondaryConnectT::value; } - -namespace tillh::pipes2 -{ - template - struct hasPrimaryT : std::false_type - { - static_assert(fail_assert); - }; - - template - constexpr static bool hasPrimary_v = hasPrimaryT::value; -} diff --git a/include/pipes2/detail/core/traits.impl.hpp b/include/pipes2/detail/core/traits.impl.hpp index f59148d..a5924c4 100644 --- a/include/pipes2/detail/core/traits.impl.hpp +++ b/include/pipes2/detail/core/traits.impl.hpp @@ -16,14 +16,14 @@ namespace tillh::pipes2::detail template struct isSender> : std::true_type {}; - template - struct isSender> : std::true_type {}; + template + struct isSender> : std::true_type {}; template struct isReceiver> : std::true_type {}; - template - struct isReceiver> : std::true_type {}; + template + struct isReceiver> : std::true_type {}; template<> struct isReceiver : std::true_type {}; @@ -46,17 +46,17 @@ namespace tillh::pipes2::detail namespace tillh::pipes2 { - template<> - struct canPrimaryConnectT : std::false_type {}; - template struct canPrimaryConnectT> : std::false_type {}; template<> - struct canPrimaryConnectT : std::true_type {}; + struct canPrimaryConnectT : std::true_type {}; - template - struct canPrimaryConnectT> : canPrimaryConnectT {}; + template<> + struct canPrimaryConnectT : std::false_type {}; + + template + struct canPrimaryConnectT> : canPrimaryConnectT> {}; } namespace tillh::pipes2 @@ -64,15 +64,12 @@ namespace tillh::pipes2 template<> struct canSecondaryConnectT : std::true_type {}; + template<> + struct canSecondaryConnectT : std::false_type {}; + template struct canSecondaryConnectT> : std::false_type {}; - template - struct canSecondaryConnectT, PrimaryConnection>> : std::disjunction...> {}; -} - -namespace tillh::pipes2 -{ - template - struct hasPrimaryT> : std::negation> {}; + template + struct canSecondaryConnectT>> : std::disjunction...> {}; } diff --git a/include/pipes2/detail/pipes/makeSource.hpp b/include/pipes2/detail/pipes/makeSource.hpp index 0c1d666..ba93d00 100644 --- a/include/pipes2/detail/pipes/makeSource.hpp +++ b/include/pipes2/detail/pipes/makeSource.hpp @@ -17,7 +17,7 @@ namespace tillh::pipes2::detail template auto makeSourceInput(T&& t) { - return makeInput(std::forward(t), OpenConnectionPlaceHolder()); + return makeInput(std::forward(t), PrimaryOpenConnectionPlaceHolder()); } template>, bool> = true> diff --git a/include/pipes2/detail/util/metaprogramming.hpp b/include/pipes2/detail/util/metaprogramming.hpp index 10b9bcc..ad426d7 100644 --- a/include/pipes2/detail/util/metaprogramming.hpp +++ b/include/pipes2/detail/util/metaprogramming.hpp @@ -3,6 +3,8 @@ #include #include +#include "pipes2/detail/util/FWD.hpp" + namespace tillh::pipes2 { template @@ -20,28 +22,28 @@ namespace tillh::pipes2 template using remove_cv_ref_t = typename remove_cv_ref::type; template - auto pick(Tuple& tuple, T& t) + auto pick(Tuple&& tuple, T&& t) { if constexpr(pickIndex == currentIndex) { - return std::move(t); + return FWD(t); } else { - return std::move(std::get(tuple)); + return std::get(FWD(tuple)); } } template - auto tuple_replace_impl(Tuple& tuple, T& t, std::index_sequence) + auto tuple_replace_impl(Tuple&& tuple, T&& t, std::index_sequence) { - return std::make_tuple(std::move(pick(tuple, t))...); + return std::make_tuple(std::move(pick(FWD(tuple), FWD(t)))...); } template - auto tuple_replace(Tuple& tuple, T& t) + auto tuple_replace(Tuple&& tuple, T&& t) { - return tuple_replace_impl(tuple, t, std::make_index_sequence>()); + return tuple_replace_impl(FWD(tuple), FWD(t), std::make_index_sequence>>()); } template @@ -55,11 +57,17 @@ namespace tillh::pipes2 struct TypeList {}; template - auto typeList(Type>) + constexpr auto typeList(Type>) { return TypeList{}; } + template + constexpr auto append(TypeList, Type) + { + return TypeList(); + } + namespace detail { template @@ -137,3 +145,18 @@ namespace tillh::pipes2 template using sum = int_constant<(Ts::value + ...)>; } + +namespace tillh::pipes2 +{ + template + constexpr static std::size_t tuple_back = std::tuple_size_v -1; + + template + using last_element = std::tuple_element_t, Tuple>; + + template + decltype(auto) getLast(Tuple&& tuple) + { + return std::get>>(FWD(tuple)); + } +} diff --git a/test/src/detail/SyntaxTree.cpp b/test/src/detail/SyntaxTree.cpp index d87888a..7cf647d 100644 --- a/test/src/detail/SyntaxTree.cpp +++ b/test/src/detail/SyntaxTree.cpp @@ -1,26 +1,31 @@ #include -#include -#include +#include #include "../Dummy.hpp" #include "is_node.hpp" -using namespace tillh::pipes2; +namespace pipes = tillh::pipes2; -using Open = OpenConnectionPlaceHolder; +using Open = pipes::OpenConnectionPlaceHolder; using Closed = DummyOutput; auto makeOutput() { return Closed{DummyOp(), {}}; } template auto replace(Node1 node1, Node2 node2) { - return makeNode(node1.op, tuple_replace(node1.connections, node2), node1.primaryConnection); + return pipes::makeNode(node1.op, pipes::tuple_replace(node1.connections, node2)); +} + +template +constexpr auto node() +{ + return pipes::makeNode(DummyOp()); } TEST(isNode, node) { - using NodeT = Node, Open>; + using NodeT = pipes::Node>; static_assert(is_node_v); } @@ -31,169 +36,248 @@ TEST(isNode, int) TEST(canSecondaryConnect, singleOpen) { - using NodeT = Node, NoPrimary>; - static_assert(canSecondaryConnect); + using NodeT = pipes::Node>; + static_assert(pipes::canSecondaryConnect); } TEST(canSecondaryConnect, singleClosed) { - using NodeT = Node, NoPrimary>; - static_assert(!canSecondaryConnect); + using NodeT = pipes::Node>; + static_assert(!pipes::canSecondaryConnect); } TEST(canSecondaryConnect, secondOpen) { - using NodeT = Node, NoPrimary>; - static_assert(canSecondaryConnect); + using NodeT = pipes::Node>; + static_assert(pipes::canSecondaryConnect); } TEST(canSecondaryConnect, twoClosed) { - using NodeT = Node, NoPrimary>; - static_assert(!canSecondaryConnect); + using NodeT = pipes::Node>; + static_assert(!pipes::canSecondaryConnect); } TEST(canSecondaryConnect, manyClosed) { - using NodeT = Node, NoPrimary>; - static_assert(!canSecondaryConnect); + using NodeT = pipes::Node>; + static_assert(!pipes::canSecondaryConnect); } TEST(canSecondaryConnect, manyOneOpen) { - using NodeT = Node, NoPrimary>; - static_assert(canSecondaryConnect); + using NodeT = pipes::Node>; + static_assert(pipes::canSecondaryConnect); } TEST(canSecondaryConnect, manySeveralOpen) { - using NodeT = Node, NoPrimary>; - static_assert(canSecondaryConnect); + using NodeT = pipes::Node>; + static_assert(pipes::canSecondaryConnect); } TEST(connectSecondaryImpl, singleNodeToOutput) { - auto node1 = makeNode(DummyOp()); + auto node1 = node(); using NodeT = decltype(node1); - static_assert(canSecondaryConnect); - static_assert(!canPrimaryConnect); + static_assert(pipes::canSecondaryConnect); + static_assert(!pipes::canPrimaryConnect); auto node2 = makeOutput(); - static_assert(is_output_v); + static_assert(pipes::is_output_v); - auto result = connectImpl(secondary_constant(), node1, node2); - static_assert(is_output_v); + auto result = pipes::connectImpl(pipes::secondary_constant(), node1, node2); + static_assert(pipes::is_output_v); } TEST(connectSecondaryImpl, depthFirst) { - auto node1 = makeNode(DummyOp()); - static_assert(canSecondaryConnect); + auto node1 = node(); + static_assert(pipes::canSecondaryConnect); - auto node2 = makeNode(DummyOp()); - static_assert(canSecondaryConnect); + auto node2 = node(); + static_assert(pipes::canSecondaryConnect); - auto node3 = connectSecondaryImpl(node1, node2); - static_assert(canSecondaryConnect); + auto node3 = pipes::connectSecondaryImpl(node1, node2); + static_assert(pipes::canSecondaryConnect); auto output = makeOutput(); - auto result = connectImpl(secondary_constant(), node3, output); - static_assert(canSecondaryConnect); + auto result = pipes::connectImpl(pipes::secondary_constant(), node3, output); + static_assert(pipes::canSecondaryConnect); } TEST(connectSecondaryImpl, openCount) { - auto node1 = makeNode(DummyOp()); - static_assert(openCount == 2); + auto node1 = node(); + static_assert(pipes::openCount == 2); - auto node2 = makeNode(DummyOp()); - static_assert(openCount == 1); + auto node2 = node(); + static_assert(pipes::openCount == 1); auto node3 = replace<0>(node1, node2); - static_assert(openCount == 2); + static_assert(pipes::openCount == 2); auto output = makeOutput(); auto result = replace<0>(node1, replace<0>(node2, output)); - static_assert(openCount == 1); + static_assert(pipes::openCount == 1); } TEST(connectSecondaryImpl, getIndices_x) { - static_assert(std::is_same_v()), std::index_sequence<0>>); - static_assert(std::is_same_v()), std::index_sequence<1, 2, 3>>); - static_assert(std::is_same_v()), std::index_sequence<0>>); - static_assert(std::is_same_v()), std::index_sequence<1>>); - static_assert(std::is_same_v()), std::index_sequence<2>>); - static_assert(std::is_same_v()), std::index_sequence<0>>); - - static_assert(std::is_same_v()), std::index_sequence<0>>); - static_assert(std::is_same_v()), std::index_sequence<1, 2>>); - static_assert(std::is_same_v()), std::index_sequence<0>>); - static_assert(std::is_same_v()), std::index_sequence<1>>); - static_assert(std::is_same_v()), std::index_sequence<>>); - static_assert(std::is_same_v()), std::index_sequence<>>); + static_assert(std::is_same_v()), std::index_sequence<0>>); + static_assert(std::is_same_v()), std::index_sequence<1, 2, 3>>); + static_assert(std::is_same_v()), std::index_sequence<0>>); + static_assert(std::is_same_v()), std::index_sequence<1>>); + static_assert(std::is_same_v()), std::index_sequence<2>>); + static_assert(std::is_same_v()), std::index_sequence<0>>); + + static_assert(std::is_same_v()), std::index_sequence<0>>); + static_assert(std::is_same_v()), std::index_sequence<1, 2>>); + static_assert(std::is_same_v()), std::index_sequence<0>>); + static_assert(std::is_same_v()), std::index_sequence<1>>); + static_assert(std::is_same_v()), std::index_sequence<>>); + static_assert(std::is_same_v()), std::index_sequence<>>); } TEST(connectSecondaryImpl, getIndices) { - auto node1 = makeNode(DummyOp()); - auto node2 = makeNode(DummyOp()); - auto node3 = makeNode(DummyOp()); + auto node1 = node(); + auto node2 = node(); + auto node3 = node(); auto combined = replace<1>(node1, replace<1>(node2, node3)); - static_assert(std::is_same_v()), std::tuple, std::index_sequence<1, 2, 3>>>); - static_assert(std::is_same_v()), std::tuple, std::index_sequence<1, 2>>>); - static_assert(std::is_same_v()), std::tuple, std::index_sequence<1>>>); - static_assert(std::is_same_v()), std::tuple, std::index_sequence<>>>); + static_assert(std::is_same_v()), std::tuple, std::index_sequence<1, 2, 3>>>); + static_assert(std::is_same_v()), std::tuple, std::index_sequence<1, 2>>>); + static_assert(std::is_same_v()), std::tuple, std::index_sequence<1>>>); + static_assert(std::is_same_v()), std::tuple, std::index_sequence<>>>); auto combined2 = replace<1>(node2, node3); - static_assert(std::is_same_v()), std::tuple, std::index_sequence<1>, std::index_sequence<2>>>); - static_assert(std::is_same_v()), std::tuple, std::index_sequence<1>, std::index_sequence<>>>); - static_assert(std::is_same_v()), std::tuple, std::index_sequence<>, std::index_sequence<>>>); + static_assert(std::is_same_v()), std::tuple, std::index_sequence<1>, std::index_sequence<2>>>); + static_assert(std::is_same_v()), std::tuple, std::index_sequence<1>, std::index_sequence<>>>); + static_assert(std::is_same_v()), std::tuple, std::index_sequence<>, std::index_sequence<>>>); } +TEST(connectSecondaryImpl, getIndicesWithPrimary) +{ + auto node1 = node(); + auto node2 = node(); + auto node3 = node(); + + auto combined = replace<1>(node1, replace<1>(node2, node3)); + + static_assert(std::is_same_v()), std::tuple, std::index_sequence<1, 2, 3>>>); + static_assert(std::is_same_v()), std::tuple, std::index_sequence<1, 2>>>); + static_assert(std::is_same_v()), std::tuple, std::index_sequence<1>>>); + static_assert(std::is_same_v()), std::tuple, std::index_sequence<>>>); + + auto combined2 = replace<1>(node2, node3); + + static_assert(std::is_same_v()), std::tuple, std::index_sequence<1>, std::index_sequence<2>>>); + static_assert(std::is_same_v()), std::tuple, std::index_sequence<1>, std::index_sequence<>>>); + static_assert(std::is_same_v()), std::tuple, std::index_sequence<>, std::index_sequence<>>>); +} TEST(connectNew, connectSecondaryImpl) { - const auto node1 = makeNode(DummyOp()); - const auto node2 = makeNode(DummyOp()); - const auto node3 = makeNode(DummyOp()); + const auto node1 = node(); + const auto node2 = node(); + const auto node3 = node(); { - auto result = connectSecondaryImpl(node1, node1); + auto result = pipes::connectSecondaryImpl(node1, node1); auto expected = replace<0>(node1, node1); static_assert(std::is_same_v); } { - auto result = connectSecondaryImpl(node2, node1, node2); + auto result = pipes::connectSecondaryImpl(node2, node1, node2); auto expected = replace<1>(replace<0>(node2, node1), node2); static_assert(std::is_same_v); } { - auto result = connectSecondaryImpl(node3, node1, node2); + auto result = pipes::connectSecondaryImpl(node3, node1, node2); auto expected = replace<1>(replace<0>(node3, node1), node2); static_assert(std::is_same_v); } } TEST(connectNew, connect_secondary) { - const auto node1 = makeNode(DummyOp()); - const auto node2 = makeNode(DummyOp()); - const auto node3 = makeNode(DummyOp()); + const auto node1 = node(); + const auto node2 = node(); + const auto node3 = node(); { - auto result = connectImpl(secondary_constant(), node1, node1); + auto result = pipes::connectImpl(pipes::secondary_constant(), node1, node1); auto expected = replace<0>(node1, node1); static_assert(std::is_same_v); } { - auto result = connectImpl(secondary_constant(), node2, node1, node2); + auto result = pipes::connectImpl(pipes::secondary_constant(), node2, node1, node2); auto expected = replace<1>(replace<0>(node2, node1), node2); static_assert(std::is_same_v); } { - auto result = connectImpl(secondary_constant(), node3, node1, node2); + auto result = pipes::connectImpl(pipes::secondary_constant(), node3, node1, node2); auto expected = replace<1>(replace<0>(node3, node1), node2); static_assert(std::is_same_v); } } + + +template +constexpr auto nodeT() +{ + return pipes::Type())>(); +} + +template +constexpr bool isNode(pipes::Type) +{ + return pipes::canPrimaryConnect> == hasPrimary && pipes::openCount> == secondaries; +} + +#define T(x) pipes::Type() + +TEST(connectNew, counts) +{ + const auto f1 = node(); + const auto f2 = node(); + const auto f3 = node(); + + const auto t1 = node(); + const auto t2 = node(); + const auto t3 = node(); + + static_assert(isNode(T(f1))); + static_assert(isNode(T(f2))); + static_assert(isNode(T(f3))); + + static_assert(isNode(T(t1))); + static_assert(isNode(T(t2))); + static_assert(isNode(T(t3))); + + { + const auto n = pipes::connectPrimary(node(), node()); + static_assert(isNode(T(n))); + } + { + const auto n = pipes::connectPrimary(node(), node()); + static_assert(isNode(T(n))); + } + { + const auto n = pipes::connectPrimary(node(), node()); + static_assert(isNode(T(n))); + } + { + const auto n = pipes::connectPrimary(node(), node()); + static_assert(isNode(T(n))); + } + //secondary + { + const auto n = pipes::connectSecondary(node(), node()); + static_assert(isNode(T(n))); + } + { + const auto n = pipes::connectSecondary(node(), node()); + static_assert(isNode(T(n))); + } +} diff --git a/test/src/detail/is_node.hpp b/test/src/detail/is_node.hpp index 0a6dcdf..69d5db2 100644 --- a/test/src/detail/is_node.hpp +++ b/test/src/detail/is_node.hpp @@ -3,8 +3,8 @@ template struct is_node : std::false_type {}; -template -struct is_node> : std::true_type {}; +template +struct is_node> : std::true_type {}; template constexpr auto is_node_v = is_node::value; diff --git a/test/src/pipes.cpp b/test/src/pipes.cpp index 5d809f7..82a5894 100644 --- a/test/src/pipes.cpp +++ b/test/src/pipes.cpp @@ -532,11 +532,84 @@ TEST_F(placeholders, tee) auto result2 = std::vector{}; auto halfPipe = tee(_) >>= transform(Transform()) >>= result2; - - //base >>= halfPipe(result1); + + base >>= halfPipe(result1); const auto expected1 = base; const auto expected2 = Transform().each(base); EXPECT_EQ(result1, expected1); EXPECT_EQ(result2, expected2); } + +TEST_F(placeholders, demux) +{ + const std::vector base = {1,2,3,4,5}; + auto result1 = std::vector{}; + auto result2 = std::vector{}; + auto result3 = std::vector{}; + + auto halfPipe = demux(_, transform(Transform()) >>= result2, _); + + base >>= halfPipe(result1, filter(Filter()) >>= result3); + + const auto expected1 = base; + const auto expected2 = Transform().each(base); + const auto expected3 = Filter().each(base); + EXPECT_EQ(result1, expected1); + EXPECT_EQ(result2, expected2); + EXPECT_EQ(result3, expected3); +} + +TEST_F(placeholders, primaryOpen) +{ + const std::vector base = {1,2,3,4,5}; + auto result1 = std::vector{}; + auto result2 = std::vector{}; + + auto halfPipe = demux(filter(Filter()), transform(Transform())); + auto halfPipe2 = halfPipe(result1); + auto fullPipe = halfPipe2(result2); + + base >>= fullPipe; + + const auto expected1 = Filter().each(base); + const auto expected2 = Transform().each(base); + EXPECT_EQ(result1, expected1); + EXPECT_EQ(result2, expected2); +} + +TEST_F(placeholders, primaryConnectWithOpenSecondaries) +{ + const std::vector base = {1,2,3,4,5}; + auto result1 = std::vector{}; + auto result2 = std::vector{}; + + auto halfPipe = tee(_) >>= demux(_); + auto halfPipe2 = halfPipe(filter(Filter()) >>= result1); + auto fullPipe = halfPipe2(transform(Transform()) >>= result2); + + base >>= fullPipe; + + const auto expected1 = Filter().each(base); + const auto expected2 = Transform().each(base); + EXPECT_EQ(result1, expected1); + EXPECT_EQ(result2, expected2); +} + +TEST_F(placeholders, primaryConnectWithPrimaryOpenInSecondaries) +{ + const std::vector base = {1,2,3,4,5}; + auto result1 = std::vector{}; + auto result2 = std::vector{}; + + auto halfPipe = tee(filter(Filter())) >>= demux(transform(Transform())); + auto halfPipe2 = halfPipe( result1); + auto fullPipe = halfPipe2( result2); + + base >>= fullPipe; + + const auto expected1 = Filter().each(base); + const auto expected2 = Transform().each(base); + EXPECT_EQ(result1, expected1); + EXPECT_EQ(result2, expected2); +}