PPI: Add simple connector type compatibility check
g0dil [Mon, 10 Mar 2008 23:16:29 +0000 (23:16 +0000)]
Utils: BUGFIX: Fix use of operator<< together with throw

git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@741 270642c3-0616-0410-b53a-bc976706d245

PPI/Connectors.cc
PPI/Connectors.cci
PPI/Connectors.hh
PPI/Connectors.test.cc
PPI/SocketSource.hh
Packets/MPEGDVBBundle/TransportPacket.test.cc
Utils/Exception.cci
Utils/Exception.cti
Utils/Exception.hh
Utils/Exception.test.cc

index ff29901..5c4ceff 100644 (file)
 
 // Custom includes
 #include "Route.hh"
+#include "Module.hh"
 
 //#include "Connectors.mpp"
 #define prefix_
 ///////////////////////////////cc.p////////////////////////////////////////
 
 ///////////////////////////////////////////////////////////////////////////
+// senf::ppi::connector::Connector
+
+prefix_ void senf::ppi::connector::Connector::connect(Connector & target)
+{
+    SENF_ASSERT( module_ && ! peer_ && target.module_ && ! target.peer_ );
+    if (! (packetTypeID() == typeid(void) ||
+           target.packetTypeID() == typeid(void) || 
+           packetTypeID() == target.packetTypeID()) )
+        throw IncompatibleConnectorsException() 
+            << ": " << prettyName(packetTypeID()) 
+            << " [in module " << prettyName(typeid(*module_))  << "] "
+            << ", " << prettyName(target.packetTypeID())
+            << " [in module " << prettyName(typeid(*target.module_)) << "]";
+            
+    peer_ = & target;
+    target.peer_ = this;
+}
+
+///////////////////////////////////////////////////////////////////////////
 // senf::ppi::connector::PassiveConnector
 
 ////////////////////////////////////////
index e4647d7..c61555c 100644 (file)
@@ -24,6 +24,7 @@
     \brief Connectors inline non-template implementation */
 
 // Custom includes
+#include "../Utils/TypeInfo.hh"
 #include "../Utils/senfassert.hh"
 
 #define prefix_ inline
@@ -59,13 +60,6 @@ prefix_ senf::ppi::connector::Connector::~Connector()
         peer_->peer_ = 0;
 }
 
-prefix_ void senf::ppi::connector::Connector::connect(Connector & target)
-{
-    SENF_ASSERT( ! peer_ && ! target.peer_ );
-    peer_ = & target;
-    target.peer_ = this;
-}
-
 ////////////////////////////////////////
 // private members
 
index a69c3d8..be55849 100644 (file)
@@ -31,6 +31,7 @@
 #include <boost/utility.hpp>
 #include <boost/scoped_ptr.hpp>
 #include "../Utils/safe_bool.hh"
+#include "../Utils/Exception.hh"
 #include "../Packets/Packets.hh"
 #include "predecl.hh"
 #include "detail/Callback.hh"
@@ -99,6 +100,9 @@ namespace connector {
             \ref ppi_connectors
      */
 
+    struct IncompatibleConnectorsException : public senf::Exception
+    { IncompatibleConnectorsException() : senf::Exception("Incompatible connectors") {} };
+
     /** \brief Connector base-class
 
         This connector provides access to the generic connector facilities. This includes the
@@ -119,6 +123,8 @@ namespace connector {
         void connect(Connector & target);
 
     private:
+        virtual std::type_info const & packetTypeID() = 0;
+
         void setModule(module::Module & module);
 
         Connector * peer_;
@@ -450,22 +456,27 @@ namespace connector {
 
 #   define TypedConnector_Input read
 #   define TypedConnector_Output write
-#   define TypedConnector(type, dir)                                                              \
+#   define TypedConnector(pType, dir)                                                              \
         template <class PacketType>                                                               \
-        class type ## dir                                                                         \
-            : public Generic ## type ## dir,                                                      \
-              private detail::Typed ## dir ## Mixin<type ## dir <PacketType>, PacketType>         \
+        class pType ## dir                                                                         \
+            : public Generic ## pType ## dir,                                                      \
+              private detail::Typed ## dir ## Mixin<pType ## dir <PacketType>, PacketType>         \
         {                                                                                         \
-            typedef detail::Typed ## dir ## Mixin<type ## dir <PacketType>, PacketType> mixin;    \
+            typedef detail::Typed ## dir ## Mixin<pType ## dir <PacketType>, PacketType> mixin;    \
         public:                                                                                   \
             using mixin::operator();                                                              \
             using mixin::TypedConnector_ ## dir ;                                                 \
         private:                                                                                  \
-             friend class detail::Typed ## dir ## Mixin<type ## dir <PacketType>, PacketType>;    \
+            virtual std::type_info const & packetTypeID()                                         \
+                { return typeid(typename PacketType::type); }                                     \
+            friend class detail::Typed ## dir ## Mixin<pType ## dir <PacketType>, PacketType>;     \
         };                                                                                        \
         template <>                                                                               \
-        class type ## dir <Packet> : public Generic ## type ## dir                                \
-        {}
+        class pType ## dir <Packet> : public Generic ## pType ## dir                                \
+        {                                                                                         \
+        private:                                                                                  \
+            virtual std::type_info const & packetTypeID() { return typeid(void); }                \
+        }
 
     TypedConnector( Passive, Input  );
     TypedConnector( Passive, Output );
index 639f58b..6b95fc2 100644 (file)
@@ -286,17 +286,18 @@ BOOST_AUTO_UNIT_TEST(activeOutput)
 
 namespace {
 
-    class TypedInputTest
+    template <class PacketType = senf::DataPacket>
+    class TypedPassiveInput
         : public ppi::module::Module
     {
-        SENF_PPI_MODULE(TypedInputTest);
+        SENF_PPI_MODULE(TypedPassiveInput);
 
     public:
-        ppi::connector::PassiveInput<senf::DataPacket> input;
+        ppi::connector::PassiveInput<PacketType> input;
 
-        TypedInputTest() {
+        TypedPassiveInput() {
             noroute(input);
-            input.onRequest(&TypedInputTest::request);
+            input.onRequest(&TypedPassiveInput::request);
         }
 
         void request() {
@@ -305,17 +306,32 @@ namespace {
         }
     };
 
-    class TypedOutputTest
+    template <class PacketType = senf::DataPacket>
+    class TypedActiveInput
         : public ppi::module::Module
     {
-        SENF_PPI_MODULE(TypedOutputTest);
+        SENF_PPI_MODULE(TypedActiveInput);
 
     public:
-        ppi::connector::PassiveOutput<senf::DataPacket> output;
+        ppi::connector::ActiveInput<PacketType> input;
 
-        TypedOutputTest() {
+        TypedActiveInput() {
+            noroute(input);
+        }
+    };
+
+    template <class PacketType = senf::DataPacket>
+    class TypedPassiveOutput
+        : public ppi::module::Module
+    {
+        SENF_PPI_MODULE(TypedPassiveOutput);
+
+    public:
+        ppi::connector::PassiveOutput<PacketType> output;
+
+        TypedPassiveOutput() {
             noroute(output);
-            output.onRequest(&TypedOutputTest::request);
+            output.onRequest(&TypedPassiveOutput::request);
         }
 
         void request() {
@@ -325,12 +341,31 @@ namespace {
         }
     };
 
+    template <class PacketType = senf::DataPacket>
+    class TypedActiveOutput
+        : public ppi::module::Module
+    {
+        SENF_PPI_MODULE(TypedActiveOutput);
+
+    public:
+        ppi::connector::ActiveOutput<PacketType> output;
+
+        TypedActiveOutput() {
+            noroute(output);
+        }
+    };
+
+    struct MyPacketType : public senf::PacketTypeBase
+    {};
+
+    typedef senf::ConcretePacket<MyPacketType> MyPacket;
+
 }
 
 BOOST_AUTO_UNIT_TEST(typedInput)
 {
     debug::ActiveSource source;
-    TypedInputTest target;
+    TypedPassiveInput<> target;
 
     ppi::connect(source,target);
     ppi::init();
@@ -341,7 +376,7 @@ BOOST_AUTO_UNIT_TEST(typedInput)
 
 BOOST_AUTO_UNIT_TEST(tyepdOutput)
 {
-    TypedOutputTest source;
+    TypedPassiveOutput<> source;
     debug::ActiveSink target;
 
     ppi::connect(source,target);
@@ -350,6 +385,42 @@ BOOST_AUTO_UNIT_TEST(tyepdOutput)
     (void) target.request();
 }
 
+BOOST_AUTO_UNIT_TEST(connectorTest)
+{
+    {
+        TypedPassiveInput<> input;
+        TypedActiveOutput<MyPacket> output;
+        BOOST_CHECK_THROW( ppi::connect(output, input), 
+                           ppi::connector::IncompatibleConnectorsException );
+    }
+    {
+        TypedPassiveInput<MyPacket> input;
+        TypedActiveOutput<> output;
+        BOOST_CHECK_THROW( ppi::connect(output, input), 
+                           ppi::connector::IncompatibleConnectorsException );
+    }
+    {
+        TypedPassiveInput<> input;
+        TypedActiveOutput<> output;
+        BOOST_CHECK_NO_THROW( ppi::connect(output, input) );
+    }
+    { 
+        TypedPassiveInput<> input;
+        debug::ActiveSource output;
+        BOOST_CHECK_NO_THROW( ppi::connect(output, input) );
+    }
+    {
+        debug::ActiveSink input;
+        TypedPassiveOutput<> output;
+        BOOST_CHECK_NO_THROW( ppi::connect(output, input) );
+    }
+    {
+        debug::ActiveSink input;
+        debug::PassiveSource output;
+        BOOST_CHECK_NO_THROW( ppi::connect(output, input) );
+    }
+}
+
 ///////////////////////////////cc.e////////////////////////////////////////
 #undef prefix_
 
index 477df4b..a74fdbc 100644 (file)
@@ -53,6 +53,7 @@ namespace ppi {
     class DgramReader
     {
     public:
+        typedef Packet PacketType;
         typedef senf::ClientSocketHandle<
             senf::MakeSocketPolicy< senf::ReadablePolicy,
                                     senf::DatagramFramingPolicy >::policy > Handle;
@@ -111,7 +112,8 @@ namespace module {
     public:
         typedef typename Reader::Handle Handle; ///< Handle type requested by the reader
 
-        connector::ActiveOutput<> output; ///< Output connector to which the data received is written
+        connector::ActiveOutput<typename Reader::PacketType> output; 
+                                        ///< Output connector to which the data received is written
         
         ActiveSocketSource(Handle handle); ///< Create new reader for the given handle
                                         /**< Data will be read from \a handle and be parsed by \a
index 91f0f28..0fee6b2 100644 (file)
@@ -73,10 +73,10 @@ BOOST_AUTO_UNIT_TEST(transportPacket_packet)
     BOOST_CHECK(       ! p->transport_error_indicator()                                  );
     BOOST_CHECK(         p->pusi()                                                       );
     BOOST_CHECK(       ! p->transport_priority()                                         );
-    BOOST_CHECK_EQUAL(   p->pid(),                      0x010fu                          );  
-    BOOST_CHECK_EQUAL(   p->transport_scrmbl_ctrl(),    0x0u                             );             
+    BOOST_CHECK_EQUAL(   p->pid(),                      0x010fu                          );
+    BOOST_CHECK_EQUAL(   p->transport_scrmbl_ctrl(),    0x0u                             );
     BOOST_CHECK_EQUAL(   p->adaptation_field_ctrl(),    0x1u                             );
-    BOOST_CHECK_EQUAL(   p->continuity_counter(),       0x0eu                            );  
+    BOOST_CHECK_EQUAL(   p->continuity_counter(),       0x0eu                            );
 }
 
 ///////////////////////////////cc.e////////////////////////////////////////
index e7a9c53..b745f80 100644 (file)
 
 ///////////////////////////////////////////////////////////////////////////
 // senf::Exception
+
 prefix_ senf::Exception::Exception(std::string const & description)
     : message_(description)
 {}
 
+prefix_ std::string const & senf::Exception::message()
+    const
+{
+    return message_;
+}
+
+prefix_ void senf::Exception::append(std::string text)
+{
+    message_ += text;
+}
+
 ///////////////////////////////////////////////////////////////////////////
+// senf::SystemException
 
 prefix_ senf::SystemException::SystemException(std::string const & descr _SENF_EXC_DEBUG_ARGS_ND)
 {
index 3588cdc..a398908 100644 (file)
 #define prefix_ inline
 ///////////////////////////////cti.p///////////////////////////////////////
 
-template <class Arg>
-prefix_ senf::Exception & senf::Exception::operator<<(Arg const & arg)
+template <class Exc, class Arg>
+prefix_ typename boost::enable_if< boost::is_convertible<Exc*,senf::Exception*>, Exc & >::type
+senf::operator<<(Exc const & exc, Arg const & arg)
 {
-    message_ += boost::lexical_cast<std::string>(arg);
-    return *this;
+    const_cast<Exc &>(exc).append( boost::lexical_cast<std::string>(arg) );
+    return const_cast<Exc &>(exc);
 }
 
 /////////////////////////////cti.e///////////////////////////////////////
index eda57d1..5f00926 100644 (file)
@@ -34,6 +34,7 @@
 #include <boost/preprocessor/repeat.hpp>
 #include <boost/preprocessor/cat.hpp>
 #include <boost/utility.hpp>
+#include <boost/type_traits/is_convertible.hpp>
 
 //#include "Exception.mpp"
 ///////////////////////////////hh.p////////////////////////////////////////
@@ -103,15 +104,10 @@ namespace senf {
         ///////////////////////////////////////////////////////////////////////////
 
         virtual char const * what() const throw();
+        std::string const & message() const;
 
-        template <class Arg>
-        Exception & operator<<(Arg const & arg); ///< Extend exception description
-                                        /**< Adds \a arg converted to string to the end of the
-                                             exception description string. This operator allows to
-                                             use Exception instances like streams. The conversion is
-                                             performed using <code>boost::lexical_cast</code> and is
-                                             therefor identical to a streaming operation. 
-                                             \see \ref exception */
+        void append(std::string text); ///< Extend exception description
+                                        /**< Adds \a text to the description text. */
 
     protected:
         Exception(std::string const & description = ""); ///< Initialize exception with string
@@ -124,6 +120,17 @@ namespace senf {
         std::string message_;
     };
 
+    template <class Exc, class Arg>
+    typename boost::enable_if< boost::is_convertible<Exc*,Exception*>, Exc & >::type
+    operator<<(Exc const & exc, Arg const & arg); ///< Extend exception description
+                                        /**< Adds \a arg converted to string to the end of the
+                                             exception description string. This operator allows to
+                                             use Exception instances like streams. The conversion is
+                                             performed using <code>boost::lexical_cast</code> and is
+                                             therefor identical to a streaming operation. 
+                                             \see \ref exception */
+
+
 #   ifdef SENF_DEBUG
 #       define _SENF_EXC_DEBUG_ARGS ,char const * file=0,int line=0
 #       define _SENF_EXC_DEBUG_ARGS_ND ,char const *file,int line
index 3e51428..d390062 100644 (file)
@@ -41,7 +41,7 @@ BOOST_AUTO_UNIT_TEST(errnoException)
 {
     try {
         try {
-            throw senf::SystemException("::open()", ENOENT);
+            throw senf::SystemException("::open()", ENOENT) << "\nmore";
         }
         catch(senf::Exception & e) {
             e << "\nx=" << 1 << boost::format("\ny=%d") % 2;
@@ -50,7 +50,8 @@ BOOST_AUTO_UNIT_TEST(errnoException)
     }
     catch (senf::SystemException & e) {
         BOOST_CHECK_EQUAL( e.errorNumber(), ENOENT );
-        BOOST_CHECK_EQUAL( e.errorString(), "No such file or directory");
+        BOOST_CHECK_EQUAL( e.errorString(), "No such file or directory" );
+        BOOST_CHECK_EQUAL( e.what(), "[No such file or directory] ::open()\nmore\nx=1\ny=2" );
     }
 }