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, A1 const & a1, Target & target);
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()
95 namespace detail { class MultiConnectorMixinAccess; }
97 /** \brief Multi connector management
99 This mixin provides a module with support for a runtime configurable number of input or
103 : public senf::ppi::module::Modulem,
104 public senf::ppi::module::MultiConnectorMixin<
105 MyModule, senf::ppi::connector::ActiveInput<> >
107 SENF_PPI_MODULE(MyModule);
109 senf::ppi::connector::PassiveOutput<> output;
114 void connectorSetup(senf::ppi::connector::ActiveInput & input)
116 route(input, output);
117 input.onThrottle(&MyModule::doThrottle);
125 friend class senf::ppi::module::MultiConnectorMixin<
126 MyModule, senf::ppi::connector::ActiveInput<> >
130 Using the MultiConnectorMixin consists of
131 \li inheriting from MultiConnectorMixin
132 \li defining a function \c connectorSetup
133 \li declaring the mixin as a friend
135 The MultiConnectorMixin takes several template arguments
136 \li the name of the derived class, \a Self_
137 \li the type of connector, \a ConnectorType_
138 \li an optional \a KeyType_ if a mapping container is required
139 \li an optional \a ContainerType_ to replace the default \c boost::ptr_vector or \c
142 \section senf_ppi_multiconnector_sequence Sequence/vector based multi connector mixin
144 If no \a KeyType_ is given (or the \a KeyType_ is \c void), the mixin will use a sequence
145 container, by default a \c boost::ptr_vector to store the connectors. In this case, new
146 connectors will be added to the end of the container. The \c connectorSetup() routine
147 however may be used to move the inserted connector to some other location, e.g.
149 container().insert(begin(), container().pop_back().release());
151 which will move the new connector from the end to the beginning.
152 \warning If you throw an exception from \c connectorSetup(), you must do so \e before moving
153 the new connector around since the mixin will remove the last element from the container
156 \par "Example:" senf::ppi::module::PriorityJoin
158 \section senf_ppi_multiconnector_map Map based multi connector mixin
160 If \a KeyType_ is given (and is not \c void), the mixin will use a mapping container, by
161 default a \c boost::ptr_map to store the connectors. The \c connectorSetup() member function
162 must return the key value under which the new connector will be stored. The new connector
163 will this be written to the container only \e after \c connectorSetup() returns.
165 When the returned key is not unique, the new connector will \e replace the old one. If this
166 is not, what you want, either check for an already existing member and throw an exception in
167 \c connectorSetup() or replace the \c boost::ptr_map by a \c boost::ptr_multimap using the
168 fourth template argument to MultiConnectorMixin.
170 \par "Example:" senf::ppi::module::AnnotationRouter
172 \section senf_ppi_multiconnector_connect Connect and additional connectorSetup() arguments
174 When connecting to a module using the MultiConnectorMixin, every new connect call will
175 allocate a new connector
179 senf::ppi::connect(someModule, myModule);
181 Some modules will expect additional arguments to be passed (see below)
185 senf::ppi::connect(mod1, myModule); // index = 0, see below
186 senf::ppi::connect(mod2, myModule, 1); // index = 1, see below
188 To declare these additional arguments, just declare \c connectorSetup() with those
189 additional arguments:
191 void connectorSetup(MyModule::ConnectorType & input, int index=0)
193 container().insert(container().begin()+index, container().pop_back().release());
197 \par "Advanced note:" These additional arguments are always passed by const-reference. If
198 you need to pass a non-const reference, declare the \c connectorSetup() argument as
199 non-const reference and wrap the real argument using \c boost::ref() (The reason for
200 this is known as 'The forwarding problem'
202 \section senf_ppi_multiconnector_advanced Advanced usage: Managing your own container
204 If you need to use a completely different type of container, you can take over the container
205 management yourself. To do this, pass \c void as container type and change \c
206 connectorSetup() to take an \c std::auto_ptr as argument. \c connectorSetup() must ensure to
207 save this connector in some container or throw an exception
210 : public senf::ppi::module::Module,
211 public senf::ppi::module::MultiConnectorMixin<
212 MyModule, senf::ppi::connector::ActiveInput<>, void, void >
214 SENF_PPI_MODULE(MyModule);
219 void connectorSetup(std::auto_ptr<ConnectorType> conn, unsigned p)
221 if (p>connectors_.size())
222 throw SomeErrorException();
223 route(*conn, output);
224 connectors_.insert(connectors_.begin()+p,conn);
227 boost::ptr_vector<ConnectorType> connectors_;
230 \warning You must make absolutely sure the connector does not get deleted when returning
231 normally from \c connectorSetup(): The connector \e must be saved somewhere
232 successfully, otherwise your code will break.
235 template <class Self_,
236 class ConnectorType_,
238 class ContainerType_=typename detail::MultiConnectorDefaultContainer<
239 KeyType_,ConnectorType_>::type>
240 class MultiConnectorMixin
241 : private detail::MultiConnectorSelectBase<ConnectorType_>::type
244 typedef ConnectorType_ ConnectorType; ///< Type of MultiConnector connector
247 typedef ContainerType_ ContainerType; ///< Type of connector container
248 ContainerType_ & connectors(); ///< Get connector container
249 ContainerType_ const & connectors() const; ///< Get connectors container (const)
253 // For exposition only
254 // Other implementations with 0..SENF_MULTI_CONNECTOR_MAX_ARGS arguments accordingly
257 ConnectorType_ & newConnector(A1 const & a1);
262 // Include 'MultiConnectorMixin member declaration' from MultiConnectorMixin.mpp
263 # define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
265 SENF_MULTI_CONNECTOR_MAX_ARGS, \
266 SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
268 # include BOOST_PP_ITERATE()
272 friend class detail::MultiConnectorMixinAccess;
274 ContainerType_ connectors_;
279 template <class Self_,
280 class ConnectorType_,
281 class ContainerType_>
282 class MultiConnectorMixin<Self_,ConnectorType_,void,ContainerType_>
283 : private detail::MultiConnectorSelectBase<ConnectorType_>::type
286 typedef ConnectorType_ ConnectorType;
289 typedef ContainerType_ ContainerType;
290 ContainerType_ & connectors();
295 // For exposition only
296 // Other implementations with 0..SENF_MULTI_CONNECTOR_MAX_ARGS arguments accordingly
299 ConnectorType_ & newConnector(A1 const & a1);
301 // See above for an additional note regarding the boost::enable_if in the real
304 template <class Source, class Target, class A1>
305 friend Source::ConnectorType & senf::ppi::connect(Source & source,
309 template <class Source, class Target, class A1>
310 friend Target::ConnectorType & senf::ppi::connect(Source & source,
315 // Include 'MultiConnectorMixin member declaration' from MultiConnectorMixin.mpp
316 # define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
318 SENF_MULTI_CONNECTOR_MAX_ARGS, \
319 SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
321 # include BOOST_PP_ITERATE()
323 # define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
325 2*SENF_MULTI_CONNECTOR_MAX_ARGS, \
326 SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
328 # include BOOST_PP_ITERATE()
330 friend class detail::MultiConnectorMixinAccess;
332 ContainerType_ connectors_;
335 template <class Self_,
336 class ConnectorType_>
337 class MultiConnectorMixin<Self_,ConnectorType_,void,void>
338 : private detail::MultiConnectorSelectBase<ConnectorType_>::type
341 typedef ConnectorType_ ConnectorType;
346 // For exposition only
347 // Other implementations with 0..SENF_MULTI_CONNECTOR_MAX_ARGS arguments accordingly
350 ConnectorType_ & newConnector(A1 const & a1);
352 // See above for an additional note regarding the boost::enable_if in the real
355 template <class Source, class Target, class A1>
356 friend Source::ConnectorType & senf::ppi::connect(Source & source,
360 template <class Source, class Target, class A1>
361 friend Target::ConnectorType & senf::ppi::connect(Source & source,
366 // Include 'MultiConnectorMixin member declaration' from MultiConnectorMixin.mpp
367 # define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
369 SENF_MULTI_CONNECTOR_MAX_ARGS, \
370 SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
372 # include BOOST_PP_ITERATE()
374 # define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
376 2*SENF_MULTI_CONNECTOR_MAX_ARGS, \
377 SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
379 # include BOOST_PP_ITERATE()
381 friend class detail::MultiConnectorMixinAccess;
388 ///////////////////////////////hh.e////////////////////////////////////////
389 //#include "MultiConnectorMixin.cci"
390 //#include "MultiConnectorMixin.ct"
391 #include "MultiConnectorMixin.cti"
398 // comment-column: 40
399 // c-file-style: "senf"
400 // indent-tabs-mode: nil
401 // ispell-local-dictionary: "american"
402 // compile-command: "scons -u test"