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