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 "../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 #include "MultiConnectorMixin.mpp"
38 #include "MultiConnectorMixin.ih"
39 ///////////////////////////////hh.p////////////////////////////////////////
41 #ifndef SENF_MULTI_CONNECTOR_MAX_ARGS
42 #define SENF_MULTI_CONNECTOR_MAX_ARGS 3
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
57 Additional implementations with 0..SENF_MULTI_CONNECTOR_MAX_ARGS arguments.
58 \related module::MultiConnectorMixin
60 template <class Source, class Target, class A1>
61 Source::ConnectorType & connect(Source & source, Target & target, A1 const & a1);
63 /** \brief Connect arbitrary source to MultiConnector target
64 Additional implementations with 0..SENF_MULTI_CONNECTOR_MAX_ARGS arguments.
65 \related module::MultiConnectorMixin
67 template <class Source, class Target>
68 Target::ConnectorType & connect(Source & source, Target & target, A1 const & a1);
72 // Include 'senf::ppi::namespace member declarations' from MultiConnectorMixin.mpp
73 # define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
75 SENF_MULTI_CONNECTOR_MAX_ARGS, \
76 SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
78 # include BOOST_PP_ITERATE()
82 /** \brief Multi connector management
84 This mixin provides a module with support for a runtime configurable number of input or
88 : public senf::ppi::module::MultiConnectorMixin<
89 MyModule, senf::ppi::connector::ActiveInput<> >
91 SENF_PPI_MODULE(MyModule);
93 senf::ppi::connector::PassiveOutput<> output;
98 void connectorSetup(senf::ppi::connector::ActiveInput & input)
100 route(input, output);
101 input.onThrottle(&MyModule::doThrottle);
109 friend class senf::ppi::module::MultiConnectorMixin<
110 MyModule, senf::ppi::connector::ActiveInput<> >
114 Using the MultiConnectorMixin consists of
115 \li inheriting from MultiConnectorMixin
116 \li defining a function \c connectorSetup
117 \li declaring the mixin as a friend
119 The MultiConnectorMixin takes several template arguments
120 \li the name of the derived class, \a Self_
121 \li the type of connector, \a ConnectorType_
122 \li an optional \a KeyType_ if a mapping container is required
123 \li an optional \a ContainerType_ to replace the default \c boost::ptr_vector or \c
126 \section senf_ppi_multiconnector_sequence Sequence/vector based multi connector mixin
128 If no \a KeyType_ is given (or the \a KeyType_ is \c void), the mixin will use a sequence
129 container, by default a \c boost::ptr_vector to store the connectors. In this case, new
130 connectors will be added to the end of the container. The \c connectorSetup() routine
131 however may be used to move the inserted connector to some other location, e.g.
133 container().insert(begin(), container().pop_back().release());
135 which will move the new connector from the end to the beginning.
136 \warning If you throw an exception from \c connectorSetup(), you must do so \e before moving
137 the new connector around since the mixin will remove the last element from the container
140 \par "Example:" senf::ppi::module::PriorityJoin
142 \section senf_ppi_multiconnector_map Map based multi connector mixin
144 If \a KeyType_ is given (and is not \c void), the mixin will use a mapping container, by
145 default a \c boost::ptr_map to store the connectors. The \c connectorSetup() member function
146 must return the key value under which the new connector will be stored. The new connector
147 will this be written to the container only \e after \c connectorSetup() returns.
149 When the returned key is not unique, the new connector will \e replace the old one. If this
150 is not, what you want, either check for an already existing member and throw an exception in
151 \c connectorSetup() or replace the \c boost::ptr_map by a \c boost::ptr_multimap using the
152 fourth template argument to MultiConnectorMixin.
154 \par "Example:" senf::ppi::module::AnnotationRouter
156 \section senf_ppi_multiconnector_connect Connect and additional \c connectorSetup() arguments
158 When connecting to a module using the MultiConnectorMixin, every new connect call will
159 allocate a new connector
163 senf::ppi::connect(someModule, myModule);
165 Some modules will expect additional arguments to be passed (see below)
169 senf::ppi::connect(mod1, myModule); // index = 0, see below
170 senf::ppi::connect(mod2, myModule, 1); // index = 1, see below
172 To declare these additional arguments, just declare \c connectorSetup() with those
173 additional arguments:
175 void connectorSetup(MyModule::ConnectorType & input, int index=0)
177 container().insert(container().begin()+index, container().pop_back().release());
180 \par "Advanced note:" These additional arguments are always passed by const-reference. If
181 you need to pass a non-const reference, declare the \c connectorSetup() argument as
182 non-const reference and wrap the real argument using \c boost::ref() (The reason for
183 this is known as 'The forwarding problem'
185 template <class Self_,
186 class ConnectorType_,
188 class ContainerType_=typename detail::MultiConnectorDefaultContainer<
189 KeyType_,ConnectorType_>::type>
190 class MultiConnectorMixin
191 : private detail::MultiConnectorSelectBase<ConnectorType_>::type
194 typedef ConnectorType_ ConnectorType;
197 typedef ContainerType_ ContainerType;
198 ContainerType_ & connectors();
202 // For exposition only
203 // Other implementations with 0..SENF_MULTI_CONNECTOR_MAX_ARGS arguments accordingly
206 ConnectorType_ & newConnector(A1 const & a1);
208 // See above for an additional note regarding the boost::enable_if in the real
211 template <class Source, class Target, class A1>
212 friend Source::ConnectorType & senf::ppi::connect(Source & source,
216 template <class Source, class Target, class A1>
217 friend Target::ConnectorType & senf::ppi::connect(Source & source,
222 // Include 'MultiConnectorMixin member declaration' from MultiConnectorMixin.mpp
223 # define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
225 SENF_MULTI_CONNECTOR_MAX_ARGS, \
226 SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
228 # include BOOST_PP_ITERATE()
230 ContainerType_ connectors_;
233 template <class Self_,
234 class ConnectorType_,
235 class ContainerType_>
236 class MultiConnectorMixin<Self_,ConnectorType_,void,ContainerType_>
237 : private detail::MultiConnectorSelectBase<ConnectorType_>::type
240 typedef ConnectorType_ ConnectorType;
243 typedef ContainerType_ ContainerType;
244 ContainerType_ & connectors();
249 // For exposition only
250 // Other implementations with 0..SENF_MULTI_CONNECTOR_MAX_ARGS arguments accordingly
253 ConnectorType_ & newConnector(A1 const & a1);
255 // See above for an additional note regarding the boost::enable_if in the real
258 template <class Source, class Target, class A1>
259 friend Source::ConnectorType & senf::ppi::connect(Source & source,
263 template <class Source, class Target, class A1>
264 friend Target::ConnectorType & senf::ppi::connect(Source & source,
269 // Include 'MultiConnectorMixin member declaration' from MultiConnectorMixin.mpp
270 # define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
272 SENF_MULTI_CONNECTOR_MAX_ARGS, \
273 SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
275 # include BOOST_PP_ITERATE()
277 ContainerType_ connectors_;
282 ///////////////////////////////hh.e////////////////////////////////////////
283 //#include "MultiConnectorMixin.cci"
284 //#include "MultiConnectorMixin.ct"
285 #include "MultiConnectorMixin.cti"
292 // comment-column: 40
293 // c-file-style: "senf"
294 // indent-tabs-mode: nil
295 // ispell-local-dictionary: "american"
296 // compile-command: "scons -u test"