149e08aacStbbdev /*
2*b15aabb3Stbbdev     Copyright (c) 2020-2021 Intel Corporation
349e08aacStbbdev 
449e08aacStbbdev     Licensed under the Apache License, Version 2.0 (the "License");
549e08aacStbbdev     you may not use this file except in compliance with the License.
649e08aacStbbdev     You may obtain a copy of the License at
749e08aacStbbdev 
849e08aacStbbdev         http://www.apache.org/licenses/LICENSE-2.0
949e08aacStbbdev 
1049e08aacStbbdev     Unless required by applicable law or agreed to in writing, software
1149e08aacStbbdev     distributed under the License is distributed on an "AS IS" BASIS,
1249e08aacStbbdev     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1349e08aacStbbdev     See the License for the specific language governing permissions and
1449e08aacStbbdev     limitations under the License.
1549e08aacStbbdev */
1649e08aacStbbdev 
1749e08aacStbbdev #ifndef __TBB_flow_graph_node_set_impl_H
1849e08aacStbbdev #define __TBB_flow_graph_node_set_impl_H
1949e08aacStbbdev 
2049e08aacStbbdev #ifndef __TBB_flow_graph_H
2149e08aacStbbdev #error Do not #include this internal file directly; use public TBB headers instead.
2249e08aacStbbdev #endif
2349e08aacStbbdev 
2449e08aacStbbdev // Included in namespace tbb::detail::d1 (in flow_graph.h)
2549e08aacStbbdev 
2649e08aacStbbdev #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
2749e08aacStbbdev // Visual Studio 2019 reports an error while calling predecessor_selector::get and successor_selector::get
2849e08aacStbbdev // Seems like the well-formed expression in trailing decltype is treated as ill-formed
2949e08aacStbbdev // TODO: investigate problems with decltype in trailing return types or find the cross-platform solution
3049e08aacStbbdev #define __TBB_MSVC_DISABLE_TRAILING_DECLTYPE (_MSC_VER >= 1900)
3149e08aacStbbdev 
3249e08aacStbbdev namespace order {
3349e08aacStbbdev struct undefined {};
3449e08aacStbbdev struct following {};
3549e08aacStbbdev struct preceding {};
3649e08aacStbbdev }
3749e08aacStbbdev 
3849e08aacStbbdev class get_graph_helper {
3949e08aacStbbdev public:
4049e08aacStbbdev     // TODO: consider making graph_reference() public and consistent interface to get a reference to the graph
4149e08aacStbbdev     // and remove get_graph_helper
4249e08aacStbbdev     template <typename T>
get(const T & object)4349e08aacStbbdev     static graph& get(const T& object) {
4449e08aacStbbdev         return get_impl(object, std::is_base_of<graph_node, T>());
4549e08aacStbbdev     }
4649e08aacStbbdev 
4749e08aacStbbdev private:
4849e08aacStbbdev     // Get graph from the object of type derived from graph_node
4949e08aacStbbdev     template <typename T>
get_impl(const T & object,std::true_type)5049e08aacStbbdev     static graph& get_impl(const T& object, std::true_type) {
5149e08aacStbbdev         return static_cast<const graph_node*>(&object)->my_graph;
5249e08aacStbbdev     }
5349e08aacStbbdev 
5449e08aacStbbdev     template <typename T>
get_impl(const T & object,std::false_type)5549e08aacStbbdev     static graph& get_impl(const T& object, std::false_type) {
5649e08aacStbbdev         return object.graph_reference();
5749e08aacStbbdev     }
5849e08aacStbbdev };
5949e08aacStbbdev 
6049e08aacStbbdev template<typename Order, typename... Nodes>
6149e08aacStbbdev struct node_set {
6249e08aacStbbdev     typedef Order order_type;
6349e08aacStbbdev 
6449e08aacStbbdev     std::tuple<Nodes&...> nodes;
node_setnode_set6549e08aacStbbdev     node_set(Nodes&... ns) : nodes(ns...) {}
6649e08aacStbbdev 
6749e08aacStbbdev     template <typename... Nodes2>
node_setnode_set6849e08aacStbbdev     node_set(const node_set<order::undefined, Nodes2...>& set) : nodes(set.nodes) {}
6949e08aacStbbdev 
graph_referencenode_set7049e08aacStbbdev     graph& graph_reference() const {
7149e08aacStbbdev         return get_graph_helper::get(std::get<0>(nodes));
7249e08aacStbbdev     }
7349e08aacStbbdev };
7449e08aacStbbdev 
7549e08aacStbbdev namespace alias_helpers {
7649e08aacStbbdev template <typename T> using output_type = typename T::output_type;
7749e08aacStbbdev template <typename T> using output_ports_type = typename T::output_ports_type;
7849e08aacStbbdev template <typename T> using input_type = typename T::input_type;
7949e08aacStbbdev template <typename T> using input_ports_type = typename T::input_ports_type;
8049e08aacStbbdev } // namespace alias_helpers
8149e08aacStbbdev 
8249e08aacStbbdev template <typename T>
8349e08aacStbbdev using has_output_type = supports<T, alias_helpers::output_type>;
8449e08aacStbbdev 
8549e08aacStbbdev template <typename T>
8649e08aacStbbdev using has_input_type = supports<T, alias_helpers::input_type>;
8749e08aacStbbdev 
8849e08aacStbbdev template <typename T>
8949e08aacStbbdev using has_input_ports_type = supports<T, alias_helpers::input_ports_type>;
9049e08aacStbbdev 
9149e08aacStbbdev template <typename T>
9249e08aacStbbdev using has_output_ports_type = supports<T, alias_helpers::output_ports_type>;
9349e08aacStbbdev 
9449e08aacStbbdev template<typename T>
9549e08aacStbbdev struct is_sender : std::is_base_of<sender<typename T::output_type>, T> {};
9649e08aacStbbdev 
9749e08aacStbbdev template<typename T>
9849e08aacStbbdev struct is_receiver : std::is_base_of<receiver<typename T::input_type>, T> {};
9949e08aacStbbdev 
10049e08aacStbbdev template <typename Node>
10149e08aacStbbdev struct is_async_node : std::false_type {};
10249e08aacStbbdev 
10349e08aacStbbdev template <typename... Args>
10449e08aacStbbdev struct is_async_node<async_node<Args...>> : std::true_type {};
10549e08aacStbbdev 
10649e08aacStbbdev template<typename FirstPredecessor, typename... Predecessors>
10749e08aacStbbdev node_set<order::following, FirstPredecessor, Predecessors...>
10849e08aacStbbdev follows(FirstPredecessor& first_predecessor, Predecessors&... predecessors) {
10949e08aacStbbdev     static_assert((conjunction<has_output_type<FirstPredecessor>,
11049e08aacStbbdev                                                    has_output_type<Predecessors>...>::value),
11149e08aacStbbdev                         "Not all node's predecessors has output_type typedef");
11249e08aacStbbdev     static_assert((conjunction<is_sender<FirstPredecessor>, is_sender<Predecessors>...>::value),
11349e08aacStbbdev                         "Not all node's predecessors are senders");
11449e08aacStbbdev     return node_set<order::following, FirstPredecessor, Predecessors...>(first_predecessor, predecessors...);
11549e08aacStbbdev }
11649e08aacStbbdev 
11749e08aacStbbdev template<typename... Predecessors>
11849e08aacStbbdev node_set<order::following, Predecessors...>
11949e08aacStbbdev follows(node_set<order::undefined, Predecessors...>& predecessors_set) {
12049e08aacStbbdev     static_assert((conjunction<has_output_type<Predecessors>...>::value),
12149e08aacStbbdev                         "Not all nodes in the set has output_type typedef");
12249e08aacStbbdev     static_assert((conjunction<is_sender<Predecessors>...>::value),
12349e08aacStbbdev                         "Not all nodes in the set are senders");
12449e08aacStbbdev     return node_set<order::following, Predecessors...>(predecessors_set);
12549e08aacStbbdev }
12649e08aacStbbdev 
12749e08aacStbbdev template<typename FirstSuccessor, typename... Successors>
12849e08aacStbbdev node_set<order::preceding, FirstSuccessor, Successors...>
12949e08aacStbbdev precedes(FirstSuccessor& first_successor, Successors&... successors) {
13049e08aacStbbdev     static_assert((conjunction<has_input_type<FirstSuccessor>,
13149e08aacStbbdev                                                     has_input_type<Successors>...>::value),
13249e08aacStbbdev                         "Not all node's successors has input_type typedef");
13349e08aacStbbdev     static_assert((conjunction<is_receiver<FirstSuccessor>, is_receiver<Successors>...>::value),
13449e08aacStbbdev                         "Not all node's successors are receivers");
13549e08aacStbbdev     return node_set<order::preceding, FirstSuccessor, Successors...>(first_successor, successors...);
13649e08aacStbbdev }
13749e08aacStbbdev 
13849e08aacStbbdev template<typename... Successors>
13949e08aacStbbdev node_set<order::preceding, Successors...>
14049e08aacStbbdev precedes(node_set<order::undefined, Successors...>& successors_set) {
14149e08aacStbbdev     static_assert((conjunction<has_input_type<Successors>...>::value),
14249e08aacStbbdev                         "Not all nodes in the set has input_type typedef");
14349e08aacStbbdev     static_assert((conjunction<is_receiver<Successors>...>::value),
14449e08aacStbbdev                         "Not all nodes in the set are receivers");
14549e08aacStbbdev     return node_set<order::preceding, Successors...>(successors_set);
14649e08aacStbbdev }
14749e08aacStbbdev 
14849e08aacStbbdev template <typename Node, typename... Nodes>
14949e08aacStbbdev node_set<order::undefined, Node, Nodes...>
15049e08aacStbbdev make_node_set(Node& first_node, Nodes&... nodes) {
15149e08aacStbbdev     return node_set<order::undefined, Node, Nodes...>(first_node, nodes...);
15249e08aacStbbdev }
15349e08aacStbbdev 
15449e08aacStbbdev template<size_t I>
15549e08aacStbbdev class successor_selector {
15649e08aacStbbdev     template <typename NodeType>
15749e08aacStbbdev     static auto get_impl(NodeType& node, std::true_type) -> decltype(input_port<I>(node)) {
15849e08aacStbbdev         return input_port<I>(node);
15949e08aacStbbdev     }
16049e08aacStbbdev 
16149e08aacStbbdev     template <typename NodeType>
16249e08aacStbbdev     static NodeType& get_impl(NodeType& node, std::false_type) { return node; }
16349e08aacStbbdev 
16449e08aacStbbdev public:
16549e08aacStbbdev     template <typename NodeType>
16649e08aacStbbdev #if __TBB_MSVC_DISABLE_TRAILING_DECLTYPE
16749e08aacStbbdev     static auto& get(NodeType& node)
16849e08aacStbbdev #else
16949e08aacStbbdev     static auto get(NodeType& node) -> decltype(get_impl(node, has_input_ports_type<NodeType>()))
17049e08aacStbbdev #endif
17149e08aacStbbdev     {
17249e08aacStbbdev         return get_impl(node, has_input_ports_type<NodeType>());
17349e08aacStbbdev     }
17449e08aacStbbdev };
17549e08aacStbbdev 
17649e08aacStbbdev template<size_t I>
17749e08aacStbbdev class predecessor_selector {
17849e08aacStbbdev     template <typename NodeType>
17949e08aacStbbdev     static auto internal_get(NodeType& node, std::true_type) -> decltype(output_port<I>(node)) {
18049e08aacStbbdev         return output_port<I>(node);
18149e08aacStbbdev     }
18249e08aacStbbdev 
18349e08aacStbbdev     template <typename NodeType>
18449e08aacStbbdev     static NodeType& internal_get(NodeType& node, std::false_type) { return node;}
18549e08aacStbbdev 
18649e08aacStbbdev     template <typename NodeType>
18749e08aacStbbdev #if __TBB_MSVC_DISABLE_TRAILING_DECLTYPE
18849e08aacStbbdev     static auto& get_impl(NodeType& node, std::false_type)
18949e08aacStbbdev #else
19049e08aacStbbdev     static auto get_impl(NodeType& node, std::false_type) -> decltype(internal_get(node, has_output_ports_type<NodeType>()))
19149e08aacStbbdev #endif
19249e08aacStbbdev     {
19349e08aacStbbdev         return internal_get(node, has_output_ports_type<NodeType>());
19449e08aacStbbdev     }
19549e08aacStbbdev 
19649e08aacStbbdev     template <typename AsyncNode>
19749e08aacStbbdev     static AsyncNode& get_impl(AsyncNode& node, std::true_type) { return node; }
19849e08aacStbbdev 
19949e08aacStbbdev public:
20049e08aacStbbdev     template <typename NodeType>
20149e08aacStbbdev #if __TBB_MSVC_DISABLE_TRAILING_DECLTYPE
20249e08aacStbbdev     static auto& get(NodeType& node)
20349e08aacStbbdev #else
20449e08aacStbbdev     static auto get(NodeType& node) -> decltype(get_impl(node, is_async_node<NodeType>()))
20549e08aacStbbdev #endif
20649e08aacStbbdev     {
20749e08aacStbbdev         return get_impl(node, is_async_node<NodeType>());
20849e08aacStbbdev     }
20949e08aacStbbdev };
21049e08aacStbbdev 
21149e08aacStbbdev template<size_t I>
21249e08aacStbbdev class make_edges_helper {
21349e08aacStbbdev public:
21449e08aacStbbdev     template<typename PredecessorsTuple, typename NodeType>
21549e08aacStbbdev     static void connect_predecessors(PredecessorsTuple& predecessors, NodeType& node) {
21649e08aacStbbdev         make_edge(std::get<I>(predecessors), successor_selector<I>::get(node));
21749e08aacStbbdev         make_edges_helper<I - 1>::connect_predecessors(predecessors, node);
21849e08aacStbbdev     }
21949e08aacStbbdev 
22049e08aacStbbdev     template<typename SuccessorsTuple, typename NodeType>
22149e08aacStbbdev     static void connect_successors(NodeType& node, SuccessorsTuple& successors) {
22249e08aacStbbdev         make_edge(predecessor_selector<I>::get(node), std::get<I>(successors));
22349e08aacStbbdev         make_edges_helper<I - 1>::connect_successors(node, successors);
22449e08aacStbbdev     }
22549e08aacStbbdev };
22649e08aacStbbdev 
22749e08aacStbbdev template<>
22849e08aacStbbdev struct make_edges_helper<0> {
22949e08aacStbbdev     template<typename PredecessorsTuple, typename NodeType>
23049e08aacStbbdev     static void connect_predecessors(PredecessorsTuple& predecessors, NodeType& node) {
23149e08aacStbbdev         make_edge(std::get<0>(predecessors), successor_selector<0>::get(node));
23249e08aacStbbdev     }
23349e08aacStbbdev 
23449e08aacStbbdev     template<typename SuccessorsTuple, typename NodeType>
23549e08aacStbbdev     static void connect_successors(NodeType& node, SuccessorsTuple& successors) {
23649e08aacStbbdev         make_edge(predecessor_selector<0>::get(node), std::get<0>(successors));
23749e08aacStbbdev     }
23849e08aacStbbdev };
23949e08aacStbbdev 
24049e08aacStbbdev // TODO: consider adding an overload for making edges between node sets
24149e08aacStbbdev template<typename NodeType, typename OrderFlagType, typename... Args>
24249e08aacStbbdev void make_edges(const node_set<OrderFlagType, Args...>& s, NodeType& node) {
24349e08aacStbbdev     const std::size_t SetSize = std::tuple_size<decltype(s.nodes)>::value;
24449e08aacStbbdev     make_edges_helper<SetSize - 1>::connect_predecessors(s.nodes, node);
24549e08aacStbbdev }
24649e08aacStbbdev 
24749e08aacStbbdev template <typename NodeType, typename OrderFlagType, typename... Args>
24849e08aacStbbdev void make_edges(NodeType& node, const node_set<OrderFlagType, Args...>& s) {
24949e08aacStbbdev     const std::size_t SetSize = std::tuple_size<decltype(s.nodes)>::value;
25049e08aacStbbdev     make_edges_helper<SetSize - 1>::connect_successors(node, s.nodes);
25149e08aacStbbdev }
25249e08aacStbbdev 
25349e08aacStbbdev template <typename NodeType, typename... Nodes>
25449e08aacStbbdev void make_edges_in_order(const node_set<order::following, Nodes...>& ns, NodeType& node) {
25549e08aacStbbdev     make_edges(ns, node);
25649e08aacStbbdev }
25749e08aacStbbdev 
25849e08aacStbbdev template <typename NodeType, typename... Nodes>
25949e08aacStbbdev void make_edges_in_order(const node_set<order::preceding, Nodes...>& ns, NodeType& node) {
26049e08aacStbbdev     make_edges(node, ns);
26149e08aacStbbdev }
26249e08aacStbbdev 
26349e08aacStbbdev #endif  // __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
26449e08aacStbbdev 
26549e08aacStbbdev #endif // __TBB_flow_graph_node_set_impl_H
266