PPI: Replace std::pair<&,&> with boost::tuple (fixes g++<4.3 problems)
[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 <boost/tuple/tuple.hpp>
41 #include <senf/Utils/type_traits.hh>
42
43 // ///////////////////////////mpp.p////////////////////////////////////////
44 #elif BOOST_PP_IS_ITERATING // ////////////////////////////////////////////
45 // ////////////////////////////////////////////////////////////////////////
46 // Local Macros
47
48 // => template <class A0, class A1, ...>
49 #define mpp_TplParams()                                                 \
50     BOOST_PP_IF(BOOST_PP_ITERATION(), mpp_TplParams_, BOOST_PP_EMPTY)()
51 #define mpp_TplParams_()                                                \
52     template <BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(), class A)>
53
54 // => , class A0, class A1, ...
55 #define mpp_TplParamsKomma()                                            \
56     BOOST_PP_ENUM_TRAILING_PARAMS(BOOST_PP_ITERATION(), class A)
57
58 // => A0 const & a0, A1 const & a1, ...
59 #define mpp_FnParams()                                                  \
60     BOOST_PP_ENUM_BINARY_PARAMS(BOOST_PP_ITERATION(), A, const & a)
61
62 // => , A0 const & a0, A1 const & a1, ...
63 #define mpp_FnParamsKomma()                                             \
64     BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(BOOST_PP_ITERATION(), A, const & a)
65
66 // => a0, a1, ...
67 #define mpp_CallParams()                                                \
68     BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(), a)
69
70 // => , a0, a1, ...
71 #define mpp_CallParamsKomma()                                           \
72     BOOST_PP_ENUM_TRAILING_PARAMS(BOOST_PP_ITERATION(), a)
73
74 // Same as above but for outer iteration (in nested file iteration)
75 #define mpp_TplParamsKomma2()                                            \
76     BOOST_PP_ENUM_TRAILING_PARAMS(BOOST_PP_FRAME_ITERATION(1), class B)
77 #define mpp_FnParams2()                                                  \
78     BOOST_PP_ENUM_BINARY_PARAMS(BOOST_PP_FRAME_ITERATION(1), B, cont & b)
79 #define mpp_FnParamsKomma2()                                             \
80     BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(BOOST_PP_FRAME_ITERATION(1), B, const & b)
81 #define mpp_CallParams2()                                                \
82     BOOST_PP_ENUM_PARAMS(BOOST_PP_FRAME_ITERATION(1), b)
83 #define mpp_CallParamsKomma2()                                           \
84     BOOST_PP_ENUM_TRAILING_PARAMS(BOOST_PP_FRAME_ITERATION(1), b)
85
86 // ////////////////////////////////////////////////////////////////////////
87 #if BOOST_PP_ITERATION_FLAGS()==1 // //////////////////////////////////////
88 // ////////////////////////////////////////////////////////////////////////
89 // senf::ppi::module::MultiConnectorMixin member declaration 1..MAX_ARGS
90
91 mpp_TplParams()
92 ConnectorType_ & newConnector( mpp_FnParams() );
93
94 // ////////////////////////////////////////////////////////////////////////
95 #elif BOOST_PP_ITERATION_FLAGS()==9 // ////////////////////////////////////
96 // ////////////////////////////////////////////////////////////////////////
97 // senf::ppi::module::MultiConnectorMixin member declaration 1..2*MAX_ARGS
98
99 template <class Source, class Target mpp_TplParamsKomma()>
100 static boost::tuple<typename Source::ConnectorType &, typename Target::ConnectorType &>
101 connect_(Source & source, Target & target mpp_FnParamsKomma());
102
103 // ////////////////////////////////////////////////////////////////////////
104 #elif BOOST_PP_ITERATION_FLAGS()==2 // ////////////////////////////////////
105 // ////////////////////////////////////////////////////////////////////////
106 // senf::ppi namespace member declaration 1..MAX_ARGS
107
108 // Here the reference to Source::ConnectorType / Target::ConnectorType
109 // works like enable_if, since only MultiConnector modules have those members
110
111 template <class Source, class Target mpp_TplParamsKomma()>
112 typename boost::enable_if<
113     boost::mpl::and_<
114         senf::ppi::module::detail::IsMulticonnectorSource<Source>,
115         boost::mpl::not_< senf::ppi::module::detail::IsMulticonnectorTarget<Target> > >,
116     typename Source::ConnectorType & >::type
117 connect(Source & source, Target & target mpp_FnParamsKomma());
118
119 template <class Source, class Target mpp_TplParamsKomma()>
120 typename boost::enable_if<
121     boost::mpl::and_<
122         boost::mpl::not_< senf::ppi::module::detail::IsMulticonnectorSource<Source> >,
123         senf::ppi::module::detail::IsMulticonnectorTarget<Target> >,
124     typename Target::ConnectorType & >::type
125 connect(Source & source, Target & target mpp_FnParamsKomma());
126
127 #define BOOST_PP_ITERATION_PARAMS_2 (4, (\
128         0, \
129         SENF_MULTI_CONNECTOR_MAX_ARGS, \
130         SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
131         4 ))
132 #include BOOST_PP_ITERATE()
133
134 // ////////////////////////////////////////////////////////////////////////
135 #elif BOOST_PP_ITERATION_FLAGS()==6 // ////////////////////////////////////
136 // ////////////////////////////////////////////////////////////////////////
137 // senf::ppi namespace member declaration 1..2*MAX_ARGS
138
139 template <class Source, class Target mpp_TplParamsKomma()>
140 typename boost::enable_if<
141     boost::mpl::and_<
142         boost::is_base_of<connector::OutputConnector, typename Source::ConnectorType>,
143         boost::is_base_of<connector::InputConnector, typename Target::ConnectorType> >,
144     boost::tuple<typename Source::ConnectorType &, typename Target::ConnectorType &> >::type
145 connect(Source & source, Target & target mpp_FnParamsKomma());
146
147 // ////////////////////////////////////////////////////////////////////////
148 #elif BOOST_PP_ITERATION_FLAGS()==4 // ////////////////////////////////////
149 // ////////////////////////////////////////////////////////////////////////
150 // senf::ppi namespace member declaration 1..MAX_ARGS x 1..MAX_ARGS
151
152 namespace detail {
153
154 template <class Fn, class Source, class Target mpp_TplParamsKomma() mpp_TplParamsKomma2()>
155 typename boost::enable_if_c<
156     senf::function_arity<Fn>::value == BOOST_PP_ITERATION()+1,
157     boost::tuple<typename Source::ConnectorType &, typename Target::ConnectorType &> >::type
158 connect_(Fn, Source & source, Target & target mpp_FnParamsKomma() mpp_FnParamsKomma2());
159
160 }
161
162 // ////////////////////////////////////////////////////////////////////////
163 #elif BOOST_PP_ITERATION_FLAGS()==8 // ////////////////////////////////////
164 // ////////////////////////////////////////////////////////////////////////
165 // senf::ppi::module::detail::MultiConnectorMixinAccess member declaration 1..MAX_ARGS
166
167 template <class Module mpp_TplParamsKomma()>
168 static typename Module::ConnectorType & 
169 newConnector(Module & module mpp_FnParamsKomma());
170
171 // ////////////////////////////////////////////////////////////////////////
172 #elif BOOST_PP_ITERATION_FLAGS()==10 // ///////////////////////////////////
173 // ////////////////////////////////////////////////////////////////////////
174 // senf::ppi::module::detail::MultiConnectorMixinAccess member declaration 1..2*MAX_ARGS
175
176 template <class Source, class Target mpp_TplParamsKomma()>
177 static boost::tuple<typename Source::ConnectorType &, typename Target::ConnectorType &>
178 connect(Source & source, Target & target mpp_FnParamsKomma());
179
180 // ////////////////////////////////////////////////////////////////////////
181 #elif BOOST_PP_ITERATION_FLAGS()==3 // ////////////////////////////////////
182 // ////////////////////////////////////////////////////////////////////////
183 // Implementation 1..MAX_ARGS
184
185 ////////////////////////////////////////
186 // Map container
187
188 template <class Self_, class ConnectorType_, class KeyType_, class ContainerType_>
189 mpp_TplParams()
190 prefix_ ConnectorType_ &
191 senf::ppi::module::MultiConnectorMixin<Self_,ConnectorType_,KeyType_,ContainerType_>::
192 newConnector(mpp_FnParams())
193 {
194     std::auto_ptr<ConnectorType_> conn (new ConnectorType_);
195     KeyType_ key (static_cast<Self_*>(this)->connectorSetup(*conn mpp_CallParamsKomma()));
196     return * connectors_.insert(key, conn).first->second;
197 }
198
199 ////////////////////////////////////////
200 // Vector container
201
202 template <class Self_, class ConnectorType_, class ContainerType_>
203 mpp_TplParams()
204 prefix_ ConnectorType_ &
205 senf::ppi::module::MultiConnectorMixin<Self_,ConnectorType_,void,ContainerType_>::
206 newConnector(mpp_FnParams())
207 {
208     connectors_.push_back(new ConnectorType_);
209     ConnectorType_ & conn (connectors_.back());
210     try { static_cast<Self_*>(this)->connectorSetup(conn mpp_CallParamsKomma()); }
211     catch (...) { connectors_.pop_back(); throw; }
212     return conn;
213 }
214
215 ////////////////////////////////////////
216 // User managed container
217
218 template <class Self_, class ConnectorType_>
219 mpp_TplParams()
220 prefix_ ConnectorType_ &
221 senf::ppi::module::MultiConnectorMixin<Self_,ConnectorType_,void,void>::
222 newConnector(mpp_FnParams())
223 {
224     std::auto_ptr<ConnectorType_> cp (new ConnectorType_);
225     ConnectorType_ & cref (*cp);
226     static_cast<Self_*>(this)->connectorSetup(cp mpp_CallParamsKomma());
227     return cref;
228 }
229
230 ////////////////////////////////////////
231 // senf::ppi::connect
232
233 template <class Source, class Target mpp_TplParamsKomma()>
234 typename boost::enable_if<
235     boost::mpl::and_<
236         senf::ppi::module::detail::IsMulticonnectorSource<Source>,
237         boost::mpl::not_< senf::ppi::module::detail::IsMulticonnectorTarget<Target> > >,
238     typename Source::ConnectorType & >::type
239 senf::ppi::connect(Source & source, Target & target mpp_FnParamsKomma())
240 {
241     typename Source::ConnectorType & c (
242         module::detail::MultiConnectorMixinAccess::newConnector(source mpp_CallParamsKomma()));
243     connect(c, target);
244     return c;
245 }
246
247 template <class Source, class Target mpp_TplParamsKomma()>
248 typename boost::enable_if<
249     boost::mpl::and_<
250         boost::mpl::not_< senf::ppi::module::detail::IsMulticonnectorSource<Source> >,
251         senf::ppi::module::detail::IsMulticonnectorTarget<Target> >,
252     typename Target::ConnectorType & >::type
253 senf::ppi::connect(Source & source, Target & target mpp_FnParamsKomma())
254 {
255     typename Target::ConnectorType & c (
256         module::detail::MultiConnectorMixinAccess::newConnector(target mpp_CallParamsKomma()));
257     connect(source, c);
258     return c;
259 }
260
261 ////////////////////////////////////////
262 // senf::ppi::module::detail::MultiConnectorMixinAccess members
263
264 template <class Module mpp_TplParamsKomma()>
265 typename Module::ConnectorType & 
266 senf::ppi::module::detail::MultiConnectorMixinAccess::newConnector(
267     Module & module mpp_FnParamsKomma())
268 {
269     return module.newConnector(mpp_CallParams());
270 }
271
272 #define BOOST_PP_ITERATION_PARAMS_2 (4, (\
273         0, \
274         SENF_MULTI_CONNECTOR_MAX_ARGS, \
275         SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
276         5 ))
277 #include BOOST_PP_ITERATE()
278
279 // ////////////////////////////////////////////////////////////////////////
280 #elif BOOST_PP_ITERATION_FLAGS()==7 // ////////////////////////////////////
281 // ////////////////////////////////////////////////////////////////////////
282 // Implementation 1..2*MAX_ARGS
283
284 ////////////////////////////////////////
285 // Map container
286
287 template <class Self_, class ConnectorType_, class KeyType_, class ContainerType_>
288 template <class Source, class Target mpp_TplParamsKomma()>
289 boost::tuple<typename Source::ConnectorType &, typename Target::ConnectorType &>
290 senf::ppi::module::MultiConnectorMixin<Self_,ConnectorType_,KeyType_,ContainerType_>::
291 connect_(Source & source, Target & target mpp_FnParamsKomma())
292 {
293     return senf::ppi::detail::connect_(
294         & Self_::connectorSetup, source, target mpp_CallParamsKomma());
295 }
296
297 ////////////////////////////////////////
298 // Vector container
299
300 template <class Self_, class ConnectorType_, class ContainerType_>
301 template <class Source, class Target mpp_TplParamsKomma()>
302 boost::tuple<typename Source::ConnectorType &, typename Target::ConnectorType &>
303 senf::ppi::module::MultiConnectorMixin<Self_,ConnectorType_,void,ContainerType_>::
304 connect_(Source & source, Target & target mpp_FnParamsKomma())
305 {
306     return senf::ppi::detail::connect_(
307         & Self_::connectorSetup, source, target mpp_CallParamsKomma());
308 }
309
310 ////////////////////////////////////////
311 // User container
312
313 template <class Self_, class ConnectorType_>
314 template <class Source, class Target mpp_TplParamsKomma()>
315 boost::tuple<typename Source::ConnectorType &, typename Target::ConnectorType &>
316 senf::ppi::module::MultiConnectorMixin<Self_,ConnectorType_,void,void>::
317 connect_(Source & source, Target & target mpp_FnParamsKomma())
318 {
319     return senf::ppi::detail::connect_(
320         & Self_::connectorSetup, source, target mpp_CallParamsKomma());
321 }
322
323 ////////////////////////////////////////
324 // senf::ppi::connect
325
326 template <class Source, class Target mpp_TplParamsKomma()>
327 typename boost::enable_if<
328     boost::mpl::and_<
329         boost::is_base_of<senf::ppi::connector::OutputConnector, typename Source::ConnectorType>,
330         boost::is_base_of<senf::ppi::connector::InputConnector, typename Target::ConnectorType> >,
331     boost::tuple<typename Source::ConnectorType &, typename Target::ConnectorType &> >::type
332 senf::ppi::connect(Source & source, Target & target mpp_FnParamsKomma())
333 {
334     return module::detail::MultiConnectorMixinAccess::connect(
335         source, target mpp_CallParamsKomma());
336 }
337
338 ////////////////////////////////////////
339 // senf::ppi::module::detail::MultiConnectorMixinAccess members
340
341 template <class Source, class Target mpp_TplParamsKomma()>
342 boost::tuple<typename Source::ConnectorType &, typename Target::ConnectorType &>
343 senf::ppi::module::detail::MultiConnectorMixinAccess::connect(
344     Source & source, Target & target mpp_FnParamsKomma())
345 {
346     return Source::connect_(source, target mpp_CallParamsKomma());
347 }
348
349 ////////////////////////////////////////////////////////////////////////
350 #elif BOOST_PP_ITERATION_FLAGS()==5 // ////////////////////////////////////
351 // ////////////////////////////////////////////////////////////////////////
352 // Implementation 1..MAX_ARGS x 1..MAX_ARGS
353
354 template <class Fn, class Source, class Target mpp_TplParamsKomma() mpp_TplParamsKomma2()>
355 typename boost::enable_if_c<
356     senf::function_arity<Fn>::value == BOOST_PP_ITERATION()+1,
357     boost::tuple<typename Source::ConnectorType &, typename Target::ConnectorType &> >::type
358 senf::ppi::detail::connect_(Fn, Source & source, Target & target 
359                             mpp_FnParamsKomma() mpp_FnParamsKomma2())
360 {
361     typename Source::ConnectorType & s (
362         module::detail::MultiConnectorMixinAccess::newConnector(source mpp_CallParamsKomma()));
363     typename Target::ConnectorType & t (
364         module::detail::MultiConnectorMixinAccess::newConnector(target mpp_CallParamsKomma2()));
365     connect(s,t);
366     return boost::tie(s,t);
367 }
368
369 // ////////////////////////////////////////////////////////////////////////
370 #endif // /////////////////////////////////////////////////////////////////
371 // ////////////////////////////////////////////////////////////////////////
372 // Undefine local Macros
373
374 #undef mpp_CallParamsKomma2
375 #undef mpp_CallParams2
376 #undef mpp_FnParamsKomma2
377 #undef mpp_FnParams2
378 #undef mpp_TplParamsKomma2
379 #undef mpp_CallParamsKomma
380 #undef mpp_CallParams
381 #undef mpp_FnParamsKomma
382 #undef mpp_FnParams
383 #undef mpp_TplParamsKomma
384 #undef mpp_TplParams_
385 #undef mpp_TplParams
386             
387 // ////////////////////////////////////////////////////////////////////////
388 /*
389  (save-excursion (re-search-backward "^// Undefine local Macros")
390  (forward-line 1) (delete-region (point) (progn (search-forward
391  "// ////") (forward-line -1) (point))) (insert "\n") (let ((b (point))
392  (e (progn (insert (save-excursion (re-search-backward 
393  "^// Local Macros") (search-forward "#define") (beginning-of-line)
394  (buffer-substring (point) (progn (search-forward "// ////")
395  (search-backward "#define") (forward-line 1) (point))))) (point))))
396  (reverse-region b e) (shell-command-on-region b e "grep -F '#define'" nil
397  t) (goto-char b) (while (looking-at "#define") (delete-char 7) (insert
398  "#undef") (skip-chars-forward " ") (re-search-forward "[^a-zA-Z0-9_]")
399  (delete-region (1- (point)) (progn (end-of-line) (point))) (forward-line
400  1))))
401 */
402 // ////////////////////////////////////////////////////////////////////////
403 #endif // /////////////////////////////////////////////////////////////////
404 // ///////////////////////////mpp.e////////////////////////////////////////
405
406 \f
407 // Local Variables:
408 // mode: c++
409 // fill-column: 100
410 // comment-column: 40
411 // c-file-style: "senf"
412 // indent-tabs-mode: nil
413 // ispell-local-dictionary: "american"
414 // compile-command: "scons -u test"
415 // End: