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