PPI: Allow connecting two MultiConnectorMixin modules
[senf.git] / senf / PPI / MultiConnectorMixin.mpp
1 // $Id$
2 //
3 // Copyright (C) 2009 
4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 //     Stefan Bund <g0dil@berlios.de>
7 //
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 // GNU General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the
20 // Free Software Foundation, Inc.,
21 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22
23 /** \file
24     \brief MultiConnectorMixin Boost.Preprocesser external iteration include */
25
26 #if !BOOST_PP_IS_ITERATING && !defined(MPP_SENF_PPI_MultiConnectorMixin_)
27 #define MPP_SENF_PPI_MultiConnectorMixin_ 1
28
29 // Custom includes
30 #include <boost/preprocessor/iteration/iterate.hpp>
31 #include <boost/preprocessor/control/if.hpp>
32 #include <boost/preprocessor/facilities/empty.hpp> 
33 #include <boost/preprocessor/repetition/enum_params.hpp>
34 #include <boost/preprocessor/repetition/enum_binary_params.hpp>
35 #include <boost/preprocessor/repetition/enum_trailing_params.hpp>
36 #include <boost/preprocessor/repetition/enum_trailing_binary_params.hpp> 
37 #include <boost/type_traits/is_base_of.hpp>
38 #include <boost/mpl/and.hpp>
39 #include <boost/mpl/not.hpp>
40 #include <senf/Utils/type_traits.hh>
41
42 // ///////////////////////////mpp.p////////////////////////////////////////
43 #elif BOOST_PP_IS_ITERATING // ////////////////////////////////////////////
44 // ////////////////////////////////////////////////////////////////////////
45 // Local Macros
46
47 #define mpp_TplParams()                                                 \
48     BOOST_PP_IF(                                                        \
49         BOOST_PP_ITERATION(),                                           \
50         mpp_TplParams_,                                                 \
51         BOOST_PP_EMPTY)()
52 #define mpp_TplParams_()                                                \
53     template <BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(), class A)>
54     
55 #define mpp_TplParamsKomma()                                            \
56     BOOST_PP_ENUM_TRAILING_PARAMS(BOOST_PP_ITERATION(), class A)
57 #define mpp_FnParams()                                                  \
58     BOOST_PP_ENUM_BINARY_PARAMS(BOOST_PP_ITERATION(), A, const & a)
59 #define mpp_FnParamsKomma()                                             \
60     BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(BOOST_PP_ITERATION(), A, const & a)
61 #define mpp_CallParams()                                                \
62     BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(), a)
63 #define mpp_CallParamsKomma()                                           \
64     BOOST_PP_ENUM_TRAILING_PARAMS(BOOST_PP_ITERATION(), a)
65
66 // Same as above but for outer loop in nested loops
67 #define mpp_TplParamsKomma2()                                            \
68     BOOST_PP_ENUM_TRAILING_PARAMS(BOOST_PP_FRAME_ITERATION(1), class B)
69 #define mpp_FnParams2()                                                  \
70     BOOST_PP_ENUM_BINARY_PARAMS(BOOST_PP_FRAME_ITERATION(1), B, const & a)
71 #define mpp_FnParamsKomma2()                                             \
72     BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(BOOST_PP_FRAME_ITERATION(1), B, const & b)
73 #define mpp_CallParams2()                                                \
74     BOOST_PP_ENUM_PARAMS(BOOST_PP_FRAME_ITERATION(1), b)
75 #define mpp_CallParamsKomma2()                                           \
76     BOOST_PP_ENUM_TRAILING_PARAMS(BOOST_PP_FRAME_ITERATION(1), b)
77
78 // ////////////////////////////////////////////////////////////////////////
79 #if BOOST_PP_ITERATION_FLAGS()==1 // //////////////////////////////////////
80 // ////////////////////////////////////////////////////////////////////////
81 // MultiConnectorMixin member declaration
82
83 mpp_TplParams()
84 ConnectorType_ & newConnector( mpp_FnParams() );
85
86 // ////////////////////////////////////////////////////////////////////////
87 #elif BOOST_PP_ITERATION_FLAGS()==9 // //////////////////////////////////////
88 // ////////////////////////////////////////////////////////////////////////
89 // MultiConnectorMixin member declaration
90
91 template <class Source, class Target mpp_TplParamsKomma()>
92 static std::pair<typename Source::ConnectorType &, typename Target::ConnectorType &>
93 connect_(Source & source, Target & target mpp_FnParamsKomma());
94
95 // ////////////////////////////////////////////////////////////////////////
96 #elif BOOST_PP_ITERATION_FLAGS()==2 // ////////////////////////////////////
97 // ////////////////////////////////////////////////////////////////////////
98 // senf::ppi namespace member declaration
99
100 // Here the reference to Source::ConnectorType / Target::ConnectorType
101 // works like enable_if, since only MultiConnector modules have those members
102
103 template <class Source, class Target mpp_TplParamsKomma()>
104 typename boost::enable_if<
105     boost::mpl::and_<
106         senf::ppi::module::detail::is_multiconnector_source<Source>,
107         boost::mpl::not_< senf::ppi::module::detail::is_multiconnector_target<Target> > >,
108     typename Source::ConnectorType & >::type
109 connect(Source & source, Target & target mpp_FnParamsKomma());
110
111 template <class Source, class Target mpp_TplParamsKomma()>
112 typename boost::enable_if<
113     boost::mpl::and_<
114         boost::mpl::not_< senf::ppi::module::detail::is_multiconnector_source<Source> >,
115         senf::ppi::module::detail::is_multiconnector_target<Target> >,
116     typename Target::ConnectorType & >::type
117 connect(Source & source, Target & target mpp_FnParamsKomma());
118
119 #define BOOST_PP_ITERATION_PARAMS_2 (4, (\
120         0, \
121         SENF_MULTI_CONNECTOR_MAX_ARGS, \
122         SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
123         4 ))
124 #include BOOST_PP_ITERATE()
125
126 // ////////////////////////////////////////////////////////////////////////
127 #elif BOOST_PP_ITERATION_FLAGS()==6 // ////////////////////////////////////
128 // ////////////////////////////////////////////////////////////////////////
129 // senf::ppi namespace member declaration (nested)
130
131 template <class Source, class Target mpp_TplParamsKomma()>
132 typename boost::enable_if<
133     boost::mpl::and_<
134         boost::is_base_of<connector::OutputConnector, typename Source::ConnectorType>,
135         boost::is_base_of<connector::InputConnector, typename Target::ConnectorType> >,
136     std::pair<typename Source::ConnectorType &, typename Target::ConnectorType &> >::type
137 connect(Source & source, Target & target mpp_FnParamsKomma());
138
139 // ////////////////////////////////////////////////////////////////////////
140 #elif BOOST_PP_ITERATION_FLAGS()==4 // ////////////////////////////////////
141 // ////////////////////////////////////////////////////////////////////////
142 // senf::ppi::detail namespace member declaration (nested iteration)
143
144 namespace detail {
145
146 template <class Fn, class Source, class Target mpp_TplParamsKomma() mpp_TplParamsKomma2()>
147 typename boost::enable_if_c<
148     senf::function_arity<Fn>::value == BOOST_PP_ITERATION()+1,
149     std::pair<typename Source::ConnectorType &, typename Target::ConnectorType &> >::type
150 connect_(Fn, Source & source, Target & target mpp_FnParamsKomma() mpp_FnParamsKomma2());
151
152 }
153
154 // ////////////////////////////////////////////////////////////////////////
155 #elif BOOST_PP_ITERATION_FLAGS()==3 // ////////////////////////////////////
156 // ////////////////////////////////////////////////////////////////////////
157 // Implementation
158
159 ////////////////////////////////////////
160 // Map container
161
162 template <class Self_, class ConnectorType_, class KeyType_, class ContainerType_>
163 mpp_TplParams()
164 prefix_ ConnectorType_ &
165 senf::ppi::module::MultiConnectorMixin<Self_,ConnectorType_,KeyType_,ContainerType_>::
166 newConnector(mpp_FnParams())
167 {
168     std::auto_ptr<ConnectorType_> conn (new ConnectorType_);
169     KeyType_ key (static_cast<Self_*>(this)->connectorSetup(*conn mpp_CallParamsKomma()));
170     return * connectors_.insert(key, conn).first->second;
171 }
172
173 ////////////////////////////////////////
174 // Vector container
175
176 template <class Self_, class ConnectorType_, class ContainerType_>
177 mpp_TplParams()
178 prefix_ ConnectorType_ &
179 senf::ppi::module::MultiConnectorMixin<Self_,ConnectorType_,void,ContainerType_>::
180 newConnector(mpp_FnParams())
181 {
182     connectors_.push_back(new ConnectorType_);
183     ConnectorType_ & conn (connectors_.back());
184     try { static_cast<Self_*>(this)->connectorSetup(conn mpp_CallParamsKomma()); }
185     catch (...) { connectors_.pop_back(); throw; }
186     return conn;
187 }
188
189 ////////////////////////////////////////
190 // User managed container
191
192 template <class Self_, class ConnectorType_>
193 mpp_TplParams()
194 prefix_ ConnectorType_ &
195 senf::ppi::module::MultiConnectorMixin<Self_,ConnectorType_,void,void>::
196 newConnector(mpp_FnParams())
197 {
198     std::auto_ptr<ConnectorType_> cp (new ConnectorType_);
199     ConnectorType_ & cref (*cp);
200     static_cast<Self_*>(this)->connectorSetup(cp mpp_CallParamsKomma());
201     return cref;
202 }
203
204 ////////////////////////////////////////
205 // senf::ppi::module::detail::MultiConnectorMixinAccess members
206
207 template <class Module mpp_TplParamsKomma()>
208 typename Module::ConnectorType & 
209 senf::ppi::module::detail::MultiConnectorMixinAccess::newConnector(
210     Module & module mpp_FnParamsKomma())
211 {
212     return module.newConnector(mpp_CallParams());
213 }
214
215 template <class Source, class Target mpp_TplParamsKomma()>
216 std::pair<typename Source::ConnectorType &, typename Target::ConnectorType &>
217 senf::ppi::module::detail::MultiConnectorMixinAccess::connect(
218     Source & source, Target & target mpp_FnParamsKomma())
219 {
220     return Source::connect_(source, target mpp_CallParamsKomma());
221 }
222
223 ////////////////////////////////////////
224 // senf::ppi::connect
225
226 template <class Source, class Target mpp_TplParamsKomma()>
227 typename boost::enable_if<
228     boost::mpl::and_<
229         senf::ppi::module::detail::is_multiconnector_source<Source>,
230         boost::mpl::not_< senf::ppi::module::detail::is_multiconnector_target<Target> > >,
231     typename Source::ConnectorType & >::type
232 senf::ppi::connect(Source & source, Target & target mpp_FnParamsKomma())
233 {
234     typename Source::ConnectorType & c (
235         module::detail::MultiConnectorMixinAccess::newConnector(source mpp_CallParamsKomma()));
236     connect(c, target);
237     return c;
238 }
239
240 template <class Source, class Target mpp_TplParamsKomma()>
241 typename boost::enable_if<
242     boost::mpl::and_<
243         boost::mpl::not_< senf::ppi::module::detail::is_multiconnector_source<Source> >,
244         senf::ppi::module::detail::is_multiconnector_target<Target> >,
245     typename Target::ConnectorType & >::type
246 senf::ppi::connect(Source & source, Target & target mpp_FnParamsKomma())
247 {
248     typename Target::ConnectorType & c (
249         module::detail::MultiConnectorMixinAccess::newConnector(target mpp_CallParamsKomma()));
250     connect(source, c);
251     return c;
252 }
253
254 #define BOOST_PP_ITERATION_PARAMS_2 (4, (\
255         0, \
256         SENF_MULTI_CONNECTOR_MAX_ARGS, \
257         SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
258         5 ))
259 #include BOOST_PP_ITERATE()
260
261 // ////////////////////////////////////////////////////////////////////////
262 #elif BOOST_PP_ITERATION_FLAGS()==5 // ////////////////////////////////////
263 // ////////////////////////////////////////////////////////////////////////
264 // Implementation for nested iteration
265
266 template <class Fn, class Source, class Target mpp_TplParamsKomma() mpp_TplParamsKomma2()>
267 typename boost::enable_if_c<
268     senf::function_arity<Fn>::value == BOOST_PP_ITERATION()+1,
269     std::pair<typename Source::ConnectorType &, typename Target::ConnectorType &> >::type
270 senf::ppi::detail::connect_(Fn, Source & source, Target & target 
271                             mpp_FnParamsKomma() mpp_FnParamsKomma2())
272 {
273     typename Source::ConnectorType & s (
274         module::detail::MultiConnectorMixinAccess::newConnector(source mpp_CallParamsKomma()));
275     typename Target::ConnectorType & t (
276         module::detail::MultiConnectorMixinAccess::newConnector(target mpp_CallParamsKomma2()));
277     connect(s,t);
278     return std::pair<typename Source::ConnectorType &, typename Target::ConnectorType &>(s,t);
279 }
280
281 // ////////////////////////////////////////////////////////////////////////
282 #elif BOOST_PP_ITERATION_FLAGS()==7 // ////////////////////////////////////
283 // ////////////////////////////////////////////////////////////////////////
284 // Implementation
285
286 template <class Self_, class ConnectorType_, class KeyType_, class ContainerType_>
287 template <class Source, class Target mpp_TplParamsKomma()>
288 std::pair<typename Source::ConnectorType &, typename Target::ConnectorType &>
289 senf::ppi::module::MultiConnectorMixin<Self_,ConnectorType_,KeyType_,ContainerType_>::
290 connect_(Source & source, Target & target mpp_FnParamsKomma())
291 {
292     return senf::ppi::detail::connect_(
293         & Self_::connectorSetup, source, target mpp_CallParamsKomma());
294 }
295
296 template <class Self_, class ConnectorType_, class ContainerType_>
297 template <class Source, class Target mpp_TplParamsKomma()>
298 std::pair<typename Source::ConnectorType &, typename Target::ConnectorType &>
299 senf::ppi::module::MultiConnectorMixin<Self_,ConnectorType_,void,ContainerType_>::
300 connect_(Source & source, Target & target mpp_FnParamsKomma())
301 {
302     return senf::ppi::detail::connect_(
303         & Self_::connectorSetup, source, target mpp_CallParamsKomma());
304 }
305
306 template <class Self_, class ConnectorType_>
307 template <class Source, class Target mpp_TplParamsKomma()>
308 std::pair<typename Source::ConnectorType &, typename Target::ConnectorType &>
309 senf::ppi::module::MultiConnectorMixin<Self_,ConnectorType_,void,void>::
310 connect_(Source & source, Target & target mpp_FnParamsKomma())
311 {
312     return senf::ppi::detail::connect_(
313         & Self_::connectorSetup, source, target mpp_CallParamsKomma());
314 }
315
316 template <class Source, class Target mpp_TplParamsKomma()>
317 typename boost::enable_if<
318     boost::mpl::and_<
319         boost::is_base_of<senf::ppi::connector::OutputConnector, typename Source::ConnectorType>,
320         boost::is_base_of<senf::ppi::connector::InputConnector, typename Target::ConnectorType> >,
321     std::pair<typename Source::ConnectorType &, typename Target::ConnectorType &> >::type
322 senf::ppi::connect(Source & source, Target & target mpp_FnParamsKomma())
323 {
324     return module::detail::MultiConnectorMixinAccess::connect(
325         source, target mpp_CallParamsKomma());
326 }
327
328 // ////////////////////////////////////////////////////////////////////////
329 #elif BOOST_PP_ITERATION_FLAGS()==8 // ////////////////////////////////////
330 // ////////////////////////////////////////////////////////////////////////
331 // senf::ppi::module::detail::MultiConnectorMixinAccess members
332
333 template <class Module mpp_TplParamsKomma()>
334 static typename Module::ConnectorType & 
335 newConnector(Module & module mpp_FnParamsKomma());
336
337 template <class Source, class Target mpp_TplParamsKomma()>
338 static std::pair<typename Source::ConnectorType &, typename Target::ConnectorType &>
339 connect(Source & source, Target & target mpp_FnParamsKomma());
340
341 // ////////////////////////////////////////////////////////////////////////
342 #endif // /////////////////////////////////////////////////////////////////
343 // ////////////////////////////////////////////////////////////////////////
344 // Undefine local Macros
345
346 #undef mpp_CallParamsKomma2
347 #undef mpp_CallParams2
348 #undef mpp_FnParamsKomma2
349 #undef mpp_FnParams2
350 #undef mpp_TplParamsKomma2
351 #undef mpp_CallParamsKomma
352 #undef mpp_CallParams
353 #undef mpp_FnParamsKomma
354 #undef mpp_FnParams
355 #undef mpp_TplParamsKomma
356 #undef mpp_TplParams_
357 #undef mpp_TplParams
358             
359 // ////////////////////////////////////////////////////////////////////////
360 /*
361  (save-excursion (re-search-backward "^// Undefine local Macros")
362  (forward-line 1) (delete-region (point) (progn (search-forward
363  "// ////") (forward-line -1) (point))) (insert "\n") (let ((b (point))
364  (e (progn (insert (save-excursion (re-search-backward 
365  "^// Local Macros") (search-forward "#define") (beginning-of-line)
366  (buffer-substring (point) (progn (search-forward "// ////")
367  (search-backward "#define") (forward-line 1) (point))))) (point))))
368  (reverse-region b e) (shell-command-on-region b e "grep -F '#define'" nil
369  t) (goto-char b) (while (looking-at "#define") (delete-char 7) (insert
370  "#undef") (skip-chars-forward " ") (re-search-forward "[^a-zA-Z0-9_]")
371  (delete-region (1- (point)) (progn (end-of-line) (point))) (forward-line
372  1))))
373 */
374 // ////////////////////////////////////////////////////////////////////////
375 #endif // /////////////////////////////////////////////////////////////////
376 // ///////////////////////////mpp.e////////////////////////////////////////
377
378 \f
379 // Local Variables:
380 // mode: c++
381 // fill-column: 100
382 // comment-column: 40
383 // c-file-style: "senf"
384 // indent-tabs-mode: nil
385 // ispell-local-dictionary: "american"
386 // compile-command: "scons -u test"
387 // End: