4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
6 // The contents of this file are subject to the Fraunhofer FOKUS Public License
7 // Version 1.0 (the "License"); you may not use this file except in compliance
8 // with the License. You may obtain a copy of the License at
9 // http://senf.berlios.de/license.html
11 // The Fraunhofer FOKUS Public License Version 1.0 is based on,
12 // but modifies the Mozilla Public License Version 1.1.
13 // See the full license text for the amendments.
15 // Software distributed under the License is distributed on an "AS IS" basis,
16 // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
17 // for the specific language governing rights and limitations under the License.
19 // The Original Code is Fraunhofer FOKUS code.
21 // The Initial Developer of the Original Code is Fraunhofer-Gesellschaft e.V.
22 // (registered association), Hansastraße 27 c, 80686 Munich, Germany.
23 // All Rights Reserved.
26 // Stefan Bund <g0dil@berlios.de>
29 \brief MultiConnectorMixin public header */
31 #ifndef HH_SENF_PPI_MultiConnectorMixin_
32 #define HH_SENF_PPI_MultiConnectorMixin_ 1
35 #include <senf/config.hh>
36 #include <boost/ptr_container/ptr_map.hpp>
37 #include <boost/ptr_container/ptr_vector.hpp>
38 #include <boost/mpl/if.hpp>
40 #ifndef SENF_MULTI_CONNECTOR_MAX_ARGS
41 #define SENF_MULTI_CONNECTOR_MAX_ARGS 3
44 #include "MultiConnectorMixin.mpp"
45 #include "MultiConnectorMixin.ih"
46 //-/////////////////////////////////////////////////////////////////////////////////////////////////
53 // For exposition only.
54 // Other implementations with 0..SENF_MULTI_CONNECTOR_MAX_ARGS arguments accordingly
55 // The real implementation includes a boost::enable_if condition in the return value, which is
56 // used to only enable the correct overload: The first overload, if the MultiConnector is an
57 // output, otherwise the second overload.
59 /** \brief Connect MultiConnector source to arbitrary target
61 Additional implementations with 0..SENF_MULTI_CONNECTOR_MAX_ARGS arguments.
63 \related module::MultiConnectorMixin
65 template <class MultiConnectorSource, class Target, class A1>
66 MultiConnectorSource::ConnectorType & connect(
67 MultiConnectorSource & source, A1 const & a1, Target & target);
69 /** \brief Connect arbitrary source to MultiConnector target
71 Additional implementations with 0..SENF_MULTI_CONNECTOR_MAX_ARGS arguments.
73 \related module::MultiConnectorMixin
75 template <class Source, class MultiConnectorTarget, class A1>
76 MultiConnectorTarget::ConnectorType & connect(
77 Source & source, MultiConnectorTarget & target, A1 const & a1);
79 template <class MultiConnectorSource, class MultiConnectorTarget, class A1, class A2>
80 std::pair<MultiConnectorSource::ConnectorType &, MultiConnectorTarget::ConnectorType &>
82 MultiConnectorSource & source, MultiConnectorTarget & target, A1 const & a1, A2 const & a2);
86 // Include 'senf::ppi namespace member declarations' from MultiConnectorMixin.mpp
87 # define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
89 SENF_MULTI_CONNECTOR_MAX_ARGS, \
90 SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
92 # include BOOST_PP_ITERATE()
98 namespace detail { struct MultiConnectorMixinAccess; }
100 /** \brief Multi-Connector management
102 This mixin provides a module with support for a runtime configurable number of input or
106 : public senf::ppi::module::Module,
107 public senf::ppi::module::MultiConnectorMixin<
108 MyModule, senf::ppi::connector::ActiveInput<> >
110 SENF_PPI_MODULE(MyModule);
112 senf::ppi::connector::PassiveOutput<> output;
117 void connectorSetup(senf::ppi::connector::ActiveInput & input)
119 route(input, output);
120 input.onThrottle(&MyModule::doThrottle);
124 void connectorDestroy(senf::ppi::connector::ActiveInput const & input)
134 friend class senf::ppi::module::MultiConnectorMixin<
135 MyModule, senf::ppi::connector::ActiveInput<> >;
139 Using the MultiConnectorMixin consists of
140 \li inheriting from MultiConnectorMixin
141 \li defining a function \c connectorSetup
142 \li declaring the mixin as a friend
143 \li optionally defining \c connectorDestroy to be notified when connectors are disconnected
145 The MultiConnectorMixin takes several template arguments
146 \li the name of the derived class, \a Self_
147 \li the type of connector, \a ConnectorType_
148 \li an optional \a KeyType_ if a mapping container is required
149 \li an optional \a ContainerType_ to replace the default \c boost::ptr_vector or \c
152 \section senf_ppi_multiconnector_sequence Sequence/vector based multi connector mixin
154 If no \a KeyType_ is given (or the \a KeyType_ is \c void), the mixin will use a sequence
155 container, by default a \c boost::ptr_vector to store the connectors. In this case, new
156 connectors will be added to the end of the container. The \c connectorSetup() routine
157 however may be used to move the inserted connector to some other location, e.g.
159 container().insert(begin(), container().pop_back().release());
161 which will move the new connector from the end to the beginning. If you want to abort adding
162 the new connector, you may throw an exception.
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.
217 Implementing \c connectorDestroy now is \e mandatory. The signature is changed to take a
221 : public senf::ppi::module::Module,
222 public senf::ppi::module::MultiConnectorMixin<
223 MyModule, senf::ppi::connector::ActiveInput<>, void, void >
225 SENF_PPI_MODULE(MyModule);
230 void connectorSetup(std::auto_ptr<ConnectorType> conn, unsigned p)
232 if (p>connectors_.size())
233 throw SomeErrorException();
234 route(*conn, output);
235 connectors_.insert(connectors_.begin()+p,conn);
238 void connectorDestroy(ConnectorType const * conn)
240 using boost::lambda::_1;
241 boost::ptr_vector<ConnectorType>::iterator i (
242 std::find_if(connectors_.begin(),connectors_.end(), &_1==conn))
243 if (i != connectors_.end())
244 connectors_.erase(i);
247 boost::ptr_vector<ConnectorType> connectors_;
250 \warning You must make absolutely sure the connector does not get deleted when returning
251 normally from \c connectorSetup(): The connector \e must be saved somewhere
252 successfully, otherwise your code will break.
255 template <class Self_,
256 class ConnectorType_,
258 class ContainerType_=typename detail::MultiConnectorDefaultContainer<
259 KeyType_,ConnectorType_>::type>
260 class MultiConnectorMixin
261 : private detail::MultiConnectorSelectBase<ConnectorType_>::type
264 typedef ConnectorType_ ConnectorType; ///< Type of MultiConnector connector
267 typedef ContainerType_ ContainerType; ///< Type of connector container
269 ContainerType_ & connectors(); ///< Get connector container
270 ContainerType_ const & connectors() const; ///< Get connectors container (const)
272 void connectorDestroy(ConnectorType const &);
278 // Include 'MultiConnectorMixin member declaration' from MultiConnectorMixin.mpp
279 # define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
281 SENF_MULTI_CONNECTOR_MAX_ARGS, \
282 SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
284 # include BOOST_PP_ITERATE()
288 void disconnected(ConnectorType_ const & c);
290 friend struct detail::MultiConnectorMixinAccess;
291 friend class detail::MultiConnectorWrapper<Self_,ConnectorType_>;
293 ContainerType_ connectors_;
298 template <class Self_,
299 class ConnectorType_,
300 class ContainerType_>
301 class MultiConnectorMixin<Self_,ConnectorType_,void,ContainerType_>
302 : private detail::MultiConnectorSelectBase<ConnectorType_>::type
305 typedef ConnectorType_ ConnectorType;
308 typedef ContainerType_ ContainerType;
310 ContainerType_ & connectors();
311 ContainerType_ const & connectors() const;
313 void connectorDestroy(ConnectorType const &);
317 // Include 'MultiConnectorMixin member declaration' from MultiConnectorMixin.mpp
318 # define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
320 SENF_MULTI_CONNECTOR_MAX_ARGS, \
321 SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
323 # include BOOST_PP_ITERATE()
325 void disconnected(ConnectorType_ const & c);
327 friend struct detail::MultiConnectorMixinAccess;
328 friend class detail::MultiConnectorWrapper<Self_,ConnectorType_>;
330 ContainerType_ connectors_;
333 template <class Self_,
334 class ConnectorType_>
335 class MultiConnectorMixin<Self_,ConnectorType_,void,void>
336 : private detail::MultiConnectorSelectBase<ConnectorType_>::type
339 typedef ConnectorType_ ConnectorType;
343 // Include 'MultiConnectorMixin member declaration' from MultiConnectorMixin.mpp
344 # define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
346 SENF_MULTI_CONNECTOR_MAX_ARGS, \
347 SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
349 # include BOOST_PP_ITERATE()
351 void disconnected(ConnectorType_ const & c);
353 friend struct detail::MultiConnectorMixinAccess;
354 friend class detail::MultiConnectorWrapper<Self_,ConnectorType_>;
361 //-/////////////////////////////////////////////////////////////////////////////////////////////////
362 //#include "MultiConnectorMixin.cci"
363 #include "MultiConnectorMixin.ct"
364 #include "MultiConnectorMixin.cti"
371 // comment-column: 40
372 // c-file-style: "senf"
373 // indent-tabs-mode: nil
374 // ispell-local-dictionary: "american"
375 // compile-command: "scons -u test"