PPI: Allow connecting two MultiConnectorMixin modules
[senf.git] / senf / PPI / MultiConnectorMixin.hh
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 public header */
25
26 #ifndef HH_SENF_PPI_MultiConnectorMixin_
27 #define HH_SENF_PPI_MultiConnectorMixin_ 1
28
29 // Custom includes
30 #include <senf/config.hh>
31 #include <boost/ptr_container/ptr_map.hpp>
32 #include <boost/ptr_container/ptr_vector.hpp>
33 #include <boost/mpl/if.hpp>
34 #include "Connectors.hh"
35 #include "Setup.hh"
36
37 #ifndef SENF_MULTI_CONNECTOR_MAX_ARGS
38 #define SENF_MULTI_CONNECTOR_MAX_ARGS 3
39 #define SENF_MULTI_CONNECTOR_MAX_ARGS2 6
40 #endif
41
42 #include "MultiConnectorMixin.mpp"
43 #include "MultiConnectorMixin.ih"
44 ///////////////////////////////hh.p////////////////////////////////////////
45
46 namespace senf {
47 namespace ppi {
48     
49 #ifdef DOXYGEN
50
51     // For exposition only.
52     // Other implementations with 0..SENF_MULTI_CONNECTOR_MAX_ARGS arguments accordingly
53     // The real implementation includes a boost::enable_if condition in the return value, which is
54     // used to only enable the correct overload: The first overload, if the MultiConnector is an
55     // output, otherwise the second overload.
56
57     /** \brief Connect MultiConnector source to arbitrary target
58
59         Additional implementations with 0..SENF_MULTI_CONNECTOR_MAX_ARGS arguments.
60
61         \related module::MultiConnectorMixin
62      */
63     template <class MultiConnectorSource, class Target, class A1>
64     MultiConnectorSource::ConnectorType & connect(
65         MultiConnectorSource & source, Target & target, A1 const & a1);
66     
67     /** \brief Connect arbitrary source to MultiConnector target
68
69         Additional implementations with 0..SENF_MULTI_CONNECTOR_MAX_ARGS arguments.
70
71         \related module::MultiConnectorMixin
72      */
73     template <class Source, class MultiConnectorTarget, class A1>
74     MultiConnectorTarget::ConnectorType & connect(
75         Source & source, MultiConnectorTarget & target, A1 const & a1);
76
77     template <class MultiConnectorSource, class MultiConnectorTarget, class A1, class A2>
78     std::pair<MultiConnectorSource::ConnectorType &, MultiConnectorTarget::ConnectorType &>
79     connect(
80         MultiConnectorSource & source, MultiConnectorTarget & target, A1 const & a1, A2 const & a2);
81
82 #else
83
84     // Include 'senf::ppi namespace member declarations' from MultiConnectorMixin.mpp
85 #   define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
86             0, \
87             SENF_MULTI_CONNECTOR_MAX_ARGS, \
88             SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
89             2 ))
90 #   include BOOST_PP_ITERATE()
91
92 #   define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
93             0, \
94             SENF_MULTI_CONNECTOR_MAX_ARGS2, \
95             SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
96             6 ))
97 #   include BOOST_PP_ITERATE()
98
99 #endif
100
101 namespace module {
102
103     namespace detail { class MultiConnectorMixinAccess; }
104
105     /** \brief Multi connector management
106
107         This mixin provides a module with support for a runtime configurable number of input or
108         output connectors.
109         \code
110         class MyModule 
111             : public senf::ppi::module::Modulem,
112               public senf::ppi::module::MultiConnectorMixin<
113                   MyModule, senf::ppi::connector::ActiveInput<> >
114         {
115             SENF_PPI_MODULE(MyModule);
116         public:
117             senf::ppi::connector::PassiveOutput<> output;
118
119             // ...
120
121         private:
122             void connectorSetup(senf::ppi::connector::ActiveInput & input)
123             {
124                 route(input, output);
125                 input.onThrottle(&MyModule::doThrottle);
126             }
127
128             void doThrottle()
129             { 
130                 // ...
131             }
132
133             friend class senf::ppi::module::MultiConnectorMixin<
134                 MyModule, senf::ppi::connector::ActiveInput<> >
135         }
136         \endcode
137
138         Using the MultiConnectorMixin consists of
139         \li inheriting from MultiConnectorMixin
140         \li defining a function \c connectorSetup
141         \li declaring the mixin as a friend
142
143         The MultiConnectorMixin takes several template arguments
144         \li the name of the derived class, \a Self_
145         \li the type of connector, \a ConnectorType_
146         \li an optional \a KeyType_ if a mapping container is required
147         \li an optional \a ContainerType_ to replace the default \c boost::ptr_vector or \c
148             boost::ptr_map.
149
150         \section senf_ppi_multiconnector_sequence Sequence/vector based multi connector mixin
151
152         If no \a KeyType_ is given (or the \a KeyType_ is \c void), the mixin will use a sequence
153         container, by default a \c boost::ptr_vector to store the connectors. In this case, new
154         connectors will be added to the end of the container. The \c connectorSetup() routine
155         however may be used to move the inserted connector to some other location, e.g.
156         \code
157         container().insert(begin(), container().pop_back().release());
158         \endcode
159         which will move the new connector from the end to the beginning. 
160         \warning If you throw an exception from \c connectorSetup(), you must do so \e before moving
161             the new connector around since the mixin will remove the last element from the container
162             on an exception.
163
164         \par "Example:" senf::ppi::module::PriorityJoin
165
166         \section senf_ppi_multiconnector_map Map based multi connector mixin
167
168         If \a KeyType_ is given (and is not \c void), the mixin will use a mapping container, by
169         default a \c boost::ptr_map to store the connectors. The \c connectorSetup() member function
170         must return the key value under which the new connector will be stored. The new connector
171         will this be written to the container only \e after \c connectorSetup() returns.
172
173         When the returned key is not unique, the new connector will \e replace the old one. If this
174         is not, what you want, either check for an already existing member and throw an exception in
175         \c connectorSetup() or replace the \c boost::ptr_map by a \c boost::ptr_multimap using the
176         fourth template argument to MultiConnectorMixin.
177
178         \par "Example:" senf::ppi::module::AnnotationRouter
179
180         \section senf_ppi_multiconnector_connect Connect and additional connectorSetup() arguments
181
182         When connecting to a module using the MultiConnectorMixin, every new connect call will
183         allocate a new connector
184         \code
185         MyModule muModule;
186         
187         senf::ppi::connect(someModule, myModule);
188         \endcode
189         Some modules will expect additional arguments to be passed (see below)
190         \code
191         MyModule myModule;
192
193         senf::ppi::connect(mod1, myModule);     // index = 0, see below
194         senf::ppi::connect(mod2, myModule, 1);  // index = 1, see below
195         \endcode
196         To declare these additional arguments, just declare \c connectorSetup() with those
197         additional arguments:
198         \code
199         void connectorSetup(MyModule::ConnectorType & input, int index=0)
200         {
201             container().insert(container().begin()+index, container().pop_back().release());
202         }
203         \endcode
204
205         \par "Advanced note:" These additional arguments are always passed by const-reference. If
206             you need to pass a non-const reference, declare the \c connectorSetup() argument as
207             non-const reference and wrap the real argument using \c boost::ref() (The reason for
208             this is known as 'The forwarding problem'
209
210         \section senf_ppi_multiconnector_advanced Advanced usage: Managing your own container
211
212         If you need to use a completely different type of container, you can take over the container
213         management yourself. To do this, pass \c void as container type and change \c
214         connectorSetup() to take an \c std::auto_ptr as argument. \c connectorSetup() must ensure to
215         save this connector in some container or throw an exception
216         \code
217         class MyModule 
218             : public senf::ppi::module::Module,
219               public senf::ppi::module::MultiConnectorMixin<
220                   MyModule, senf::ppi::connector::ActiveInput<>, void, void >
221         {
222             SENF_PPI_MODULE(MyModule);
223         public:
224             // ...
225
226         private:
227             void connectorSetup(std::auto_ptr<ConnectorType> conn, unsigned p)
228             {
229                 if (p>connectors_.size())
230                    throw SomeErrorException();
231                 route(*conn, output);
232                 connectors_.insert(connectors_.begin()+p,conn);
233             }
234
235             boost::ptr_vector<ConnectorType> connectors_;
236         };
237         \endcode
238         \warning You must make absolutely sure the connector does not get deleted when returning
239             normally from \c connectorSetup(): The connector \e must be saved somewhere
240             successfully, otherwise your code will break.
241
242      */
243     template <class Self_, 
244               class ConnectorType_, 
245               class KeyType_=void, 
246               class ContainerType_=typename detail::MultiConnectorDefaultContainer<
247                                                KeyType_,ConnectorType_>::type>
248     class MultiConnectorMixin 
249         : private detail::MultiConnectorSelectBase<ConnectorType_>::type
250     {
251     public:
252         typedef ConnectorType_ ConnectorType; ///< Type of MultiConnector connector
253
254     protected:
255         typedef ContainerType_ ContainerType; ///< Type of connector container
256         ContainerType_ & connectors();        ///< Get connector container
257         ContainerType_ const & connectors() const; ///< Get connectors container (const)
258
259     private:
260 #if 0
261         // For exposition only
262         // Other implementations with 0..SENF_MULTI_CONNECTOR_MAX_ARGS arguments accordingly
263
264         tempalte <class A1>
265         ConnectorType_ & newConnector(A1 const & a1);
266
267 #endif
268 #ifndef DOXYGEN
269
270         // Include 'MultiConnectorMixin member declaration' from MultiConnectorMixin.mpp
271 #       define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
272             0, \
273             SENF_MULTI_CONNECTOR_MAX_ARGS, \
274             SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
275             1 ))
276 #       include BOOST_PP_ITERATE()
277
278 #       define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
279             0, \
280             SENF_MULTI_CONNECTOR_MAX_ARGS2, \
281             SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
282             9 ))
283 #       include BOOST_PP_ITERATE()
284
285 #endif
286
287         friend class detail::MultiConnectorMixinAccess;
288         
289         ContainerType_ connectors_;
290     };
291
292 #ifndef DOXYGEN
293
294     template <class Self_,
295               class ConnectorType_,
296               class ContainerType_>
297     class MultiConnectorMixin<Self_,ConnectorType_,void,ContainerType_>
298         : private detail::MultiConnectorSelectBase<ConnectorType_>::type
299     {
300     public:
301         typedef ConnectorType_ ConnectorType;
302         
303     protected:
304         typedef ContainerType_ ContainerType;
305         ContainerType_ & connectors();
306
307     private:
308
309 #if 0
310         // For exposition only
311         // Other implementations with 0..SENF_MULTI_CONNECTOR_MAX_ARGS arguments accordingly
312
313         tempalte <class A1>
314         ConnectorType_ & newConnector(A1 const & a1);
315
316         // See above for an additional note regarding the boost::enable_if in the real
317         // implementation
318         
319         template <class Source, class Target, class A1>
320         friend Source::ConnectorType & senf::ppi::connect(Source & source, 
321                                                           Target & target, 
322                                                           A1 const & a1);
323
324         template <class Source, class Target, class A1>
325         friend Target::ConnectorType & senf::ppi::connect(Source & source,
326                                                           Target & target,
327                                                           A1 const & a1);
328 #endif
329
330         // Include 'MultiConnectorMixin member declaration' from MultiConnectorMixin.mpp
331 #       define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
332             0, \
333             SENF_MULTI_CONNECTOR_MAX_ARGS, \
334             SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
335             1 ))
336 #       include BOOST_PP_ITERATE()
337         
338 #       define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
339             0, \
340             SENF_MULTI_CONNECTOR_MAX_ARGS2, \
341             SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
342             9 ))
343 #       include BOOST_PP_ITERATE()
344
345         friend class detail::MultiConnectorMixinAccess;
346
347         ContainerType_ connectors_;
348     };
349
350     template <class Self_, 
351               class ConnectorType_>
352     class MultiConnectorMixin<Self_,ConnectorType_,void,void>
353         : private detail::MultiConnectorSelectBase<ConnectorType_>::type
354     {
355     public:
356         typedef ConnectorType_ ConnectorType;
357
358     private:
359
360 #if 0
361         // For exposition only
362         // Other implementations with 0..SENF_MULTI_CONNECTOR_MAX_ARGS arguments accordingly
363
364         tempalte <class A1>
365         ConnectorType_ & newConnector(A1 const & a1);
366
367         // See above for an additional note regarding the boost::enable_if in the real
368         // implementation
369         
370         template <class Source, class Target, class A1>
371         friend Source::ConnectorType & senf::ppi::connect(Source & source, 
372                                                           Target & target, 
373                                                           A1 const & a1);
374
375         template <class Source, class Target, class A1>
376         friend Target::ConnectorType & senf::ppi::connect(Source & source,
377                                                           Target & target,
378                                                           A1 const & a1);
379 #endif
380
381         // Include 'MultiConnectorMixin member declaration' from MultiConnectorMixin.mpp
382 #       define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
383             0, \
384             SENF_MULTI_CONNECTOR_MAX_ARGS, \
385             SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
386             1 ))
387 #       include BOOST_PP_ITERATE()
388
389 #       define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
390             0, \
391             SENF_MULTI_CONNECTOR_MAX_ARGS2, \
392             SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
393             9 ))
394 #       include BOOST_PP_ITERATE()
395
396         friend class detail::MultiConnectorMixinAccess;
397     };
398
399 #endif
400         
401 }}}
402
403 ///////////////////////////////hh.e////////////////////////////////////////
404 //#include "MultiConnectorMixin.cci"
405 //#include "MultiConnectorMixin.ct"
406 #include "MultiConnectorMixin.cti"
407 #endif
408
409 \f
410 // Local Variables:
411 // mode: c++
412 // fill-column: 100
413 // comment-column: 40
414 // c-file-style: "senf"
415 // indent-tabs-mode: nil
416 // ispell-local-dictionary: "american"
417 // compile-command: "scons -u test"
418 // End: