diff --git a/PPI/Connectors.cc b/PPI/Connectors.cc index ff299011dd27204f93c653014fd46b59dcf4a813..5c4ceff4e3a4553f49049e74250cb31ca89218b7 100644 --- a/PPI/Connectors.cc +++ b/PPI/Connectors.cc @@ -28,11 +28,31 @@ // 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 diff --git a/PPI/Connectors.cci b/PPI/Connectors.cci index e4647d7358e55b2693f00c1408aecff4568446dd..c61555cc3447520ee52d5dec8569e19aecb86afd 100644 --- a/PPI/Connectors.cci +++ b/PPI/Connectors.cci @@ -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 diff --git a/PPI/Connectors.hh b/PPI/Connectors.hh index a69c3d8f7bda027377a5349053be9d63ee8231e8..be55849db43207ae9ee86a73b5f43eaaa4acc6f6 100644 --- a/PPI/Connectors.hh +++ b/PPI/Connectors.hh @@ -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 ); diff --git a/PPI/Connectors.test.cc b/PPI/Connectors.test.cc index 639f58b90548c66ced14200887712c8078e409e6..6b95fc2700035283aeeb73b5bfbc1f4f30dce578 100644 --- a/PPI/Connectors.test.cc +++ b/PPI/Connectors.test.cc @@ -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_ diff --git a/PPI/SocketSource.hh b/PPI/SocketSource.hh index 477df4bad8e86e5d98b06dbfe31f7c0a26cbf88c..a74fdbcad31010738320ef2cf37622bcc37f8b79 100644 --- a/PPI/SocketSource.hh +++ b/PPI/SocketSource.hh @@ -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 diff --git a/Packets/MPEGDVBBundle/TransportPacket.test.cc b/Packets/MPEGDVBBundle/TransportPacket.test.cc index 91f0f28a6aa33e9dfcd045138f67ce1cb1024d87..0fee6b292489858be60893b1746da69848eb5246 100644 --- a/Packets/MPEGDVBBundle/TransportPacket.test.cc +++ b/Packets/MPEGDVBBundle/TransportPacket.test.cc @@ -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//////////////////////////////////////// diff --git a/Utils/Exception.cci b/Utils/Exception.cci index e7a9c53987163b9b8fa91800fbb57dddc78d5e11..b745f8056ee7e6625eb5cda9faf2434322629092 100644 --- a/Utils/Exception.cci +++ b/Utils/Exception.cci @@ -29,11 +29,24 @@ /////////////////////////////////////////////////////////////////////////// // 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) { diff --git a/Utils/Exception.cti b/Utils/Exception.cti index 3588cdcac3dc29c9d5e357ca7f04c39c597001da..a3989080a8b9fafbc052068a5a3ab67518eb15e4 100644 --- a/Utils/Exception.cti +++ b/Utils/Exception.cti @@ -31,11 +31,12 @@ #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/////////////////////////////////////// diff --git a/Utils/Exception.hh b/Utils/Exception.hh index eda57d1cbef217ce9f5a7be68cabc056b6e604cc..5f00926f4c64ee639965351ef17bcd55647cc598 100644 --- a/Utils/Exception.hh +++ b/Utils/Exception.hh @@ -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 diff --git a/Utils/Exception.test.cc b/Utils/Exception.test.cc index 3e5142878e2c364255adb97f2e326d35d20d4b7d..d3900627f5f4a0122c769ea6a5fef677db0931bb 100644 --- a/Utils/Exception.test.cc +++ b/Utils/Exception.test.cc @@ -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" ); } }