]> git.sesse.net Git - casparcg/blob - concrt_extras/connect.h
dependencies: Cleanup
[casparcg] / concrt_extras / connect.h
1 //--------------------------------------------------------------------------\r
2 // \r
3 //  Copyright (c) Microsoft Corporation.  All rights reserved. \r
4 // \r
5 //  File: connect.h\r
6 //\r
7 //  connect / disconnect helper functions\r
8 //\r
9 //--------------------------------------------------------------------------\r
10 #pragma once\r
11 #include <type_traits>\r
12 #include <agents.h>\r
13 \r
14 namespace Concurrency\r
15 {\r
16         namespace details\r
17         {   \r
18             //details for the connect type traits\r
19 \r
20             //creates a has_member_foo class which can be used to check\r
21             //for a named member variable\r
22             #define DEFINE_HAS_MEMBER(NAME)                                             \\r
23             template <typename T> class has_member_ ## NAME {                           \\r
24             private:                                                                    \\r
25                 template <typename U> static std::true_type helper(decltype(&U::NAME)); \\r
26                 template <typename U> static std::false_type helper(...);               \\r
27                 typedef decltype(helper<T>(nullptr)) helper_t;                          \\r
28             public:                                                                     \\r
29                 static const bool value = helper_t::value;                              \\r
30             };\r
31 \r
32             //define input_buffer & output_buffer classes\r
33             DEFINE_HAS_MEMBER(input_buffer)\r
34             DEFINE_HAS_MEMBER(output_buffer)\r
35 \r
36                 //there must be an existing type trait for this\r
37             template<const bool value_type>\r
38             struct _is_true : std::false_type\r
39             {\r
40             };\r
41 \r
42             template<>\r
43             struct _is_true<true> : std::true_type\r
44             {\r
45             };\r
46 \r
47             //_as_ref normalizes an instance of a class to a reference parameter.\r
48             //this works with pointers, references and values, but probably not with\r
49             //pointer to pointer and definitely not with shared pointers\r
50             template<typename T>\r
51             class _as_ref\r
52             {\r
53                 _as_ref & operator=(const _as_ref & );\r
54 \r
55             public:\r
56                 typedef T type;\r
57                 //_as_ref(T& t): ref(t){}\r
58                 _as_ref(T& t): ref(t){}\r
59                 _as_ref(T* t): ref(*t){}\r
60                 typename std::add_const<typename std::add_reference<T>::type>::type& ref;\r
61             };\r
62 \r
63             //_as_ref normalizes an instance of a class to a reference parameter.\r
64             template <typename T>\r
65             class as_ref : public _as_ref<typename std::remove_pointer<T>::type>\r
66             {\r
67                 as_ref & operator=( const as_ref & );\r
68             public:\r
69                 as_ref(T& t):_as_ref(t){}\r
70             };\r
71 \r
72         }// end details namespace\r
73 \r
74         using namespace details;\r
75         //type traits, determines if a class acts as a compound message target\r
76         template<typename target_type>\r
77         struct is_compound_target\r
78             : _is_true<has_member_input_buffer<typename std::remove_cv<target_type>::type>::value>\r
79         {\r
80         };\r
81 \r
82         //type traits, determines if a class acts as a compound message source\r
83         template<typename source_type>\r
84         struct is_compound_source\r
85             : _is_true<has_member_output_buffer<typename std::remove_cv<source_type>::type>::value>\r
86         {\r
87         };\r
88 \r
89         //connects two message blocks or compound message blocks forward declaration\r
90         template<typename source_type, typename target_type>\r
91         inline void connect(source_type& source, target_type& target);\r
92 \r
93         //disconnects two message blocks or compound message blocks forward declaration\r
94         template<typename source_type, typename target_type>\r
95         inline void disconnect(source_type& source, target_type& target);\r
96 \r
97         namespace details\r
98         {\r
99             //connects an ISource to an ITarget\r
100             template <typename source_block, typename target_block>\r
101             inline void connect_to_target_impl(source_block& source, target_block& target)\r
102             {\r
103                 source.link_target(&target);\r
104             }\r
105             //connect a simple source to a simple target\r
106             template<typename source_type, typename target_type>\r
107             inline void connect_impl(source_type& source, std::false_type /*not_compound_source*/, \r
108                 target_type& target, std::false_type /*not_compound_target*/)\r
109             {\r
110                 connect_to_target_impl(source,target);\r
111             }\r
112 \r
113             //connect a simple source to a compound target\r
114             template<typename source_type, typename target_type>\r
115             inline void connect_impl(source_type& source, std::false_type /*not_compound_source*/, \r
116                 target_type& target, std::true_type /*is_compound_target*/)\r
117             {\r
118                 samples::connect(source, target.input_buffer);\r
119             }\r
120 \r
121             //connect a compound source to a simple target\r
122             template<typename source_type, typename target_type>\r
123             inline void connect_impl(source_type& source, std::true_type  /*not_compound_source*/, \r
124                 target_type& target, std::false_type /*is_compound_target*/)\r
125             {\r
126                 samples::connect(source.output_buffer, target);\r
127             }\r
128 \r
129             //connect a compound source to a compound target\r
130             template<typename source_type, typename target_type>\r
131             inline void connect_impl(source_type& source, std::true_type /*not_compound_source*/, \r
132                 target_type& target, std::true_type /*is_compound_target*/)\r
133             {\r
134                 samples::connect(source.output_buffer, target.input_buffer);\r
135             }\r
136 \r
137             //connect_impl function that works with 'as_ref' types, this function\r
138             //relies on overloading and is_compound_source/target type traits to resolve\r
139             //to simple message blocks\r
140             template<typename source_type, typename target_type>\r
141             inline void connect_impl(const source_type& source, const target_type& target)\r
142             {\r
143                 connect_impl(source.ref, is_compound_source<typename source_type::type>(),\r
144                     target.ref, is_compound_target<typename target_type::type>());\r
145             }\r
146 \r
147             template <typename source_block, typename target_block>\r
148             inline void disconnect_from_target_impl(source_block& source, target_block& target)\r
149             {\r
150                 source.unlink_target(&target);\r
151             }\r
152             //disconnect a source from a target, neither of which is a compound source or target\r
153             template<typename source_type, typename target_type>\r
154             inline void disconnect_impl(source_type& source, std::false_type /*not_compound_source*/, \r
155                 target_type& target, std::false_type /*not_compound_target*/)\r
156             {\r
157                 disconnect_from_target_impl(source,target);\r
158             }\r
159             //disconnect a simple source to a compound target\r
160             template<typename source_type, typename target_type>\r
161             inline void disconnect_impl(source_type& source, std::false_type /*not_compound_source*/, \r
162                 target_type& target, std::true_type  /*is_compound_target*/)\r
163             {\r
164                 samples::disconnect(source, target.input_buffer);\r
165             }\r
166             //disconnect a compound source from a simple target\r
167             template<typename source_type, typename target_type>\r
168             inline void disconnect_impl(source_type& source, std::true_type  /*not_compound_source*/, \r
169                 target_type& target, std::false_type /*is_compound_target*/)\r
170             {\r
171                 samples::disconnect(source.output_buffer, target);\r
172             }\r
173 \r
174             //disconnect a compound source from a compound target\r
175             template<typename source_type, typename target_type>\r
176             inline void disconnect_impl(source_type& source, std::true_type /*not_compound_source*/, \r
177                 target_type& target, std::true_type /*is_compound_target*/)\r
178             {\r
179                 samples::disconnect(source.output_buffer, target.input_buffer);\r
180             }\r
181 \r
182             //disconnect impl has pointers removed already these are as_ref types\r
183             template<typename source_type, typename target_type>\r
184             inline void disconnect_impl(const source_type& source, const target_type& target)\r
185             {\r
186                 //first pass remove pointers\r
187                 disconnect_impl(source.ref, is_compound_source<typename source_type::type>(),\r
188                     target.ref, is_compound_target<typename target_type::type>());\r
189             }\r
190             template<typename source_type>\r
191             inline void disconnect_all_impl(source_type& source, std::false_type/*not_compound_source*/)\r
192             {\r
193                 source.unlink_targets();\r
194             }\r
195             template<typename source_type>\r
196             inline void disconnect_all_impl(source_type& source, std::true_type /*is_compound_source*/)\r
197             {\r
198                 samples::disconnect(source.output_buffer);\r
199             }\r
200             template<typename source_type>\r
201             inline void disconnect_all_impl(source_type& source)\r
202             {\r
203                 details::disconnect_all_impl(source.ref, is_compound_source<typename source_type::type>());\r
204             }\r
205 \r
206         }// end details namespace\r
207 \r
208         //connects two message blocks or compound message blocks\r
209         template<typename source_type, typename target_type>\r
210         inline void connect(source_type& source, target_type& target)\r
211         {\r
212             details::connect_impl(as_ref<source_type>(source), as_ref<target_type>(target));\r
213         }\r
214 \r
215         //disconnects two message blocks or compound message blocks\r
216         template<typename source_type, typename target_type>\r
217         inline void disconnect(source_type& source, target_type& target)\r
218         {\r
219             details::disconnect_impl(as_ref<source_type>(source), as_ref<target_type>(target));\r
220         }\r
221 \r
222         //connects two message blocks or compound message blocks, source is shared_ptr\r
223         template<typename source_type, typename target_type>\r
224         inline void connect(std::shared_ptr<source_type>& source_ptr, target_type& target)\r
225         {\r
226             details::connect_impl(as_ref<source_type>(*source_ptr.get()), as_ref<target_type>(target));\r
227         }\r
228 \r
229         //connects two message blocks or compound message blocks both shared ptrs\r
230         template<typename source_type, typename target_type>\r
231         inline void connect(std::shared_ptr<source_type>& source_ptr, std::shared_ptr<target_type>& target_ptr)\r
232         {\r
233             details::connect_impl(as_ref<source_type>(*source_ptr.get()), as_ref<target_type>(*target_ptr.get()));\r
234         }\r
235 \r
236         //connects two message blocks or compound message blocks target is shared_ptr\r
237         template<typename source_type, typename target_type>\r
238         inline void connect(source_type& source, std::shared_ptr<target_type>& target_ptr)\r
239         {\r
240             details::connect_impl(as_ref<source_type>(source), as_ref<target_type>(*target_ptr.get()));\r
241         }\r
242 \r
243         //connects two message blocks or compound message blocks, source is shared_ptr\r
244         template<typename source_type, typename target_type>\r
245         inline void disconnect(std::shared_ptr<source_type>& source_ptr, target_type& target)\r
246         {\r
247             details::disconnect_impl(as_ref<source_type>(*source_ptr.get()), as_ref<target_type>(target));\r
248         }\r
249 \r
250         //connects two message blocks or compound message blocks both shared ptrs\r
251         template<typename source_type, typename target_type>\r
252         inline void disconnect(std::shared_ptr<source_type>& source_ptr, std::shared_ptr<target_type>& target_ptr)\r
253         {\r
254             details::disconnect_impl(as_ref<source_type>(*source_ptr.get()), as_ref<target_type>(*target_ptr.get()));\r
255         }\r
256 \r
257         //connects two message blocks or compound message blocks target is shared_ptr\r
258         template<typename source_type, typename target_type>\r
259         inline void disconnect(source_type& source, std::shared_ptr<target_type>& target_ptr)\r
260         {\r
261             details::disconnect_impl(as_ref<source_type>(source), as_ref<target_type>(*target_ptr.get()));\r
262         }\r
263 \r
264         //disconnects all connected targets\r
265         template<typename source_type>\r
266         inline void disconnect(source_type& source)\r
267         {\r
268             details::disconnect_all_impl(as_ref<source_type>(source));\r
269         }\r
270 \r
271         //disconnects a message block that is a shared_ptr\r
272         template<typename source_type>\r
273         inline void disconnect(std::shared_ptr<source_type>& source_ptr)\r
274         {\r
275             details::disconnect_all_impl(as_ref<source_type>(*source_ptr.get()));\r
276         }\r
277 }