1 //--------------------------------------------------------------------------
\r
3 // Copyright (c) Microsoft Corporation. All rights reserved.
\r
7 // connect / disconnect helper functions
\r
9 //--------------------------------------------------------------------------
\r
11 #include <type_traits>
\r
14 namespace Concurrency
\r
18 //details for the connect type traits
\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
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
29 static const bool value = helper_t::value; \
\r
32 //define input_buffer & output_buffer classes
\r
33 DEFINE_HAS_MEMBER(input_buffer)
\r
34 DEFINE_HAS_MEMBER(output_buffer)
\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
43 struct _is_true<true> : std::true_type
\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
53 _as_ref & operator=(const _as_ref & );
\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
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
67 as_ref & operator=( const as_ref & );
\r
69 as_ref(T& t):_as_ref(t){}
\r
72 }// end details namespace
\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
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
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
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
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
103 source.link_target(&target);
\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
110 connect_to_target_impl(source,target);
\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
118 samples::connect(source, target.input_buffer);
\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
126 samples::connect(source.output_buffer, target);
\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
134 samples::connect(source.output_buffer, target.input_buffer);
\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
143 connect_impl(source.ref, is_compound_source<typename source_type::type>(),
\r
144 target.ref, is_compound_target<typename target_type::type>());
\r
147 template <typename source_block, typename target_block>
\r
148 inline void disconnect_from_target_impl(source_block& source, target_block& target)
\r
150 source.unlink_target(&target);
\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
157 disconnect_from_target_impl(source,target);
\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
164 samples::disconnect(source, target.input_buffer);
\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
171 samples::disconnect(source.output_buffer, target);
\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
179 samples::disconnect(source.output_buffer, target.input_buffer);
\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
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
190 template<typename source_type>
\r
191 inline void disconnect_all_impl(source_type& source, std::false_type/*not_compound_source*/)
\r
193 source.unlink_targets();
\r
195 template<typename source_type>
\r
196 inline void disconnect_all_impl(source_type& source, std::true_type /*is_compound_source*/)
\r
198 samples::disconnect(source.output_buffer);
\r
200 template<typename source_type>
\r
201 inline void disconnect_all_impl(source_type& source)
\r
203 details::disconnect_all_impl(source.ref, is_compound_source<typename source_type::type>());
\r
206 }// end details namespace
\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
212 details::connect_impl(as_ref<source_type>(source), as_ref<target_type>(target));
\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
219 details::disconnect_impl(as_ref<source_type>(source), as_ref<target_type>(target));
\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
226 details::connect_impl(as_ref<source_type>(*source_ptr.get()), as_ref<target_type>(target));
\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
233 details::connect_impl(as_ref<source_type>(*source_ptr.get()), as_ref<target_type>(*target_ptr.get()));
\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
240 details::connect_impl(as_ref<source_type>(source), as_ref<target_type>(*target_ptr.get()));
\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
247 details::disconnect_impl(as_ref<source_type>(*source_ptr.get()), as_ref<target_type>(target));
\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
254 details::disconnect_impl(as_ref<source_type>(*source_ptr.get()), as_ref<target_type>(*target_ptr.get()));
\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
261 details::disconnect_impl(as_ref<source_type>(source), as_ref<target_type>(*target_ptr.get()));
\r
264 //disconnects all connected targets
\r
265 template<typename source_type>
\r
266 inline void disconnect(source_type& source)
\r
268 details::disconnect_all_impl(as_ref<source_type>(source));
\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
275 details::disconnect_all_impl(as_ref<source_type>(*source_ptr.get()));
\r