4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 // Stefan Bund <g0dil@berlios.de>
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.
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.
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.
24 \brief MultiConnectorMixin public header */
26 #ifndef HH_SENF_PPI_MultiConnectorMixin_
27 #define HH_SENF_PPI_MultiConnectorMixin_ 1
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"
37 #include "MultiConnectorMixin.mpp"
38 #include "MultiConnectorMixin.ih"
39 ///////////////////////////////hh.p////////////////////////////////////////
41 #ifndef SENF_MULTI_CONNECTOR_MAX_ARGS
42 #define SENF_MULTI_CONNECTOR_MAX_ARGS 3
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.
56 /** \brief Connect MultiConnector source to arbitrary target
58 Additional implementations with 0..SENF_MULTI_CONNECTOR_MAX_ARGS arguments.
60 \related module::MultiConnectorMixin
62 template <class MultiConnectorSource, class Target, class A1>
63 MultiConnectorSource::ConnectorType & connect(
64 MultiConnectorSource & source, Target & target, A1 const & a1);
66 /** \brief Connect arbitrary source to MultiConnector target
68 Additional implementations with 0..SENF_MULTI_CONNECTOR_MAX_ARGS arguments.
70 \related module::MultiConnectorMixin
72 template <class Source, class MultiConnectorTarget, class A1>
73 MultiConnectorTarget::ConnectorType & connect(
74 Source & source, MultiConnectorTarget & target, A1 const & a1);
78 // Include 'senf::ppi::namespace member declarations' from MultiConnectorMixin.mpp
79 # define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
81 SENF_MULTI_CONNECTOR_MAX_ARGS, \
82 SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
84 # include BOOST_PP_ITERATE()
90 /** \brief Multi connector management
92 This mixin provides a module with support for a runtime configurable number of input or
96 : public senf::ppi::module::Modulem,
97 public senf::ppi::module::MultiConnectorMixin<
98 MyModule, senf::ppi::connector::ActiveInput<> >
100 SENF_PPI_MODULE(MyModule);
102 senf::ppi::connector::PassiveOutput<> output;
107 void connectorSetup(senf::ppi::connector::ActiveInput & input)
109 route(input, output);
110 input.onThrottle(&MyModule::doThrottle);
118 friend class senf::ppi::module::MultiConnectorMixin<
119 MyModule, senf::ppi::connector::ActiveInput<> >
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
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
135 \section senf_ppi_multiconnector_sequence Sequence/vector based multi connector mixin
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.
142 container().insert(begin(), container().pop_back().release());
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
149 \par "Example:" senf::ppi::module::PriorityJoin
151 \section senf_ppi_multiconnector_map Map based multi connector mixin
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.
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.
163 \par "Example:" senf::ppi::module::AnnotationRouter
165 \section senf_ppi_multiconnector_connect Connect and additional connectorSetup() arguments
167 When connecting to a module using the MultiConnectorMixin, every new connect call will
168 allocate a new connector
172 senf::ppi::connect(someModule, myModule);
174 Some modules will expect additional arguments to be passed (see below)
178 senf::ppi::connect(mod1, myModule); // index = 0, see below
179 senf::ppi::connect(mod2, myModule, 1); // index = 1, see below
181 To declare these additional arguments, just declare \c connectorSetup() with those
182 additional arguments:
184 void connectorSetup(MyModule::ConnectorType & input, int index=0)
186 container().insert(container().begin()+index, container().pop_back().release());
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'
195 \section senf_ppi_multiconnector_advanced Advanced usage: Managing your own container
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
203 : public senf::ppi::module::Module,
204 public senf::ppi::module::MultiConnectorMixin<
205 MyModule, senf::ppi::connector::ActiveInput<>, void, void >
207 SENF_PPI_MODULE(MyModule);
212 void connectorSetup(std::auto_ptr<ConnectorType> conn, unsigned p)
214 if (p>connectors_.size())
215 throw SomeErrorException();
216 route(*conn, output);
217 connectors_.insert(connectors_.begin()+p,conn);
220 boost::ptr_vector<ConnectorType> connectors_;
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.
228 template <class Self_,
229 class ConnectorType_,
231 class ContainerType_=typename detail::MultiConnectorDefaultContainer<
232 KeyType_,ConnectorType_>::type>
233 class MultiConnectorMixin
234 : private detail::MultiConnectorSelectBase<ConnectorType_>::type
237 typedef ConnectorType_ ConnectorType; ///< Type of MultiConnector connector
240 typedef ContainerType_ ContainerType; ///< Type of connector container
241 ContainerType_ & connectors(); ///< Get connector container
242 ContainerType_ const & connectors() const; ///< Get connectors container (const)
246 // For exposition only
247 // Other implementations with 0..SENF_MULTI_CONNECTOR_MAX_ARGS arguments accordingly
250 ConnectorType_ & newConnector(A1 const & a1);
252 // See above for an additional note regarding the boost::enable_if in the real
255 template <class Source, class Target, class A1>
256 friend Source::ConnectorType & senf::ppi::connect(Source & source,
260 template <class Source, class Target, class A1>
261 friend Target::ConnectorType & senf::ppi::connect(Source & source,
267 // Include 'MultiConnectorMixin member declaration' from MultiConnectorMixin.mpp
268 # define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
270 SENF_MULTI_CONNECTOR_MAX_ARGS, \
271 SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
273 # include BOOST_PP_ITERATE()
277 ContainerType_ connectors_;
282 template <class Self_,
283 class ConnectorType_,
284 class ContainerType_>
285 class MultiConnectorMixin<Self_,ConnectorType_,void,ContainerType_>
286 : private detail::MultiConnectorSelectBase<ConnectorType_>::type
289 typedef ConnectorType_ ConnectorType;
292 typedef ContainerType_ ContainerType;
293 ContainerType_ & connectors();
298 // For exposition only
299 // Other implementations with 0..SENF_MULTI_CONNECTOR_MAX_ARGS arguments accordingly
302 ConnectorType_ & newConnector(A1 const & a1);
304 // See above for an additional note regarding the boost::enable_if in the real
307 template <class Source, class Target, class A1>
308 friend Source::ConnectorType & senf::ppi::connect(Source & source,
312 template <class Source, class Target, class A1>
313 friend Target::ConnectorType & senf::ppi::connect(Source & source,
318 // Include 'MultiConnectorMixin member declaration' from MultiConnectorMixin.mpp
319 # define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
321 SENF_MULTI_CONNECTOR_MAX_ARGS, \
322 SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
324 # include BOOST_PP_ITERATE()
326 ContainerType_ connectors_;
329 template <class Self_,
330 class ConnectorType_>
331 class MultiConnectorMixin<Self_,ConnectorType_,void,void>
332 : private detail::MultiConnectorSelectBase<ConnectorType_>::type
335 typedef ConnectorType_ ConnectorType;
340 // For exposition only
341 // Other implementations with 0..SENF_MULTI_CONNECTOR_MAX_ARGS arguments accordingly
344 ConnectorType_ & newConnector(A1 const & a1);
346 // See above for an additional note regarding the boost::enable_if in the real
349 template <class Source, class Target, class A1>
350 friend Source::ConnectorType & senf::ppi::connect(Source & source,
354 template <class Source, class Target, class A1>
355 friend Target::ConnectorType & senf::ppi::connect(Source & source,
360 // Include 'MultiConnectorMixin member declaration' from MultiConnectorMixin.mpp
361 # define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
363 SENF_MULTI_CONNECTOR_MAX_ARGS, \
364 SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
366 # include BOOST_PP_ITERATE()
373 ///////////////////////////////hh.e////////////////////////////////////////
374 //#include "MultiConnectorMixin.cci"
375 //#include "MultiConnectorMixin.ct"
376 #include "MultiConnectorMixin.cti"
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"