1 /* 2 Copyright (c) 2020-2021 Intel Corporation 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 #ifndef __TBB_flow_graph_node_set_impl_H 18 #define __TBB_flow_graph_node_set_impl_H 19 20 #ifndef __TBB_flow_graph_H 21 #error Do not #include this internal file directly; use public TBB headers instead. 22 #endif 23 24 // Included in namespace tbb::detail::d1 (in flow_graph.h) 25 26 #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET 27 // Visual Studio 2019 reports an error while calling predecessor_selector::get and successor_selector::get 28 // Seems like the well-formed expression in trailing decltype is treated as ill-formed 29 // TODO: investigate problems with decltype in trailing return types or find the cross-platform solution 30 #define __TBB_MSVC_DISABLE_TRAILING_DECLTYPE (_MSC_VER >= 1900) 31 32 namespace order { 33 struct undefined {}; 34 struct following {}; 35 struct preceding {}; 36 } 37 38 class get_graph_helper { 39 public: 40 // TODO: consider making graph_reference() public and consistent interface to get a reference to the graph 41 // and remove get_graph_helper 42 template <typename T> 43 static graph& get(const T& object) { 44 return get_impl(object, std::is_base_of<graph_node, T>()); 45 } 46 47 private: 48 // Get graph from the object of type derived from graph_node 49 template <typename T> 50 static graph& get_impl(const T& object, std::true_type) { 51 return static_cast<const graph_node*>(&object)->my_graph; 52 } 53 54 template <typename T> 55 static graph& get_impl(const T& object, std::false_type) { 56 return object.graph_reference(); 57 } 58 }; 59 60 template<typename Order, typename... Nodes> 61 struct node_set { 62 typedef Order order_type; 63 64 std::tuple<Nodes&...> nodes; 65 node_set(Nodes&... ns) : nodes(ns...) {} 66 67 template <typename... Nodes2> 68 node_set(const node_set<order::undefined, Nodes2...>& set) : nodes(set.nodes) {} 69 70 graph& graph_reference() const { 71 return get_graph_helper::get(std::get<0>(nodes)); 72 } 73 }; 74 75 namespace alias_helpers { 76 template <typename T> using output_type = typename T::output_type; 77 template <typename T> using output_ports_type = typename T::output_ports_type; 78 template <typename T> using input_type = typename T::input_type; 79 template <typename T> using input_ports_type = typename T::input_ports_type; 80 } // namespace alias_helpers 81 82 template <typename T> 83 using has_output_type = supports<T, alias_helpers::output_type>; 84 85 template <typename T> 86 using has_input_type = supports<T, alias_helpers::input_type>; 87 88 template <typename T> 89 using has_input_ports_type = supports<T, alias_helpers::input_ports_type>; 90 91 template <typename T> 92 using has_output_ports_type = supports<T, alias_helpers::output_ports_type>; 93 94 template<typename T> 95 struct is_sender : std::is_base_of<sender<typename T::output_type>, T> {}; 96 97 template<typename T> 98 struct is_receiver : std::is_base_of<receiver<typename T::input_type>, T> {}; 99 100 template <typename Node> 101 struct is_async_node : std::false_type {}; 102 103 template <typename... Args> 104 struct is_async_node<async_node<Args...>> : std::true_type {}; 105 106 template<typename FirstPredecessor, typename... Predecessors> 107 node_set<order::following, FirstPredecessor, Predecessors...> 108 follows(FirstPredecessor& first_predecessor, Predecessors&... predecessors) { 109 static_assert((conjunction<has_output_type<FirstPredecessor>, 110 has_output_type<Predecessors>...>::value), 111 "Not all node's predecessors has output_type typedef"); 112 static_assert((conjunction<is_sender<FirstPredecessor>, is_sender<Predecessors>...>::value), 113 "Not all node's predecessors are senders"); 114 return node_set<order::following, FirstPredecessor, Predecessors...>(first_predecessor, predecessors...); 115 } 116 117 template<typename... Predecessors> 118 node_set<order::following, Predecessors...> 119 follows(node_set<order::undefined, Predecessors...>& predecessors_set) { 120 static_assert((conjunction<has_output_type<Predecessors>...>::value), 121 "Not all nodes in the set has output_type typedef"); 122 static_assert((conjunction<is_sender<Predecessors>...>::value), 123 "Not all nodes in the set are senders"); 124 return node_set<order::following, Predecessors...>(predecessors_set); 125 } 126 127 template<typename FirstSuccessor, typename... Successors> 128 node_set<order::preceding, FirstSuccessor, Successors...> 129 precedes(FirstSuccessor& first_successor, Successors&... successors) { 130 static_assert((conjunction<has_input_type<FirstSuccessor>, 131 has_input_type<Successors>...>::value), 132 "Not all node's successors has input_type typedef"); 133 static_assert((conjunction<is_receiver<FirstSuccessor>, is_receiver<Successors>...>::value), 134 "Not all node's successors are receivers"); 135 return node_set<order::preceding, FirstSuccessor, Successors...>(first_successor, successors...); 136 } 137 138 template<typename... Successors> 139 node_set<order::preceding, Successors...> 140 precedes(node_set<order::undefined, Successors...>& successors_set) { 141 static_assert((conjunction<has_input_type<Successors>...>::value), 142 "Not all nodes in the set has input_type typedef"); 143 static_assert((conjunction<is_receiver<Successors>...>::value), 144 "Not all nodes in the set are receivers"); 145 return node_set<order::preceding, Successors...>(successors_set); 146 } 147 148 template <typename Node, typename... Nodes> 149 node_set<order::undefined, Node, Nodes...> 150 make_node_set(Node& first_node, Nodes&... nodes) { 151 return node_set<order::undefined, Node, Nodes...>(first_node, nodes...); 152 } 153 154 template<size_t I> 155 class successor_selector { 156 template <typename NodeType> 157 static auto get_impl(NodeType& node, std::true_type) -> decltype(input_port<I>(node)) { 158 return input_port<I>(node); 159 } 160 161 template <typename NodeType> 162 static NodeType& get_impl(NodeType& node, std::false_type) { return node; } 163 164 public: 165 template <typename NodeType> 166 #if __TBB_MSVC_DISABLE_TRAILING_DECLTYPE 167 static auto& get(NodeType& node) 168 #else 169 static auto get(NodeType& node) -> decltype(get_impl(node, has_input_ports_type<NodeType>())) 170 #endif 171 { 172 return get_impl(node, has_input_ports_type<NodeType>()); 173 } 174 }; 175 176 template<size_t I> 177 class predecessor_selector { 178 template <typename NodeType> 179 static auto internal_get(NodeType& node, std::true_type) -> decltype(output_port<I>(node)) { 180 return output_port<I>(node); 181 } 182 183 template <typename NodeType> 184 static NodeType& internal_get(NodeType& node, std::false_type) { return node;} 185 186 template <typename NodeType> 187 #if __TBB_MSVC_DISABLE_TRAILING_DECLTYPE 188 static auto& get_impl(NodeType& node, std::false_type) 189 #else 190 static auto get_impl(NodeType& node, std::false_type) -> decltype(internal_get(node, has_output_ports_type<NodeType>())) 191 #endif 192 { 193 return internal_get(node, has_output_ports_type<NodeType>()); 194 } 195 196 template <typename AsyncNode> 197 static AsyncNode& get_impl(AsyncNode& node, std::true_type) { return node; } 198 199 public: 200 template <typename NodeType> 201 #if __TBB_MSVC_DISABLE_TRAILING_DECLTYPE 202 static auto& get(NodeType& node) 203 #else 204 static auto get(NodeType& node) -> decltype(get_impl(node, is_async_node<NodeType>())) 205 #endif 206 { 207 return get_impl(node, is_async_node<NodeType>()); 208 } 209 }; 210 211 template<size_t I> 212 class make_edges_helper { 213 public: 214 template<typename PredecessorsTuple, typename NodeType> 215 static void connect_predecessors(PredecessorsTuple& predecessors, NodeType& node) { 216 make_edge(std::get<I>(predecessors), successor_selector<I>::get(node)); 217 make_edges_helper<I - 1>::connect_predecessors(predecessors, node); 218 } 219 220 template<typename SuccessorsTuple, typename NodeType> 221 static void connect_successors(NodeType& node, SuccessorsTuple& successors) { 222 make_edge(predecessor_selector<I>::get(node), std::get<I>(successors)); 223 make_edges_helper<I - 1>::connect_successors(node, successors); 224 } 225 }; 226 227 template<> 228 struct make_edges_helper<0> { 229 template<typename PredecessorsTuple, typename NodeType> 230 static void connect_predecessors(PredecessorsTuple& predecessors, NodeType& node) { 231 make_edge(std::get<0>(predecessors), successor_selector<0>::get(node)); 232 } 233 234 template<typename SuccessorsTuple, typename NodeType> 235 static void connect_successors(NodeType& node, SuccessorsTuple& successors) { 236 make_edge(predecessor_selector<0>::get(node), std::get<0>(successors)); 237 } 238 }; 239 240 // TODO: consider adding an overload for making edges between node sets 241 template<typename NodeType, typename OrderFlagType, typename... Args> 242 void make_edges(const node_set<OrderFlagType, Args...>& s, NodeType& node) { 243 const std::size_t SetSize = std::tuple_size<decltype(s.nodes)>::value; 244 make_edges_helper<SetSize - 1>::connect_predecessors(s.nodes, node); 245 } 246 247 template <typename NodeType, typename OrderFlagType, typename... Args> 248 void make_edges(NodeType& node, const node_set<OrderFlagType, Args...>& s) { 249 const std::size_t SetSize = std::tuple_size<decltype(s.nodes)>::value; 250 make_edges_helper<SetSize - 1>::connect_successors(node, s.nodes); 251 } 252 253 template <typename NodeType, typename... Nodes> 254 void make_edges_in_order(const node_set<order::following, Nodes...>& ns, NodeType& node) { 255 make_edges(ns, node); 256 } 257 258 template <typename NodeType, typename... Nodes> 259 void make_edges_in_order(const node_set<order::preceding, Nodes...>& ns, NodeType& node) { 260 make_edges(node, ns); 261 } 262 263 #endif // __TBB_PREVIEW_FLOW_GRAPH_NODE_SET 264 265 #endif // __TBB_flow_graph_node_set_impl_H 266