From dc9fe9e84ec11825d8e45ce5f27288429854729f Mon Sep 17 00:00:00 2001 From: "Boyarinov, Konstantin" Date: Tue, 13 May 2025 14:21:26 +0300 Subject: [PATCH 1/6] Simplify FG deduction guides, add support for new callable types --- .../tbb/detail/_flow_graph_nodes_deduction.h | 95 ++++++------------- 1 file changed, 30 insertions(+), 65 deletions(-) diff --git a/include/oneapi/tbb/detail/_flow_graph_nodes_deduction.h b/include/oneapi/tbb/detail/_flow_graph_nodes_deduction.h index 47ecfb2a84..3337ca4a25 100644 --- a/include/oneapi/tbb/detail/_flow_graph_nodes_deduction.h +++ b/include/oneapi/tbb/detail/_flow_graph_nodes_deduction.h @@ -23,83 +23,55 @@ namespace tbb { namespace detail { namespace d2 { -template -struct declare_body_types { +template +struct declare_input_type { using input_type = Input; - using output_type = Output; -}; - -struct NoInputBody {}; - -template -struct declare_body_types { - using output_type = Output; }; -template struct body_types; - -template -struct body_types : declare_body_types {}; - -template -struct body_types : declare_body_types {}; - -template -struct body_types : declare_body_types {}; - -template -struct body_types : declare_body_types {}; - -template -struct body_types : declare_body_types {}; - -template -struct body_types : declare_body_types {}; +template <> +struct declare_input_type {}; template -struct body_types : declare_body_types {}; +struct body_types : declare_input_type> { + using output_type = std::decay_t; +}; -template -struct body_types : declare_body_types {}; +template +struct extract_member_function_types; -template -struct body_types : declare_body_types {}; +template +struct extract_member_function_types : body_types {}; -template -using input_t = typename body_types::input_type; +template +struct extract_member_function_types : body_types {}; +// Body is represented as a callable object - extract types from the pointer to operator() template -using output_t = typename body_types::output_type; - -template -auto decide_on_operator_overload(Output (T::*name)(const Input&) const)->decltype(name); - -template -auto decide_on_operator_overload(Output (T::*name)(const Input&))->decltype(name); +struct extract_body_types : extract_member_function_types {}; -template -auto decide_on_operator_overload(Output (T::*name)(Input&) const)->decltype(name); - -template -auto decide_on_operator_overload(Output (T::*name)(Input&))->decltype(name); +// Body is represented as a pointer to function +template +struct extract_body_types : body_types {}; +// Body is represented as a pointer to member function template -auto decide_on_operator_overload(Output (*name)(const Input&))->decltype(name); +struct extract_body_types : body_types {}; +// Body is represented as a pointer to member object template -auto decide_on_operator_overload(Output (*name)(Input&))->decltype(name); +struct extract_body_types : body_types {}; template -decltype(decide_on_operator_overload(&Body::operator())) decide_on_callable_type(int); +using input_type = typename extract_body_types::input_type; template -decltype(decide_on_operator_overload(std::declval())) decide_on_callable_type(...); +using output_type = typename extract_body_types::output_type; // Deduction guides for Flow Graph nodes template input_node(GraphOrSet&&, Body) -->input_node(0))>>; +->input_node>; #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET @@ -134,7 +106,7 @@ queue_node(const NodeSet&) template sequencer_node(GraphOrProxy&&, Sequencer) -->sequencer_node(0))>>; +->sequencer_node>; #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET template @@ -181,17 +153,14 @@ join_node(const node_set) template join_node(GraphOrProxy&&, Body, Bodies...) -->join_node(0))>, - input_t(0))>...>, - key_matching(0))>>>>; +->join_node, input_type...>, + key_matching>>>; #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET template indexer_node(const node_set&) ->indexer_node; -#endif -#if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET template limiter_node(const NodeSet&, size_t) ->limiter_node>; @@ -210,16 +179,12 @@ template function_node(GraphOrSet&&, size_t, Body, Policy, node_priority_t = no_priority) -->function_node(0))>, - output_t(0))>, - Policy>; +->function_node, output_type, Policy>; template function_node(GraphOrSet&&, size_t, Body, node_priority_t = no_priority) -->function_node(0))>, - output_t(0))>, - queueing>; +->function_node, output_type, queueing>; template struct continue_output { From e800607257cf39b29297b7c04a5510a686a50cea Mon Sep 17 00:00:00 2001 From: "Boyarinov, Konstantin" Date: Tue, 20 May 2025 15:18:20 +0300 Subject: [PATCH 2/6] Extend tests --- .../tbb/detail/_flow_graph_nodes_deduction.h | 14 +-- test/conformance/conformance_flowgraph.h | 61 +++++++++++++ .../conformance/conformance_function_node.cpp | 86 ++++++++++++++----- .../conformance_sequencer_node.cpp | 49 ++++++++--- test/tbb/test_join_node_key_matching.cpp | 61 +++++++++---- 5 files changed, 216 insertions(+), 55 deletions(-) diff --git a/include/oneapi/tbb/detail/_flow_graph_nodes_deduction.h b/include/oneapi/tbb/detail/_flow_graph_nodes_deduction.h index 3337ca4a25..91dcecd981 100644 --- a/include/oneapi/tbb/detail/_flow_graph_nodes_deduction.h +++ b/include/oneapi/tbb/detail/_flow_graph_nodes_deduction.h @@ -25,29 +25,29 @@ namespace d2 { template struct declare_input_type { - using input_type = Input; + using input_type = std::decay_t; }; template <> struct declare_input_type {}; template -struct body_types : declare_input_type> { +struct body_types : declare_input_type { using output_type = std::decay_t; }; template -struct extract_member_function_types; +struct extract_callable_object_types; template -struct extract_member_function_types : body_types {}; +struct extract_callable_object_types : body_types {}; template -struct extract_member_function_types : body_types {}; +struct extract_callable_object_types : body_types {}; // Body is represented as a callable object - extract types from the pointer to operator() template -struct extract_body_types : extract_member_function_types {}; +struct extract_body_types : extract_callable_object_types {}; // Body is represented as a pointer to function template @@ -55,7 +55,7 @@ struct extract_body_types : body_types {}; // Body is represented as a pointer to member function template -struct extract_body_types : body_types {}; +struct extract_body_types : body_types {}; // Body is represented as a pointer to member object template diff --git a/test/conformance/conformance_flowgraph.h b/test/conformance/conformance_flowgraph.h index 25eb95210d..4bf96fd599 100644 --- a/test/conformance/conformance_flowgraph.h +++ b/test/conformance/conformance_flowgraph.h @@ -811,4 +811,65 @@ void test_with_reserving_join_node_class() { if at least one successor accepts the tuple must consume messages"); } } + +#if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT +namespace deduction_guides_testing { + +template +struct callable_object_body_base { + using input_type = std::decay_t; + using output_type = std::decay_t; +}; + +template +struct callable_object_body : callable_object_body_base { + Output operator()(Input) { return Output{}; } +}; + +template +struct callable_object_body : callable_object_body_base { + Output operator()(Input) const { return Output{}; } +}; + +template +Output function_body(Input) { return Output{}; } + +template +struct Input { + Output member_object_body; + Output member_function_body() const { return Output{}; } +}; + +template +struct read_types { + using input_type = typename Body::input_type; + using output_type = typename Body::output_type; +}; + +template +struct read_types { + using input_type = std::decay_t; + using output_type = std::decay_t; +}; + +template +struct read_types { + using input_type = std::decay_t; + using output_type = std::decay_t; +}; + +template +struct read_types { + using input_type = std::decay_t; + using output_type = std::decay_t; +}; + +template +using input_type = typename read_types::input_type; + +template +using output_type = typename read_types::output_type; + +} // namespace deduction_guides_testing +#endif #endif // __TBB_test_conformance_conformance_flowgraph_H diff --git a/test/conformance/conformance_function_node.cpp b/test/conformance/conformance_function_node.cpp index 332558cf35..0cdc2d35b0 100644 --- a/test/conformance/conformance_function_node.cpp +++ b/test/conformance/conformance_function_node.cpp @@ -32,47 +32,89 @@ using output_msg = conformance::message +struct print; template void test_deduction_guides_common(Body body) { + using input_type = deduction_guides_testing::input_type; + using output_type = deduction_guides_testing::output_type; + using namespace tbb::flow; graph g; function_node f1(g, unlimited, body); - static_assert(std::is_same_v>); + static_assert(std::is_same_v>); - function_node f2(g, unlimited, body, rejecting()); - static_assert(std::is_same_v>); + function_node f2(g, unlimited, body, rejecting{}); + static_assert(std::is_same_v>); - function_node f3(g, unlimited, body, node_priority_t(5)); - static_assert(std::is_same_v>); + function_node f3(g, unlimited, body, node_priority_t{5}); + static_assert(std::is_same_v>); - function_node f4(g, unlimited, body, rejecting(), node_priority_t(5)); - static_assert(std::is_same_v>); + function_node f4(g, unlimited, body, rejecting{}, node_priority_t{5}); + static_assert(std::is_same_v>); #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET - function_node f5(follows(f2), unlimited, body); - static_assert(std::is_same_v>); + function_node> pred_f(g, unlimited, [](int) { + return std::decay_t{}; + }); + + function_node succ_f(g, unlimited, [](const output_type&) { + return 1; + }); + + function_node f5(follows(pred_f), unlimited, body); + static_assert(std::is_same_v>); + + function_node f6(follows(pred_f), unlimited, body, rejecting{}); + static_assert(std::is_same_v>); + + function_node f7(follows(pred_f), unlimited, body, node_priority_t{5}); + static_assert(std::is_same_v>); - function_node f6(follows(f5), unlimited, body, rejecting()); - static_assert(std::is_same_v>); + function_node f8(follows(pred_f), unlimited, body, rejecting{}, node_priority_t{5}); + static_assert(std::is_same_v>); - function_node f7(follows(f6), unlimited, body, node_priority_t(5)); - static_assert(std::is_same_v>); + function_node f9(precedes(succ_f), unlimited, body); + static_assert(std::is_same_v>); - function_node f8(follows(f7), unlimited, body, rejecting(), node_priority_t(5)); - static_assert(std::is_same_v>); -#endif // __TBB_PREVIEW_FLOW_GRAPH_NODE_SET + function_node f10(precedes(succ_f), unlimited, body, rejecting{}); + static_assert(std::is_same_v>); + + function_node f11(precedes(succ_f), unlimited, body, node_priority_t{5}); + static_assert(std::is_same_v>); + + function_node f12(precedes(succ_f), unlimited, body, rejecting{}, node_priority_t{5}); + static_assert(std::is_same_v>); +#endif - function_node f9(f1); - static_assert(std::is_same_v>); + function_node f13(f1); + static_assert(std::is_same_v); +} + +template +void test_deduction_guides_body_types() { + using namespace deduction_guides_testing; + + using mutable_callable_type = callable_object_body; + using const_callable_type = callable_object_body; + test_deduction_guides_common(mutable_callable_type{}); + test_deduction_guides_common(const_callable_type{}); + test_deduction_guides_common(function_body); +#if __TBB_CPP17_INVOKE_PRESENT + using pure_input_type = std::decay_t; + test_deduction_guides_common(&pure_input_type::member_object_body); + test_deduction_guides_common(&pure_input_type::member_function_body); +#endif } void test_deduction_guides() { - test_deduction_guides_common([](const int&)->int { return 1; }); - test_deduction_guides_common([](const int&) mutable ->int { return 1; }); - test_deduction_guides_common(function_body_f); + using output_type = int; + using input_type = deduction_guides_testing::Input; + + test_deduction_guides_body_types(); + test_deduction_guides_body_types(); } #endif diff --git a/test/conformance/conformance_sequencer_node.cpp b/test/conformance/conformance_sequencer_node.cpp index a28fa9e5c1..65ef1a7771 100644 --- a/test/conformance/conformance_sequencer_node.cpp +++ b/test/conformance/conformance_sequencer_node.cpp @@ -30,28 +30,57 @@ #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT template void test_deduction_guides_common(Body body) { + using input_type = deduction_guides_testing::input_type; + static_assert(std::is_same_v, std::size_t>, + "incorrect test setup"); + using namespace tbb::flow; graph g; - broadcast_node br(g); sequencer_node s1(g, body); - static_assert(std::is_same_v>); + static_assert(std::is_same_v>); #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET - sequencer_node s2(follows(br), body); - static_assert(std::is_same_v>); + using pure_input_type = std::decay_t; + function_node pred_f(g, unlimited, [](int) { + return pure_input_type{}; + }); + + function_node succ_f(g, unlimited, [](const pure_input_type&) { + return 1; + }); + + sequencer_node s2(follows(pred_f), body); + static_assert(std::is_same_v>); + + sequencer_node s3(precedes(succ_f), body); + static_assert(std::is_same_v>); #endif - sequencer_node s3(s1); - static_assert(std::is_same_v>); + sequencer_node s4(s1); + static_assert(std::is_same_v); } -std::size_t sequencer_body_f(const int&) { return 1; } +template +void test_deduction_guides_body_types() { + using namespace deduction_guides_testing; + + using mutable_callable_type = callable_object_body; + using const_callable_type = callable_object_body; + test_deduction_guides_common(mutable_callable_type{}); + test_deduction_guides_common(const_callable_type{}); + test_deduction_guides_common(function_body); +#if __TBB_CPP17_INVOKE_PRESENT + using pure_input_type = std::decay_t; + test_deduction_guides_common(&pure_input_type::member_object_body); + test_deduction_guides_common(&pure_input_type::member_function_body); +#endif +} void test_deduction_guides() { - test_deduction_guides_common([](const int&)->std::size_t { return 1; }); - test_deduction_guides_common([](const int&) mutable ->std::size_t { return 1; }); - test_deduction_guides_common(sequencer_body_f); + using input_type = deduction_guides_testing::Input; + test_deduction_guides_body_types(); + test_deduction_guides_body_types(); } #endif diff --git a/test/tbb/test_join_node_key_matching.cpp b/test/tbb/test_join_node_key_matching.cpp index c930f69df4..cae641c525 100644 --- a/test/tbb/test_join_node_key_matching.cpp +++ b/test/tbb/test_join_node_key_matching.cpp @@ -17,38 +17,67 @@ #include "common/config.h" #include "test_join_node.h" - +#include "conformance/conformance_flowgraph.h" #include "common/concepts_common.h" //! \file test_join_node_key_matching.cpp //! \brief Test for [flow_graph.join_node] specification #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT -void test_deduction_guides() { - using namespace tbb::flow; - using tuple_type = std::tuple; +template +void test_deduction_guides_common(Body port_body) { + using input_type = deduction_guides_testing::input_type; + using key_type = deduction_guides_testing::output_type; + using namespace tbb::flow; graph g; - auto body_int = [](const int&)->int { return 1; }; - auto body_double = [](const double&)->int { return 1; }; - join_node j1(g, body_int, body_int, body_double); - static_assert(std::is_same_v>>); + using pure_input_type = std::decay_t; + using tuple_type = std::tuple; + using policy_type = key_matching; + + join_node j1(g, port_body, port_body); + static_assert(std::is_same_v>); #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET - broadcast_node b1(g), b2(g); - broadcast_node b3(g); - broadcast_node b4(g); + broadcast_node pred1(g); + broadcast_node pred2(g); + + broadcast_node succ(g); - join_node j2(follows(b1, b2, b3), body_int, body_int, body_double); - static_assert(std::is_same_v>>); + join_node j2(follows(pred1, pred2), port_body, port_body); + static_assert(std::is_same_v>); - join_node j3(precedes(b4), body_int, body_int, body_double); - static_assert(std::is_same_v>>); + join_node j3(precedes(succ), port_body, port_body); + static_assert(std::is_same_v>); #endif join_node j4(j1); - static_assert(std::is_same_v>>); + static_assert(std::is_same_v); +} + +template +void test_deduction_guides_body_types() { + using namespace deduction_guides_testing; + + using mutable_callable_type = callable_object_body; + using const_callable_type = callable_object_body; + test_deduction_guides_common(mutable_callable_type{}); + test_deduction_guides_common(const_callable_type{}); + test_deduction_guides_common(function_body); +#if __TBB_CPP17_INVOKE_PRESENT + using pure_input_type = std::decay_t; + test_deduction_guides_common(&pure_input_type::member_object_body); + test_deduction_guides_common(&pure_input_type::member_function_body); +#endif +} + +void test_deduction_guides() { + using key_type = int; + using input_type = deduction_guides_testing::Input; + + test_deduction_guides_body_types(); + test_deduction_guides_body_types(); } #endif From 9aa77c6a55ca5c47803f2f1cc29b2066e5a5301a Mon Sep 17 00:00:00 2001 From: "Boyarinov, Konstantin" Date: Wed, 21 May 2025 13:46:50 +0300 Subject: [PATCH 3/6] Make extract_body_types SFINAE-friendly --- include/oneapi/tbb/detail/_flow_graph_nodes_deduction.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/oneapi/tbb/detail/_flow_graph_nodes_deduction.h b/include/oneapi/tbb/detail/_flow_graph_nodes_deduction.h index 91dcecd981..0c78d9088a 100644 --- a/include/oneapi/tbb/detail/_flow_graph_nodes_deduction.h +++ b/include/oneapi/tbb/detail/_flow_graph_nodes_deduction.h @@ -45,9 +45,13 @@ struct extract_callable_object_types : body_types struct extract_callable_object_types : body_types {}; +template +struct extract_body_types; + // Body is represented as a callable object - extract types from the pointer to operator() template -struct extract_body_types : extract_callable_object_types {}; +struct extract_body_types> + : extract_callable_object_types {}; // Body is represented as a pointer to function template From ecfb51cf68905118775902e3348b3b43da0a5f34 Mon Sep 17 00:00:00 2001 From: "Boyarinov, Konstantin" Date: Thu, 22 May 2025 14:11:15 +0300 Subject: [PATCH 4/6] Add wait_for_all --- test/conformance/conformance_function_node.cpp | 1 + test/conformance/conformance_sequencer_node.cpp | 2 ++ test/tbb/test_join_node_key_matching.cpp | 1 + 3 files changed, 4 insertions(+) diff --git a/test/conformance/conformance_function_node.cpp b/test/conformance/conformance_function_node.cpp index 0cdc2d35b0..189195bf9c 100644 --- a/test/conformance/conformance_function_node.cpp +++ b/test/conformance/conformance_function_node.cpp @@ -91,6 +91,7 @@ void test_deduction_guides_common(Body body) { function_node f13(f1); static_assert(std::is_same_v); + g.wait_for_all(); } template diff --git a/test/conformance/conformance_sequencer_node.cpp b/test/conformance/conformance_sequencer_node.cpp index 65ef1a7771..195b90e8b4 100644 --- a/test/conformance/conformance_sequencer_node.cpp +++ b/test/conformance/conformance_sequencer_node.cpp @@ -59,6 +59,8 @@ void test_deduction_guides_common(Body body) { sequencer_node s4(s1); static_assert(std::is_same_v); + + g.wait_for_all(); } template diff --git a/test/tbb/test_join_node_key_matching.cpp b/test/tbb/test_join_node_key_matching.cpp index cae641c525..08cb064d30 100644 --- a/test/tbb/test_join_node_key_matching.cpp +++ b/test/tbb/test_join_node_key_matching.cpp @@ -54,6 +54,7 @@ void test_deduction_guides_common(Body port_body) { join_node j4(j1); static_assert(std::is_same_v); + g.wait_for_all(); } template From c6b9bb56de8fa58e93b61cf150c3104a42a97121 Mon Sep 17 00:00:00 2001 From: "Boyarinov, Konstantin" Date: Thu, 22 May 2025 14:16:19 +0300 Subject: [PATCH 5/6] Fix copyright --- test/conformance/conformance_function_node.cpp | 2 +- test/conformance/conformance_sequencer_node.cpp | 2 +- test/tbb/test_join_node_key_matching.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/conformance/conformance_function_node.cpp b/test/conformance/conformance_function_node.cpp index 189195bf9c..ef07bae9ea 100644 --- a/test/conformance/conformance_function_node.cpp +++ b/test/conformance/conformance_function_node.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2020-2023 Intel Corporation + Copyright (c) 2020-2025 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/test/conformance/conformance_sequencer_node.cpp b/test/conformance/conformance_sequencer_node.cpp index 195b90e8b4..dd607d380e 100644 --- a/test/conformance/conformance_sequencer_node.cpp +++ b/test/conformance/conformance_sequencer_node.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2020-2023 Intel Corporation + Copyright (c) 2020-2025 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/test/tbb/test_join_node_key_matching.cpp b/test/tbb/test_join_node_key_matching.cpp index 08cb064d30..84b646567d 100644 --- a/test/tbb/test_join_node_key_matching.cpp +++ b/test/tbb/test_join_node_key_matching.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2005-2023 Intel Corporation + Copyright (c) 2005-2025 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. From 6c8de258c995ec6b2c5f7c418b1455d89d3271b6 Mon Sep 17 00:00:00 2001 From: "Boyarinov, Konstantin" Date: Thu, 22 May 2025 14:23:46 +0300 Subject: [PATCH 6/6] Fix copyright for nodes_deduction file --- include/oneapi/tbb/detail/_flow_graph_nodes_deduction.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/oneapi/tbb/detail/_flow_graph_nodes_deduction.h b/include/oneapi/tbb/detail/_flow_graph_nodes_deduction.h index 0c78d9088a..66a8bdf812 100644 --- a/include/oneapi/tbb/detail/_flow_graph_nodes_deduction.h +++ b/include/oneapi/tbb/detail/_flow_graph_nodes_deduction.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2005-2024 Intel Corporation + Copyright (c) 2005-2025 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.