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::Module,
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);
121 void connectorDestroy(senf::ppi::connector::ActiveInput const & input)
131 friend class senf::ppi::module::MultiConnectorMixin<
132 MyModule, senf::ppi::connector::ActiveInput<> >;
136 Using the MultiConnectorMixin consists of
137 \li inheriting from MultiConnectorMixin
138 \li defining a function \c connectorSetup
139 \li declaring the mixin as a friend
140 \li optionally defining \c connectorDestroy to be notified when connectors are disconnected
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. If you want to abort adding
159 the new connector, you may throw an exception.
161 \par "Example:" senf::ppi::module::PriorityJoin
163 \section senf_ppi_multiconnector_map Map based multi connector mixin
165 If \a KeyType_ is given (and is not \c void), the mixin will use a mapping container, by
166 default a \c boost::ptr_map to store the connectors. The \c connectorSetup() member function
167 must return the key value under which the new connector will be stored. The new connector
168 will this be written to the container only \e after \c connectorSetup() returns.
170 When the returned key is not unique, the new connector will \e replace the old one. If this
171 is not what you want, either check for an already existing member and throw an exception in
172 \c connectorSetup() or replace the \c boost::ptr_map by a \c boost::ptr_multimap using the
173 fourth template argument to MultiConnectorMixin.
175 \par "Example:" senf::ppi::module::AnnotationRouter
177 \section senf_ppi_multiconnector_connect Connect and additional connectorSetup() arguments
179 When connecting to a module using the MultiConnectorMixin, every new connect call will
180 allocate a new connector
184 senf::ppi::connect(someModule, myModule);
186 Some modules will expect additional arguments to be passed (see below)
190 senf::ppi::connect(mod1, myModule); // index = 0, see below
191 senf::ppi::connect(mod2, myModule, 1); // index = 1, see below
193 To declare these additional arguments, just declare \c connectorSetup() with those
194 additional arguments:
196 void connectorSetup(MyModule::ConnectorType & input, int index=0)
198 container().insert(container().begin()+index, container().pop_back().release());
202 \par "Advanced note:" These additional arguments are always passed by const-reference. If
203 you need to pass a non-const reference, declare the \c connectorSetup() argument as
204 non-const reference and wrap the real argument using \c boost::ref() (The reason for
205 this is known as 'The forwarding problem').
207 \section senf_ppi_multiconnector_advanced Advanced usage: Managing your own container
209 If you need to use a completely different type of container, you can take over the container
210 management yourself. To do this, pass \c void as container type and change \c
211 connectorSetup() to take an \c std::auto_ptr as argument. \c connectorSetup() must ensure to
212 save this connector in some container or throw an exception.
214 Implementing \c connectorDestroy now is \e mandatory. The signature is changed to take a
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 void connectorDestroy(ConnectorType const * conn)
237 using boost::lambda::_1;
238 boost::ptr_vector<ConnectorType>::iterator i (
239 std::find_if(connectors_.begin(),connectors_.end(), &_1==conn))
240 if (i != connectors_.end())
241 connectors_.erase(i);
244 boost::ptr_vector<ConnectorType> connectors_;
247 \warning You must make absolutely sure the connector does not get deleted when returning
248 normally from \c connectorSetup(): The connector \e must be saved somewhere
249 successfully, otherwise your code will break.
252 template <class Self_,
253 class ConnectorType_,
255 class ContainerType_=typename detail::MultiConnectorDefaultContainer<
256 KeyType_,ConnectorType_>::type>
257 class MultiConnectorMixin
258 : private detail::MultiConnectorSelectBase<ConnectorType_>::type
261 typedef ConnectorType_ ConnectorType; ///< Type of MultiConnector connector
264 typedef ContainerType_ ContainerType; ///< Type of connector container
266 ContainerType_ & connectors(); ///< Get connector container
267 ContainerType_ const & connectors() const; ///< Get connectors container (const)
269 void connectorDestroy(ConnectorType const &);
275 // Include 'MultiConnectorMixin member declaration' from MultiConnectorMixin.mpp
276 # define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
278 SENF_MULTI_CONNECTOR_MAX_ARGS, \
279 SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
281 # include BOOST_PP_ITERATE()
285 void disconnected(ConnectorType_ const & c);
287 friend class detail::MultiConnectorMixinAccess;
288 friend class detail::MultiConnectorWrapper<Self_,ConnectorType_>;
290 ContainerType_ connectors_;
295 template <class Self_,
296 class ConnectorType_,
297 class ContainerType_>
298 class MultiConnectorMixin<Self_,ConnectorType_,void,ContainerType_>
299 : private detail::MultiConnectorSelectBase<ConnectorType_>::type
302 typedef ConnectorType_ ConnectorType;
305 typedef ContainerType_ ContainerType;
307 ContainerType_ & connectors();
308 ContainerType_ const & connectors() const;
310 void connectorDestroy(ConnectorType const &);
314 // Include 'MultiConnectorMixin member declaration' from MultiConnectorMixin.mpp
315 # define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
317 SENF_MULTI_CONNECTOR_MAX_ARGS, \
318 SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
320 # include BOOST_PP_ITERATE()
322 void disconnected(ConnectorType_ const & c);
324 friend class detail::MultiConnectorMixinAccess;
325 friend class detail::MultiConnectorWrapper<Self_,ConnectorType_>;
327 ContainerType_ connectors_;
330 template <class Self_,
331 class ConnectorType_>
332 class MultiConnectorMixin<Self_,ConnectorType_,void,void>
333 : private detail::MultiConnectorSelectBase<ConnectorType_>::type
336 typedef ConnectorType_ ConnectorType;
340 // Include 'MultiConnectorMixin member declaration' from MultiConnectorMixin.mpp
341 # define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
343 SENF_MULTI_CONNECTOR_MAX_ARGS, \
344 SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
346 # include BOOST_PP_ITERATE()
348 void disconnected(ConnectorType_ const & c);
350 friend class detail::MultiConnectorMixinAccess;
351 friend class detail::MultiConnectorWrapper<Self_,ConnectorType_>;
358 ///////////////////////////////hh.e////////////////////////////////////////
359 //#include "MultiConnectorMixin.cci"
360 #include "MultiConnectorMixin.ct"
361 #include "MultiConnectorMixin.cti"
368 // comment-column: 40
369 // c-file-style: "senf"
370 // indent-tabs-mode: nil
371 // ispell-local-dictionary: "american"
372 // compile-command: "scons -u test"