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>
35 #ifndef SENF_MULTI_CONNECTOR_MAX_ARGS
36 #define SENF_MULTI_CONNECTOR_MAX_ARGS 3
39 #include "MultiConnectorMixin.mpp"
40 #include "MultiConnectorMixin.ih"
41 //-/////////////////////////////////////////////////////////////////////////////////////////////////
48 // For exposition only.
49 // Other implementations with 0..SENF_MULTI_CONNECTOR_MAX_ARGS arguments accordingly
50 // The real implementation includes a boost::enable_if condition in the return value, which is
51 // used to only enable the correct overload: The first overload, if the MultiConnector is an
52 // output, otherwise the second overload.
54 /** \brief Connect MultiConnector source to arbitrary target
56 Additional implementations with 0..SENF_MULTI_CONNECTOR_MAX_ARGS arguments.
58 \related module::MultiConnectorMixin
60 template <class MultiConnectorSource, class Target, class A1>
61 MultiConnectorSource::ConnectorType & connect(
62 MultiConnectorSource & source, A1 const & a1, Target & target);
64 /** \brief Connect arbitrary source to MultiConnector target
66 Additional implementations with 0..SENF_MULTI_CONNECTOR_MAX_ARGS arguments.
68 \related module::MultiConnectorMixin
70 template <class Source, class MultiConnectorTarget, class A1>
71 MultiConnectorTarget::ConnectorType & connect(
72 Source & source, MultiConnectorTarget & target, A1 const & a1);
74 template <class MultiConnectorSource, class MultiConnectorTarget, class A1, class A2>
75 std::pair<MultiConnectorSource::ConnectorType &, MultiConnectorTarget::ConnectorType &>
77 MultiConnectorSource & source, MultiConnectorTarget & target, A1 const & a1, A2 const & a2);
81 // Include 'senf::ppi namespace member declarations' from MultiConnectorMixin.mpp
82 # define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
84 SENF_MULTI_CONNECTOR_MAX_ARGS, \
85 SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
87 # include BOOST_PP_ITERATE()
93 namespace detail { class MultiConnectorMixinAccess; }
95 /** \brief Multi-Connector management
97 This mixin provides a module with support for a runtime configurable number of input or
101 : public senf::ppi::module::Module,
102 public senf::ppi::module::MultiConnectorMixin<
103 MyModule, senf::ppi::connector::ActiveInput<> >
105 SENF_PPI_MODULE(MyModule);
107 senf::ppi::connector::PassiveOutput<> output;
112 void connectorSetup(senf::ppi::connector::ActiveInput & input)
114 route(input, output);
115 input.onThrottle(&MyModule::doThrottle);
119 void connectorDestroy(senf::ppi::connector::ActiveInput const & input)
129 friend class senf::ppi::module::MultiConnectorMixin<
130 MyModule, senf::ppi::connector::ActiveInput<> >;
134 Using the MultiConnectorMixin consists of
135 \li inheriting from MultiConnectorMixin
136 \li defining a function \c connectorSetup
137 \li declaring the mixin as a friend
138 \li optionally defining \c connectorDestroy to be notified when connectors are disconnected
140 The MultiConnectorMixin takes several template arguments
141 \li the name of the derived class, \a Self_
142 \li the type of connector, \a ConnectorType_
143 \li an optional \a KeyType_ if a mapping container is required
144 \li an optional \a ContainerType_ to replace the default \c boost::ptr_vector or \c
147 \section senf_ppi_multiconnector_sequence Sequence/vector based multi connector mixin
149 If no \a KeyType_ is given (or the \a KeyType_ is \c void), the mixin will use a sequence
150 container, by default a \c boost::ptr_vector to store the connectors. In this case, new
151 connectors will be added to the end of the container. The \c connectorSetup() routine
152 however may be used to move the inserted connector to some other location, e.g.
154 container().insert(begin(), container().pop_back().release());
156 which will move the new connector from the end to the beginning. If you want to abort adding
157 the new connector, you may throw an exception.
159 \par "Example:" senf::ppi::module::PriorityJoin
161 \section senf_ppi_multiconnector_map Map based multi connector mixin
163 If \a KeyType_ is given (and is not \c void), the mixin will use a mapping container, by
164 default a \c boost::ptr_map to store the connectors. The \c connectorSetup() member function
165 must return the key value under which the new connector will be stored. The new connector
166 will this be written to the container only \e after \c connectorSetup() returns.
168 When the returned key is not unique, the new connector will \e replace the old one. If this
169 is not what you want, either check for an already existing member and throw an exception in
170 \c connectorSetup() or replace the \c boost::ptr_map by a \c boost::ptr_multimap using the
171 fourth template argument to MultiConnectorMixin.
173 \par "Example:" senf::ppi::module::AnnotationRouter
175 \section senf_ppi_multiconnector_connect Connect and additional connectorSetup() arguments
177 When connecting to a module using the MultiConnectorMixin, every new connect call will
178 allocate a new connector
182 senf::ppi::connect(someModule, myModule);
184 Some modules will expect additional arguments to be passed (see below)
188 senf::ppi::connect(mod1, myModule); // index = 0, see below
189 senf::ppi::connect(mod2, myModule, 1); // index = 1, see below
191 To declare these additional arguments, just declare \c connectorSetup() with those
192 additional arguments:
194 void connectorSetup(MyModule::ConnectorType & input, int index=0)
196 container().insert(container().begin()+index, container().pop_back().release());
200 \par "Advanced note:" These additional arguments are always passed by const-reference. If
201 you need to pass a non-const reference, declare the \c connectorSetup() argument as
202 non-const reference and wrap the real argument using \c boost::ref() (The reason for
203 this is known as 'The forwarding problem').
205 \section senf_ppi_multiconnector_advanced Advanced usage: Managing your own container
207 If you need to use a completely different type of container, you can take over the container
208 management yourself. To do this, pass \c void as container type and change \c
209 connectorSetup() to take an \c std::auto_ptr as argument. \c connectorSetup() must ensure to
210 save this connector in some container or throw an exception.
212 Implementing \c connectorDestroy now is \e mandatory. The signature is changed to take a
216 : public senf::ppi::module::Module,
217 public senf::ppi::module::MultiConnectorMixin<
218 MyModule, senf::ppi::connector::ActiveInput<>, void, void >
220 SENF_PPI_MODULE(MyModule);
225 void connectorSetup(std::auto_ptr<ConnectorType> conn, unsigned p)
227 if (p>connectors_.size())
228 throw SomeErrorException();
229 route(*conn, output);
230 connectors_.insert(connectors_.begin()+p,conn);
233 void connectorDestroy(ConnectorType const * conn)
235 using boost::lambda::_1;
236 boost::ptr_vector<ConnectorType>::iterator i (
237 std::find_if(connectors_.begin(),connectors_.end(), &_1==conn))
238 if (i != connectors_.end())
239 connectors_.erase(i);
242 boost::ptr_vector<ConnectorType> connectors_;
245 \warning You must make absolutely sure the connector does not get deleted when returning
246 normally from \c connectorSetup(): The connector \e must be saved somewhere
247 successfully, otherwise your code will break.
250 template <class Self_,
251 class ConnectorType_,
253 class ContainerType_=typename detail::MultiConnectorDefaultContainer<
254 KeyType_,ConnectorType_>::type>
255 class MultiConnectorMixin
256 : private detail::MultiConnectorSelectBase<ConnectorType_>::type
259 typedef ConnectorType_ ConnectorType; ///< Type of MultiConnector connector
262 typedef ContainerType_ ContainerType; ///< Type of connector container
264 ContainerType_ & connectors(); ///< Get connector container
265 ContainerType_ const & connectors() const; ///< Get connectors container (const)
267 void connectorDestroy(ConnectorType const &);
273 // Include 'MultiConnectorMixin member declaration' from MultiConnectorMixin.mpp
274 # define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
276 SENF_MULTI_CONNECTOR_MAX_ARGS, \
277 SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
279 # include BOOST_PP_ITERATE()
283 void disconnected(ConnectorType_ const & c);
285 friend class detail::MultiConnectorMixinAccess;
286 friend class detail::MultiConnectorWrapper<Self_,ConnectorType_>;
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;
305 ContainerType_ & connectors();
306 ContainerType_ const & connectors() const;
308 void connectorDestroy(ConnectorType const &);
312 // Include 'MultiConnectorMixin member declaration' from MultiConnectorMixin.mpp
313 # define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
315 SENF_MULTI_CONNECTOR_MAX_ARGS, \
316 SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
318 # include BOOST_PP_ITERATE()
320 void disconnected(ConnectorType_ const & c);
322 friend class detail::MultiConnectorMixinAccess;
323 friend class detail::MultiConnectorWrapper<Self_,ConnectorType_>;
325 ContainerType_ connectors_;
328 template <class Self_,
329 class ConnectorType_>
330 class MultiConnectorMixin<Self_,ConnectorType_,void,void>
331 : private detail::MultiConnectorSelectBase<ConnectorType_>::type
334 typedef ConnectorType_ ConnectorType;
338 // Include 'MultiConnectorMixin member declaration' from MultiConnectorMixin.mpp
339 # define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
341 SENF_MULTI_CONNECTOR_MAX_ARGS, \
342 SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
344 # include BOOST_PP_ITERATE()
346 void disconnected(ConnectorType_ const & c);
348 friend class detail::MultiConnectorMixinAccess;
349 friend class detail::MultiConnectorWrapper<Self_,ConnectorType_>;
356 //-/////////////////////////////////////////////////////////////////////////////////////////////////
357 //#include "MultiConnectorMixin.cci"
358 #include "MultiConnectorMixin.ct"
359 #include "MultiConnectorMixin.cti"
366 // comment-column: 40
367 // c-file-style: "senf"
368 // indent-tabs-mode: nil
369 // ispell-local-dictionary: "american"
370 // compile-command: "scons -u test"