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