PPI: Add user container support to MultiConnectorMixin
g0dil [Tue, 30 Jun 2009 10:56:20 +0000 (10:56 +0000)]
git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@1250 270642c3-0616-0410-b53a-bc976706d245

PPI/MultiConnectorMixin.hh
PPI/MultiConnectorMixin.mpp
PPI/MultiConnectorMixin.test.cc

index e63d7ff..a04be33 100644 (file)
@@ -93,7 +93,8 @@ namespace module {
         output connectors.
         \code
         class MyModule 
-            : public senf::ppi::module::MultiConnectorMixin<
+            : public senf::ppi::module::Modulem,
+              public senf::ppi::module::MultiConnectorMixin<
                   MyModule, senf::ppi::connector::ActiveInput<> >
         {
             SENF_PPI_MODULE(MyModule);
@@ -190,6 +191,39 @@ namespace module {
             you need to pass a non-const reference, declare the \c connectorSetup() argument as
             non-const reference and wrap the real argument using \c boost::ref() (The reason for
             this is known as 'The forwarding problem'
+
+        \section Advanced usage: Managing your own container
+
+        If you need to use a completely different type of container, you can take over the container
+        management yourself. To do this, pass \c void as container type and change \c
+        connectorSetup() to take an \c std::auto_ptr as argument. \c connectorSetup() must ensure to
+        save this connector in some container or throw an exception
+        \code
+        class MyModule 
+            : public senf::ppi::module::Modulem,
+              public senf::ppi::module::MultiConnectorMixin<
+                  MyModule, senf::ppi::connector::ActiveInput<>, void, void >
+        {
+            SENF_PPI_MODULE(MyModule);
+        public:
+            // ...
+
+        private:
+            void connectorSetup(std::auto_ptr<ConnectorType> conn, unsigned p)
+            {
+                if (p>connectors_.size())
+                   throw SomeErrorException();
+                route(*conn, output);
+                connectors_.insert(connectors_.begin()+p,conn);
+            }
+
+            boost::ptr_vector<ConnectorType> connectors_;
+        };
+        \endcode
+        \warning You must make absolutely sure the connector does not get deleted when returning
+            normally from \c connectorSetup(): The connector \e must be saved somewhere
+            successfully, otherwise your code will break.
+
      */
     template <class Self_, 
               class ConnectorType_, 
@@ -292,6 +326,46 @@ namespace module {
         ContainerType_ connectors_;
     };
 
+    template <class Self_, 
+              class ConnectorType_>
+    class MultiConnectorMixin<Self_,ConnectorType_,void,void>
+        : private detail::MultiConnectorSelectBase<ConnectorType_>::type
+    {
+    public:
+        typedef ConnectorType_ ConnectorType;
+
+    private:
+
+#if 0
+        // For exposition only
+        // Other implementations with 0..SENF_MULTI_CONNECTOR_MAX_ARGS arguments accordingly
+
+        tempalte <class A1>
+        ConnectorType_ & newConnector(A1 const & a1);
+
+        // See above for an additional note regarding the boost::enable_if in the real
+        // implementation
+        
+        template <class Source, class Target, class A1>
+        friend Source::ConnectorType & senf::ppi::connect(Source & source, 
+                                                          Target & target, 
+                                                          A1 const & a1);
+
+        template <class Source, class Target, class A1>
+        friend Target::ConnectorType & senf::ppi::connect(Source & source,
+                                                          Target & target,
+                                                          A1 const & a1);
+#endif
+
+        // Include 'MultiConnectorMixin member declaration' from MultiConnectorMixin.mpp
+#       define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
+            0, \
+            SENF_MULTI_CONNECTOR_MAX_ARGS, \
+            SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
+            1 ))
+#       include BOOST_PP_ITERATE()
+    };
+
 #endif
         
 }}}
index be0c920..121bf8c 100644 (file)
@@ -102,6 +102,9 @@ connect(Source & source, Target & target mpp_FnParamsKomma());
 // ////////////////////////////////////////////////////////////////////////
 // Implementation
 
+////////////////////////////////////////
+// Map container
+
 template <class Self_, class ConnectorType_, class KeyType_, class ContainerType_>
 mpp_TplParams()
 prefix_ ConnectorType_ &
@@ -113,6 +116,9 @@ newConnector(mpp_FnParams())
     return * connectors_.insert(key, conn).first->second;
 }
 
+////////////////////////////////////////
+// Vector container
+
 template <class Self_, class ConnectorType_, class ContainerType_>
 mpp_TplParams()
 prefix_ ConnectorType_ &
@@ -126,6 +132,24 @@ newConnector(mpp_FnParams())
     return conn;
 }
 
+////////////////////////////////////////
+// User managed container
+
+template <class Self_, class ConnectorType_>
+mpp_TplParams()
+prefix_ ConnectorType_ &
+senf::ppi::module::MultiConnectorMixin<Self_,ConnectorType_,void,void>::
+newConnector(mpp_FnParams())
+{
+    std::auto_ptr<ConnectorType_> cp (new ConnectorType_);
+    ConnectorType_ & cref (*cp);
+    static_cast<Self_*>(this)->connectorSetup(cp mpp_CallParamsKomma());
+    return cref;
+}
+
+////////////////////////////////////////
+// senf::ppi::connect
+
 template <class Source, class Target mpp_TplParamsKomma()>
 typename boost::enable_if<
     boost::is_base_of<senf::ppi::connector::OutputConnector, typename Source::ConnectorType>,
index 34b76d5..bb81a69 100644 (file)
@@ -27,7 +27,7 @@
 //#include "MultiConnectorMixin.test.ih"
 
 // Custom includes
-#include "MultiConnectorMixin.hh"
+#include "PPI.hh"
 
 #include "../Utils/auto_unit_test.hh"
 #include <boost/test/test_tools.hpp>
 #define prefix_
 ///////////////////////////////cc.p////////////////////////////////////////
 
-BOOST_AUTO_UNIT_TEST(dynamicConnectorMixin)
-{}
+namespace {
+    // We only test the user-collection case, all other cases are already handled by
+    // existing modules
+
+    // Primitive duplicator
+    class MyModule
+        : public senf::ppi::module::Module,
+          public senf::ppi::module::MultiConnectorMixin<MyModule,
+                                                        senf::ppi::connector::ActiveOutput<>,
+                                                        void, void>
+    {
+        SENF_PPI_MODULE(MyModule);
+    public:
+        senf::ppi::connector::PassiveInput<> input;
+
+        MyModule()
+            {
+                noroute(input); 
+                input.onRequest(&MyModule::request);
+            }
+
+    private:
+        void connectorSetup(std::auto_ptr<ConnectorType> c)
+            {
+                route(input, *c);
+                connectors_.push_back(c);
+            }
+
+        void request()
+            {
+                senf::Packet p (input());
+                for (Connectors::iterator i (connectors_.begin()), i_end (connectors_.end());
+                     i != i_end; ++i)
+                    (*i)(p);
+            }
+
+        typedef boost::ptr_vector<MyModule::ConnectorType> Connectors;
+        Connectors connectors_;
+                
+        friend class senf::ppi::module::MultiConnectorMixin<MyModule,
+                                                            senf::ppi::connector::ActiveOutput<>,
+                                                            void, void>;
+
+    };
+}
+
+BOOST_AUTO_UNIT_TEST(multiConnectorMixin_userContainer)
+{
+    senf::ppi::module::debug::ActiveSource source;
+    MyModule module;
+    senf::ppi::module::debug::PassiveSink sink1;
+    senf::ppi::module::debug::PassiveSink sink2;
+
+    senf::ppi::connect(source, module);
+    senf::ppi::connect(module, sink1);
+    senf::ppi::connect(module, sink2);
+    senf::ppi::init();
+
+    senf::Packet p (senf::DataPacket::create());
+
+    source.submit(p);
+    BOOST_CHECK_EQUAL( sink1.size(), 1u );
+    BOOST_CHECK_EQUAL( sink2.size(), 1u );
+    BOOST_CHECK( sink1.pop_front() == p );
+    BOOST_CHECK( sink2.pop_front() == p );
+    
+}
 
 ///////////////////////////////cc.e////////////////////////////////////////
 #undef prefix_