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
39 #define SENF_MULTI_CONNECTOR_MAX_ARGS2 6
42 #include "MultiConnectorMixin.mpp"
43 #include "MultiConnectorMixin.ih"
44 ///////////////////////////////hh.p////////////////////////////////////////
51 // For exposition only.
52 // Other implementations with 0..SENF_MULTI_CONNECTOR_MAX_ARGS arguments accordingly
53 // The real implementation includes a boost::enable_if condition in the return value, which is
54 // used to only enable the correct overload: The first overload, if the MultiConnector is an
55 // output, otherwise the second overload.
57 /** \brief Connect MultiConnector source to arbitrary target
59 Additional implementations with 0..SENF_MULTI_CONNECTOR_MAX_ARGS arguments.
61 \related module::MultiConnectorMixin
63 template <class MultiConnectorSource, class Target, class A1>
64 MultiConnectorSource::ConnectorType & connect(
65 MultiConnectorSource & source, Target & target, A1 const & a1);
67 /** \brief Connect arbitrary source to MultiConnector target
69 Additional implementations with 0..SENF_MULTI_CONNECTOR_MAX_ARGS arguments.
71 \related module::MultiConnectorMixin
73 template <class Source, class MultiConnectorTarget, class A1>
74 MultiConnectorTarget::ConnectorType & connect(
75 Source & source, MultiConnectorTarget & target, A1 const & a1);
77 template <class MultiConnectorSource, class MultiConnectorTarget, class A1, class A2>
78 std::pair<MultiConnectorSource::ConnectorType &, MultiConnectorTarget::ConnectorType &>
80 MultiConnectorSource & source, MultiConnectorTarget & target, A1 const & a1, A2 const & a2);
84 // Include 'senf::ppi namespace member declarations' from MultiConnectorMixin.mpp
85 # define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
87 SENF_MULTI_CONNECTOR_MAX_ARGS, \
88 SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
90 # include BOOST_PP_ITERATE()
92 # define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
94 SENF_MULTI_CONNECTOR_MAX_ARGS2, \
95 SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
97 # include BOOST_PP_ITERATE()
103 namespace detail { class MultiConnectorMixinAccess; }
105 /** \brief Multi connector management
107 This mixin provides a module with support for a runtime configurable number of input or
111 : public senf::ppi::module::Modulem,
112 public senf::ppi::module::MultiConnectorMixin<
113 MyModule, senf::ppi::connector::ActiveInput<> >
115 SENF_PPI_MODULE(MyModule);
117 senf::ppi::connector::PassiveOutput<> output;
122 void connectorSetup(senf::ppi::connector::ActiveInput & input)
124 route(input, output);
125 input.onThrottle(&MyModule::doThrottle);
133 friend class senf::ppi::module::MultiConnectorMixin<
134 MyModule, senf::ppi::connector::ActiveInput<> >
138 Using the MultiConnectorMixin consists of
139 \li inheriting from MultiConnectorMixin
140 \li defining a function \c connectorSetup
141 \li declaring the mixin as a friend
143 The MultiConnectorMixin takes several template arguments
144 \li the name of the derived class, \a Self_
145 \li the type of connector, \a ConnectorType_
146 \li an optional \a KeyType_ if a mapping container is required
147 \li an optional \a ContainerType_ to replace the default \c boost::ptr_vector or \c
150 \section senf_ppi_multiconnector_sequence Sequence/vector based multi connector mixin
152 If no \a KeyType_ is given (or the \a KeyType_ is \c void), the mixin will use a sequence
153 container, by default a \c boost::ptr_vector to store the connectors. In this case, new
154 connectors will be added to the end of the container. The \c connectorSetup() routine
155 however may be used to move the inserted connector to some other location, e.g.
157 container().insert(begin(), container().pop_back().release());
159 which will move the new connector from the end to the beginning.
160 \warning If you throw an exception from \c connectorSetup(), you must do so \e before moving
161 the new connector around since the mixin will remove the last element from the container
164 \par "Example:" senf::ppi::module::PriorityJoin
166 \section senf_ppi_multiconnector_map Map based multi connector mixin
168 If \a KeyType_ is given (and is not \c void), the mixin will use a mapping container, by
169 default a \c boost::ptr_map to store the connectors. The \c connectorSetup() member function
170 must return the key value under which the new connector will be stored. The new connector
171 will this be written to the container only \e after \c connectorSetup() returns.
173 When the returned key is not unique, the new connector will \e replace the old one. If this
174 is not, what you want, either check for an already existing member and throw an exception in
175 \c connectorSetup() or replace the \c boost::ptr_map by a \c boost::ptr_multimap using the
176 fourth template argument to MultiConnectorMixin.
178 \par "Example:" senf::ppi::module::AnnotationRouter
180 \section senf_ppi_multiconnector_connect Connect and additional connectorSetup() arguments
182 When connecting to a module using the MultiConnectorMixin, every new connect call will
183 allocate a new connector
187 senf::ppi::connect(someModule, myModule);
189 Some modules will expect additional arguments to be passed (see below)
193 senf::ppi::connect(mod1, myModule); // index = 0, see below
194 senf::ppi::connect(mod2, myModule, 1); // index = 1, see below
196 To declare these additional arguments, just declare \c connectorSetup() with those
197 additional arguments:
199 void connectorSetup(MyModule::ConnectorType & input, int index=0)
201 container().insert(container().begin()+index, container().pop_back().release());
205 \par "Advanced note:" These additional arguments are always passed by const-reference. If
206 you need to pass a non-const reference, declare the \c connectorSetup() argument as
207 non-const reference and wrap the real argument using \c boost::ref() (The reason for
208 this is known as 'The forwarding problem'
210 \section senf_ppi_multiconnector_advanced Advanced usage: Managing your own container
212 If you need to use a completely different type of container, you can take over the container
213 management yourself. To do this, pass \c void as container type and change \c
214 connectorSetup() to take an \c std::auto_ptr as argument. \c connectorSetup() must ensure to
215 save this connector in some container or throw an exception
218 : public senf::ppi::module::Module,
219 public senf::ppi::module::MultiConnectorMixin<
220 MyModule, senf::ppi::connector::ActiveInput<>, void, void >
222 SENF_PPI_MODULE(MyModule);
227 void connectorSetup(std::auto_ptr<ConnectorType> conn, unsigned p)
229 if (p>connectors_.size())
230 throw SomeErrorException();
231 route(*conn, output);
232 connectors_.insert(connectors_.begin()+p,conn);
235 boost::ptr_vector<ConnectorType> connectors_;
238 \warning You must make absolutely sure the connector does not get deleted when returning
239 normally from \c connectorSetup(): The connector \e must be saved somewhere
240 successfully, otherwise your code will break.
243 template <class Self_,
244 class ConnectorType_,
246 class ContainerType_=typename detail::MultiConnectorDefaultContainer<
247 KeyType_,ConnectorType_>::type>
248 class MultiConnectorMixin
249 : private detail::MultiConnectorSelectBase<ConnectorType_>::type
252 typedef ConnectorType_ ConnectorType; ///< Type of MultiConnector connector
255 typedef ContainerType_ ContainerType; ///< Type of connector container
256 ContainerType_ & connectors(); ///< Get connector container
257 ContainerType_ const & connectors() const; ///< Get connectors container (const)
261 // For exposition only
262 // Other implementations with 0..SENF_MULTI_CONNECTOR_MAX_ARGS arguments accordingly
265 ConnectorType_ & newConnector(A1 const & a1);
270 // Include 'MultiConnectorMixin member declaration' from MultiConnectorMixin.mpp
271 # define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
273 SENF_MULTI_CONNECTOR_MAX_ARGS, \
274 SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
276 # include BOOST_PP_ITERATE()
278 # define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
280 SENF_MULTI_CONNECTOR_MAX_ARGS2, \
281 SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
283 # include BOOST_PP_ITERATE()
287 friend class detail::MultiConnectorMixinAccess;
289 ContainerType_ connectors_;
294 template <class Self_,
295 class ConnectorType_,
296 class ContainerType_>
297 class MultiConnectorMixin<Self_,ConnectorType_,void,ContainerType_>
298 : private detail::MultiConnectorSelectBase<ConnectorType_>::type
301 typedef ConnectorType_ ConnectorType;
304 typedef ContainerType_ ContainerType;
305 ContainerType_ & connectors();
310 // For exposition only
311 // Other implementations with 0..SENF_MULTI_CONNECTOR_MAX_ARGS arguments accordingly
314 ConnectorType_ & newConnector(A1 const & a1);
316 // See above for an additional note regarding the boost::enable_if in the real
319 template <class Source, class Target, class A1>
320 friend Source::ConnectorType & senf::ppi::connect(Source & source,
324 template <class Source, class Target, class A1>
325 friend Target::ConnectorType & senf::ppi::connect(Source & source,
330 // Include 'MultiConnectorMixin member declaration' from MultiConnectorMixin.mpp
331 # define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
333 SENF_MULTI_CONNECTOR_MAX_ARGS, \
334 SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
336 # include BOOST_PP_ITERATE()
338 # define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
340 SENF_MULTI_CONNECTOR_MAX_ARGS2, \
341 SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
343 # include BOOST_PP_ITERATE()
345 friend class detail::MultiConnectorMixinAccess;
347 ContainerType_ connectors_;
350 template <class Self_,
351 class ConnectorType_>
352 class MultiConnectorMixin<Self_,ConnectorType_,void,void>
353 : private detail::MultiConnectorSelectBase<ConnectorType_>::type
356 typedef ConnectorType_ ConnectorType;
361 // For exposition only
362 // Other implementations with 0..SENF_MULTI_CONNECTOR_MAX_ARGS arguments accordingly
365 ConnectorType_ & newConnector(A1 const & a1);
367 // See above for an additional note regarding the boost::enable_if in the real
370 template <class Source, class Target, class A1>
371 friend Source::ConnectorType & senf::ppi::connect(Source & source,
375 template <class Source, class Target, class A1>
376 friend Target::ConnectorType & senf::ppi::connect(Source & source,
381 // Include 'MultiConnectorMixin member declaration' from MultiConnectorMixin.mpp
382 # define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
384 SENF_MULTI_CONNECTOR_MAX_ARGS, \
385 SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
387 # include BOOST_PP_ITERATE()
389 # define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
391 SENF_MULTI_CONNECTOR_MAX_ARGS2, \
392 SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
394 # include BOOST_PP_ITERATE()
396 friend class detail::MultiConnectorMixinAccess;
403 ///////////////////////////////hh.e////////////////////////////////////////
404 //#include "MultiConnectorMixin.cci"
405 //#include "MultiConnectorMixin.ct"
406 #include "MultiConnectorMixin.cti"
413 // comment-column: 40
414 // c-file-style: "senf"
415 // indent-tabs-mode: nil
416 // ispell-local-dictionary: "american"
417 // compile-command: "scons -u test"