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 <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"
37 #ifndef SENF_MULTI_CONNECTOR_MAX_ARGS
38 #define SENF_MULTI_CONNECTOR_MAX_ARGS 3
41 #include "MultiConnectorMixin.mpp"
42 #include "MultiConnectorMixin.ih"
43 ///////////////////////////////hh.p////////////////////////////////////////
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);
76 template <class MultiConnectorSource, class MultiConnectorTarget, class A1, class A2>
77 std::pair<MultiConnectorSource::ConnectorType &, MultiConnectorTarget::ConnectorType &>
79 MultiConnectorSource & source, MultiConnectorTarget & target, A1 const & a1, A2 const & a2);
83 // Include 'senf::ppi namespace member declarations' from MultiConnectorMixin.mpp
84 # define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
86 SENF_MULTI_CONNECTOR_MAX_ARGS, \
87 SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
89 # include BOOST_PP_ITERATE()
91 # define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
93 2*SENF_MULTI_CONNECTOR_MAX_ARGS, \
94 SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
96 # include BOOST_PP_ITERATE()
102 namespace detail { class MultiConnectorMixinAccess; }
104 /** \brief Multi connector management
106 This mixin provides a module with support for a runtime configurable number of input or
110 : public senf::ppi::module::Modulem,
111 public senf::ppi::module::MultiConnectorMixin<
112 MyModule, senf::ppi::connector::ActiveInput<> >
114 SENF_PPI_MODULE(MyModule);
116 senf::ppi::connector::PassiveOutput<> output;
121 void connectorSetup(senf::ppi::connector::ActiveInput & input)
123 route(input, output);
124 input.onThrottle(&MyModule::doThrottle);
132 friend class senf::ppi::module::MultiConnectorMixin<
133 MyModule, senf::ppi::connector::ActiveInput<> >
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
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
149 \section senf_ppi_multiconnector_sequence Sequence/vector based multi connector mixin
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.
156 container().insert(begin(), container().pop_back().release());
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
163 \par "Example:" senf::ppi::module::PriorityJoin
165 \section senf_ppi_multiconnector_map Map based multi connector mixin
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.
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.
177 \par "Example:" senf::ppi::module::AnnotationRouter
179 \section senf_ppi_multiconnector_connect Connect and additional connectorSetup() arguments
181 When connecting to a module using the MultiConnectorMixin, every new connect call will
182 allocate a new connector
186 senf::ppi::connect(someModule, myModule);
188 Some modules will expect additional arguments to be passed (see below)
192 senf::ppi::connect(mod1, myModule); // index = 0, see below
193 senf::ppi::connect(mod2, myModule, 1); // index = 1, see below
195 To declare these additional arguments, just declare \c connectorSetup() with those
196 additional arguments:
198 void connectorSetup(MyModule::ConnectorType & input, int index=0)
200 container().insert(container().begin()+index, container().pop_back().release());
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'
209 \section senf_ppi_multiconnector_advanced Advanced usage: Managing your own container
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
217 : public senf::ppi::module::Module,
218 public senf::ppi::module::MultiConnectorMixin<
219 MyModule, senf::ppi::connector::ActiveInput<>, void, void >
221 SENF_PPI_MODULE(MyModule);
226 void connectorSetup(std::auto_ptr<ConnectorType> conn, unsigned p)
228 if (p>connectors_.size())
229 throw SomeErrorException();
230 route(*conn, output);
231 connectors_.insert(connectors_.begin()+p,conn);
234 boost::ptr_vector<ConnectorType> connectors_;
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.
242 template <class Self_,
243 class ConnectorType_,
245 class ContainerType_=typename detail::MultiConnectorDefaultContainer<
246 KeyType_,ConnectorType_>::type>
247 class MultiConnectorMixin
248 : private detail::MultiConnectorSelectBase<ConnectorType_>::type
251 typedef ConnectorType_ ConnectorType; ///< Type of MultiConnector connector
254 typedef ContainerType_ ContainerType; ///< Type of connector container
255 ContainerType_ & connectors(); ///< Get connector container
256 ContainerType_ const & connectors() const; ///< Get connectors container (const)
260 // For exposition only
261 // Other implementations with 0..SENF_MULTI_CONNECTOR_MAX_ARGS arguments accordingly
264 ConnectorType_ & newConnector(A1 const & a1);
269 // Include 'MultiConnectorMixin member declaration' from MultiConnectorMixin.mpp
270 # define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
272 SENF_MULTI_CONNECTOR_MAX_ARGS, \
273 SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
275 # include BOOST_PP_ITERATE()
277 # define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
279 2*SENF_MULTI_CONNECTOR_MAX_ARGS, \
280 SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
282 # include BOOST_PP_ITERATE()
286 friend class detail::MultiConnectorMixinAccess;
288 ContainerType_ connectors_;
293 template <class Self_,
294 class ConnectorType_,
295 class ContainerType_>
296 class MultiConnectorMixin<Self_,ConnectorType_,void,ContainerType_>
297 : private detail::MultiConnectorSelectBase<ConnectorType_>::type
300 typedef ConnectorType_ ConnectorType;
303 typedef ContainerType_ ContainerType;
304 ContainerType_ & connectors();
309 // For exposition only
310 // Other implementations with 0..SENF_MULTI_CONNECTOR_MAX_ARGS arguments accordingly
313 ConnectorType_ & newConnector(A1 const & a1);
315 // See above for an additional note regarding the boost::enable_if in the real
318 template <class Source, class Target, class A1>
319 friend Source::ConnectorType & senf::ppi::connect(Source & source,
323 template <class Source, class Target, class A1>
324 friend Target::ConnectorType & senf::ppi::connect(Source & source,
329 // Include 'MultiConnectorMixin member declaration' from MultiConnectorMixin.mpp
330 # define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
332 SENF_MULTI_CONNECTOR_MAX_ARGS, \
333 SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
335 # include BOOST_PP_ITERATE()
337 # define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
339 2*SENF_MULTI_CONNECTOR_MAX_ARGS, \
340 SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
342 # include BOOST_PP_ITERATE()
344 friend class detail::MultiConnectorMixinAccess;
346 ContainerType_ connectors_;
349 template <class Self_,
350 class ConnectorType_>
351 class MultiConnectorMixin<Self_,ConnectorType_,void,void>
352 : private detail::MultiConnectorSelectBase<ConnectorType_>::type
355 typedef ConnectorType_ ConnectorType;
360 // For exposition only
361 // Other implementations with 0..SENF_MULTI_CONNECTOR_MAX_ARGS arguments accordingly
364 ConnectorType_ & newConnector(A1 const & a1);
366 // See above for an additional note regarding the boost::enable_if in the real
369 template <class Source, class Target, class A1>
370 friend Source::ConnectorType & senf::ppi::connect(Source & source,
374 template <class Source, class Target, class A1>
375 friend Target::ConnectorType & senf::ppi::connect(Source & source,
380 // Include 'MultiConnectorMixin member declaration' from MultiConnectorMixin.mpp
381 # define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
383 SENF_MULTI_CONNECTOR_MAX_ARGS, \
384 SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
386 # include BOOST_PP_ITERATE()
388 # define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
390 2*SENF_MULTI_CONNECTOR_MAX_ARGS, \
391 SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
393 # include BOOST_PP_ITERATE()
395 friend class detail::MultiConnectorMixinAccess;
402 ///////////////////////////////hh.e////////////////////////////////////////
403 //#include "MultiConnectorMixin.cci"
404 //#include "MultiConnectorMixin.ct"
405 #include "MultiConnectorMixin.cti"
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"