PPI: Stupidity bugfix ...
[senf.git] / 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 "../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 #include "MultiConnectorMixin.mpp"
38 #include "MultiConnectorMixin.ih"
39 ///////////////////////////////hh.p////////////////////////////////////////
40
41 #ifndef SENF_MULTI_CONNECTOR_MAX_ARGS
42 #define SENF_MULTI_CONNECTOR_MAX_ARGS 3
43 #endif
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 #else
77
78     // Include 'senf::ppi::namespace member declarations' from MultiConnectorMixin.mpp
79 #   define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
80             0, \
81             SENF_MULTI_CONNECTOR_MAX_ARGS, \
82             SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
83             2 ))
84 #   include BOOST_PP_ITERATE()
85
86 #endif
87
88 namespace module {
89
90     /** \brief Multi connector management
91
92         This mixin provides a module with support for a runtime configurable number of input or
93         output connectors.
94         \code
95         class MyModule 
96             : public senf::ppi::module::MultiConnectorMixin<
97                   MyModule, senf::ppi::connector::ActiveInput<> >
98         {
99             SENF_PPI_MODULE(MyModule);
100         public:
101             senf::ppi::connector::PassiveOutput<> output;
102
103             // ...
104
105         private:
106             void connectorSetup(senf::ppi::connector::ActiveInput & input)
107             {
108                 route(input, output);
109                 input.onThrottle(&MyModule::doThrottle);
110             }
111
112             void doThrottle()
113             { 
114                 // ...
115             }
116
117             friend class senf::ppi::module::MultiConnectorMixin<
118                 MyModule, senf::ppi::connector::ActiveInput<> >
119         }
120         \endcode
121
122         Using the MultiConnectorMixin consists of
123         \li inheriting from MultiConnectorMixin
124         \li defining a function \c connectorSetup
125         \li declaring the mixin as a friend
126
127         The MultiConnectorMixin takes several template arguments
128         \li the name of the derived class, \a Self_
129         \li the type of connector, \a ConnectorType_
130         \li an optional \a KeyType_ if a mapping container is required
131         \li an optional \a ContainerType_ to replace the default \c boost::ptr_vector or \c
132             boost::ptr_map.
133
134         \section senf_ppi_multiconnector_sequence Sequence/vector based multi connector mixin
135
136         If no \a KeyType_ is given (or the \a KeyType_ is \c void), the mixin will use a sequence
137         container, by default a \c boost::ptr_vector to store the connectors. In this case, new
138         connectors will be added to the end of the container. The \c connectorSetup() routine
139         however may be used to move the inserted connector to some other location, e.g.
140         \code
141         container().insert(begin(), container().pop_back().release());
142         \endcode
143         which will move the new connector from the end to the beginning. 
144         \warning If you throw an exception from \c connectorSetup(), you must do so \e before moving
145             the new connector around since the mixin will remove the last element from the container
146             on an exception.
147
148         \par "Example:" senf::ppi::module::PriorityJoin
149
150         \section senf_ppi_multiconnector_map Map based multi connector mixin
151
152         If \a KeyType_ is given (and is not \c void), the mixin will use a mapping container, by
153         default a \c boost::ptr_map to store the connectors. The \c connectorSetup() member function
154         must return the key value under which the new connector will be stored. The new connector
155         will this be written to the container only \e after \c connectorSetup() returns.
156
157         When the returned key is not unique, the new connector will \e replace the old one. If this
158         is not, what you want, either check for an already existing member and throw an exception in
159         \c connectorSetup() or replace the \c boost::ptr_map by a \c boost::ptr_multimap using the
160         fourth template argument to MultiConnectorMixin.
161
162         \par "Example:" senf::ppi::module::AnnotationRouter
163
164         \section senf_ppi_multiconnector_connect Connect and additional connectorSetup() arguments
165
166         When connecting to a module using the MultiConnectorMixin, every new connect call will
167         allocate a new connector
168         \code
169         MyModule muModule;
170         
171         senf::ppi::connect(someModule, myModule);
172         \endcode
173         Some modules will expect additional arguments to be passed (see below)
174         \code
175         MyModule myModule;
176
177         senf::ppi::connect(mod1, myModule);     // index = 0, see below
178         senf::ppi::connect(mod2, myModule, 1);  // index = 1, see below
179         \endcode
180         To declare these additional arguments, just declare \c connectorSetup() with those
181         additional arguments:
182         \code
183         void connectorSetup(MyModule::ConnectorType & input, int index=0)
184         {
185             container().insert(container().begin()+index, container().pop_back().release());
186         }
187         \endcode
188
189         \par "Advanced note:" These additional arguments are always passed by const-reference. If
190             you need to pass a non-const reference, declare the \c connectorSetup() argument as
191             non-const reference and wrap the real argument using \c boost::ref() (The reason for
192             this is known as 'The forwarding problem'
193      */
194     template <class Self_, 
195               class ConnectorType_, 
196               class KeyType_=void, 
197               class ContainerType_=typename detail::MultiConnectorDefaultContainer<
198                                                KeyType_,ConnectorType_>::type>
199     class MultiConnectorMixin 
200         : private detail::MultiConnectorSelectBase<ConnectorType_>::type
201     {
202     public:
203         typedef ConnectorType_ ConnectorType; ///< Type of MultiConnector connector
204
205     protected:
206         typedef ContainerType_ ContainerType; ///< Type of connector container
207         ContainerType_ & connectors();        ///< Get connector container
208         ContainerType_ const & connectors() const; ///< Get connectors container (const)
209
210     private:
211 #if 0
212         // For exposition only
213         // Other implementations with 0..SENF_MULTI_CONNECTOR_MAX_ARGS arguments accordingly
214
215         tempalte <class A1>
216         ConnectorType_ & newConnector(A1 const & a1);
217
218         // See above for an additional note regarding the boost::enable_if in the real
219         // implementation
220         
221         template <class Source, class Target, class A1>
222         friend Source::ConnectorType & senf::ppi::connect(Source & source, 
223                                                           Target & target, 
224                                                           A1 const & a1);
225
226         template <class Source, class Target, class A1>
227         friend Target::ConnectorType & senf::ppi::connect(Source & source,
228                                                           Target & target,
229                                                           A1 const & a1);
230 #endif
231 #ifndef DOXYGEN
232
233         // Include 'MultiConnectorMixin member declaration' from MultiConnectorMixin.mpp
234 #       define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
235             0, \
236             SENF_MULTI_CONNECTOR_MAX_ARGS, \
237             SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
238             1 ))
239 #       include BOOST_PP_ITERATE()
240
241 #endif
242         
243         ContainerType_ connectors_;
244     };
245
246 #ifndef DOXYGEN
247
248     template <class Self_,
249               class ConnectorType_,
250               class ContainerType_>
251     class MultiConnectorMixin<Self_,ConnectorType_,void,ContainerType_>
252         : private detail::MultiConnectorSelectBase<ConnectorType_>::type
253     {
254     public:
255         typedef ConnectorType_ ConnectorType;
256         
257     protected:
258         typedef ContainerType_ ContainerType;
259         ContainerType_ & connectors();
260
261     private:
262
263 #if 0
264         // For exposition only
265         // Other implementations with 0..SENF_MULTI_CONNECTOR_MAX_ARGS arguments accordingly
266
267         tempalte <class A1>
268         ConnectorType_ & newConnector(A1 const & a1);
269
270         // See above for an additional note regarding the boost::enable_if in the real
271         // implementation
272         
273         template <class Source, class Target, class A1>
274         friend Source::ConnectorType & senf::ppi::connect(Source & source, 
275                                                           Target & target, 
276                                                           A1 const & a1);
277
278         template <class Source, class Target, class A1>
279         friend Target::ConnectorType & senf::ppi::connect(Source & source,
280                                                           Target & target,
281                                                           A1 const & a1);
282 #endif
283
284         // Include 'MultiConnectorMixin member declaration' from MultiConnectorMixin.mpp
285 #       define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
286             0, \
287             SENF_MULTI_CONNECTOR_MAX_ARGS, \
288             SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
289             1 ))
290 #       include BOOST_PP_ITERATE()
291         
292         ContainerType_ connectors_;
293     };
294
295 #endif
296         
297 }}}
298
299 ///////////////////////////////hh.e////////////////////////////////////////
300 //#include "MultiConnectorMixin.cci"
301 //#include "MultiConnectorMixin.ct"
302 #include "MultiConnectorMixin.cti"
303 #endif
304
305 \f
306 // Local Variables:
307 // mode: c++
308 // fill-column: 100
309 // comment-column: 40
310 // c-file-style: "senf"
311 // indent-tabs-mode: nil
312 // ispell-local-dictionary: "american"
313 // compile-command: "scons -u test"
314 // End: