PPI: Implement a more sane multi-connector connect API
[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 mpp_FnParamsKomma(), Target & target);
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()==4 // ////////////////////////////////////
136 // ////////////////////////////////////////////////////////////////////////
137 // senf::ppi namespace member declaration 1..MAX_ARGS x 1..MAX_ARGS
138
139 template <class Source, class Target mpp_TplParamsKomma() mpp_TplParamsKomma2()>
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 mpp_FnParamsKomma(), Target & target mpp_FnParamsKomma2());
146
147 // ////////////////////////////////////////////////////////////////////////
148 #elif BOOST_PP_ITERATION_FLAGS()==8 // ////////////////////////////////////
149 // ////////////////////////////////////////////////////////////////////////
150 // senf::ppi::module::detail::MultiConnectorMixinAccess member declaration 1..MAX_ARGS
151
152 template <class Module mpp_TplParamsKomma()>
153 static typename Module::ConnectorType & 
154 newConnector(Module & module mpp_FnParamsKomma());
155
156 // ////////////////////////////////////////////////////////////////////////
157 #elif BOOST_PP_ITERATION_FLAGS()==3 // ////////////////////////////////////
158 // ////////////////////////////////////////////////////////////////////////
159 // Implementation 1..MAX_ARGS
160
161 ////////////////////////////////////////
162 // Map container
163
164 template <class Self_, class ConnectorType_, class KeyType_, class ContainerType_>
165 mpp_TplParams()
166 prefix_ ConnectorType_ &
167 senf::ppi::module::MultiConnectorMixin<Self_,ConnectorType_,KeyType_,ContainerType_>::
168 newConnector(mpp_FnParams())
169 {
170     std::auto_ptr<ConnectorType_> conn (new ConnectorType_);
171     KeyType_ key (static_cast<Self_*>(this)->connectorSetup(*conn mpp_CallParamsKomma()));
172     return * connectors_.insert(key, conn).first->second;
173 }
174
175 ////////////////////////////////////////
176 // Vector container
177
178 template <class Self_, class ConnectorType_, class ContainerType_>
179 mpp_TplParams()
180 prefix_ ConnectorType_ &
181 senf::ppi::module::MultiConnectorMixin<Self_,ConnectorType_,void,ContainerType_>::
182 newConnector(mpp_FnParams())
183 {
184     connectors_.push_back(new ConnectorType_);
185     ConnectorType_ & conn (connectors_.back());
186     try { static_cast<Self_*>(this)->connectorSetup(conn mpp_CallParamsKomma()); }
187     catch (...) { connectors_.pop_back(); throw; }
188     return conn;
189 }
190
191 ////////////////////////////////////////
192 // User managed container
193
194 template <class Self_, class ConnectorType_>
195 mpp_TplParams()
196 prefix_ ConnectorType_ &
197 senf::ppi::module::MultiConnectorMixin<Self_,ConnectorType_,void,void>::
198 newConnector(mpp_FnParams())
199 {
200     std::auto_ptr<ConnectorType_> cp (new ConnectorType_);
201     ConnectorType_ & cref (*cp);
202     static_cast<Self_*>(this)->connectorSetup(cp mpp_CallParamsKomma());
203     return cref;
204 }
205
206 ////////////////////////////////////////
207 // senf::ppi::connect
208
209 template <class Source, class Target mpp_TplParamsKomma()>
210 typename boost::enable_if<
211     boost::mpl::and_<
212         senf::ppi::module::detail::IsMulticonnectorSource<Source>,
213         boost::mpl::not_< senf::ppi::module::detail::IsMulticonnectorTarget<Target> > >,
214     typename Source::ConnectorType & >::type
215 senf::ppi::connect(Source & source mpp_FnParamsKomma(), Target & target)
216 {
217     typename Source::ConnectorType & c (
218         module::detail::MultiConnectorMixinAccess::newConnector(source mpp_CallParamsKomma()));
219     connect(c, target);
220     return c;
221 }
222
223 template <class Source, class Target mpp_TplParamsKomma()>
224 typename boost::enable_if<
225     boost::mpl::and_<
226         boost::mpl::not_< senf::ppi::module::detail::IsMulticonnectorSource<Source> >,
227         senf::ppi::module::detail::IsMulticonnectorTarget<Target> >,
228     typename Target::ConnectorType & >::type
229 senf::ppi::connect(Source & source, Target & target mpp_FnParamsKomma())
230 {
231     typename Target::ConnectorType & c (
232         module::detail::MultiConnectorMixinAccess::newConnector(target mpp_CallParamsKomma()));
233     connect(source, c);
234     return c;
235 }
236
237 ////////////////////////////////////////
238 // senf::ppi::module::detail::MultiConnectorMixinAccess members
239
240 template <class Module mpp_TplParamsKomma()>
241 typename Module::ConnectorType & 
242 senf::ppi::module::detail::MultiConnectorMixinAccess::newConnector(
243     Module & module mpp_FnParamsKomma())
244 {
245     return module.newConnector(mpp_CallParams());
246 }
247
248 #define BOOST_PP_ITERATION_PARAMS_2 (4, (\
249         0, \
250         SENF_MULTI_CONNECTOR_MAX_ARGS, \
251         SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
252         5 ))
253 #include BOOST_PP_ITERATE()
254
255 ////////////////////////////////////////////////////////////////////////
256 #elif BOOST_PP_ITERATION_FLAGS()==5 // ////////////////////////////////////
257 // ////////////////////////////////////////////////////////////////////////
258 // Implementation 1..MAX_ARGS x 1..MAX_ARGS
259
260 template <class Source, class Target mpp_TplParamsKomma() mpp_TplParamsKomma2()>
261 typename boost::enable_if<
262     boost::mpl::and_<
263         boost::is_base_of<senf::ppi::connector::OutputConnector, typename Source::ConnectorType>,
264         boost::is_base_of<senf::ppi::connector::InputConnector, typename Target::ConnectorType> >,
265     boost::tuple<typename Source::ConnectorType &, typename Target::ConnectorType &> >::type
266 senf::ppi::connect(Source & source mpp_FnParamsKomma(), Target & target mpp_FnParamsKomma2())
267 {
268     typename Source::ConnectorType & s (
269         module::detail::MultiConnectorMixinAccess::newConnector(source mpp_CallParamsKomma()));
270     typename Target::ConnectorType & t (
271         module::detail::MultiConnectorMixinAccess::newConnector(target mpp_CallParamsKomma2()));
272     connect(s,t);
273     return boost::tie(s,t);
274 }
275
276 // ////////////////////////////////////////////////////////////////////////
277 #endif // /////////////////////////////////////////////////////////////////
278 // ////////////////////////////////////////////////////////////////////////
279 // Undefine local Macros
280
281 #undef mpp_CallParamsKomma2
282 #undef mpp_CallParams2
283 #undef mpp_FnParamsKomma2
284 #undef mpp_FnParams2
285 #undef mpp_TplParamsKomma2
286 #undef mpp_CallParamsKomma
287 #undef mpp_CallParams
288 #undef mpp_FnParamsKomma
289 #undef mpp_FnParams
290 #undef mpp_TplParamsKomma
291 #undef mpp_TplParams_
292 #undef mpp_TplParams
293             
294 // ////////////////////////////////////////////////////////////////////////
295 /*
296  (save-excursion (re-search-backward "^// Undefine local Macros")
297  (forward-line 1) (delete-region (point) (progn (search-forward
298  "// ////") (forward-line -1) (point))) (insert "\n") (let ((b (point))
299  (e (progn (insert (save-excursion (re-search-backward 
300  "^// Local Macros") (search-forward "#define") (beginning-of-line)
301  (buffer-substring (point) (progn (search-forward "// ////")
302  (search-backward "#define") (forward-line 1) (point))))) (point))))
303  (reverse-region b e) (shell-command-on-region b e "grep -F '#define'" nil
304  t) (goto-char b) (while (looking-at "#define") (delete-char 7) (insert
305  "#undef") (skip-chars-forward " ") (re-search-forward "[^a-zA-Z0-9_]")
306  (delete-region (1- (point)) (progn (end-of-line) (point))) (forward-line
307  1))))
308 */
309 // ////////////////////////////////////////////////////////////////////////
310 #endif // /////////////////////////////////////////////////////////////////
311 // ///////////////////////////mpp.e////////////////////////////////////////
312
313 \f
314 // Local Variables:
315 // mode: c++
316 // fill-column: 100
317 // comment-column: 40
318 // c-file-style: "senf"
319 // indent-tabs-mode: nil
320 // ispell-local-dictionary: "american"
321 // compile-command: "scons -u test"
322 // End: