Packets/GenericTLV: added some documentation
[senf.git] / senf / Packets / GenericTLV.hh
index 6f89e82..e6f798a 100644 (file)
 #define HH_SENF_Packets_GenericTLV_ 1
 
 // Custom includes
+#include <boost/ptr_container/ptr_map.hpp>
 #include <senf/Packets/Packets.hh>
 #include <senf/Utils/type_traits.hh>
+#include <senf/Utils/singleton.hh>
 
 //#include "GenericTLV.hh.mpp"
 ///////////////////////////////hh.p////////////////////////////////////////
@@ -53,7 +55,7 @@ namespace senf {
         \endcode
        
         Your concrete TLV parsers will inherit from this base class and have to define a specific
-        value field and a \c TYPEID member:
+        value field and a \c typeId member:
         \code
         struct MyConcreteTLVParser : public MyTLVParserBase
         {
@@ -63,10 +65,10 @@ namespace senf {
             SENF_PARSER_FINALIZE ( MyConcreteTLVParser         );
          
             SENF_PARSER_INIT() {
-                type() = TYPEID;
+                type() = typeId;
                 length_() = 4;
             }        
-            static const type_t::value_type TYPEID = 0x42;
+            static const type_t::value_type typeId = 0x42;
         };
         \endcode
        
@@ -89,7 +91,7 @@ namespace senf {
         typedef senf::GenericTLVParserBase<MyTLVParserBase> MyGenericTLVParser;
         \endcode
         
-        This generiv tlv parser can now be used for example in a list:
+        This generic tlv parser can now be used for example in a list:
         \code
         class MyTestPacketParser : public senf::PacketParserBase
         {
@@ -124,7 +126,8 @@ namespace senf {
         \endcode  
 
         \see 
-            IPv6GenericOptionTLVParser, WLANGenericInfoElementParser, MIHGenericTLVParser 
+            IPv6GenericOptionParser, WLANGenericInfoElementParser, MIHGenericTLVParser \n
+            GenericTLVParserRegistry
      */
     template <class Base>
     class GenericTLVParserBase : public Base
@@ -147,6 +150,8 @@ namespace senf {
 
         senf::PacketInterpreterBase::range value() const;
         
+        void dump(std::ostream & os) const;
+        
 #ifndef DOXYGEN
         template<class ForwardReadableRange>
         void value(ForwardReadableRange const & val,
@@ -174,8 +179,110 @@ namespace senf {
         Base & self();
         Base const & self() const;
     };
-}
+    
+    
+    namespace detail {
+        template <class BaseParser>
+        struct GenericTLVParserRegistry_EntryBase {
+            virtual void dump(GenericTLVParserBase<BaseParser> const & parser, std::ostream & os) const = 0;
+        };
+    
+        template <class BaseParser, class Parser>
+        struct GenericTLVParserRegistry_Entry
+            : GenericTLVParserRegistry_EntryBase<BaseParser>
+        {
+            virtual void dump(GenericTLVParserBase<BaseParser> const & parser, std::ostream & os) const;
+        };
+    }
+    
+    /** \brief TLV parser registration facility
 
+        The %GenericTLVParserRegistry provides a generic facility to globally register concrete
+        TLV parser by the type value. The concrete TLV parser must therefore provide a \c typeId
+        member. See GenericTLVParserBase for details about the assumed class structure.
+        
+        Every registry is identified by the base tlv parser class. Parsers can be registered 
+        statically only: 
+        \code
+        GenericTLVParserRegistry<MyTLVParserBase>::RegistrationProxy<ConcreteTLVParser>
+            registerConcreteTLVParser;
+        \endcode 
+        This global variable declaration will register ConcreteTLVParser. The variable 
+        registerConcreteTLVParser is a dummy. It's only function is to force the call of 
+        it's constructor during global construction time. This static registration only
+        works when the symbol is included into the final binary.
+        
+        To simplify the registration the \ref SENF_PACKET_TLV_REGISTRY_REGISTER macro can be used.
+        The \c ConreteTLVParser must therefore provide a \c Registry typedef pointing to the
+        %GenericTLVParserRegistry; typically you put this typedef to the TLVBaseParser class.
+        \code
+        struct MyTLVParserBase : public senf::PacketParserBase
+        {
+            ...
+            typedef GenericTLVParserRegistry<MyTLVParserBase> Registry;
+        };
+        struct MyConcreteTLVParser : public MyTLVParserBase
+        {
+            ....
+            static const type_t::value_type typeId = 0x42;
+            void dump(std::ostream & os) const;
+        };
+        
+        // register MyConcreteTLVParser to the MyTLVParserBase-Registry with the type id 0x42:
+        SENF_PACKET_TLV_REGISTRY_REGISTER( MyConcreteTLVParser );
+        \endcode
+        
+        The registry provides a dump() member to dump an instance of a generic TLV parser.
+        If the type value of the given TLV parser is registered the generic tlv will be
+        casted to the registered concrete TLV parser and the dump member from this parser
+        will be called. Otherwise the generic TLV parser will be dumped in a generic way
+        (hexdump of the value).
+        
+        \see
+            GenericTLVParserBase for the general TLV class structure \n
+            IPv6OptionParser::Registry, WLANInfoElementParser::Registry,
+            MIHBaseTLVParser::Registry 
+     */
+    template <class BaseParser>
+    class GenericTLVParserRegistry
+        : public senf::singleton<GenericTLVParserRegistry<BaseParser> >
+    {
+        typedef boost::ptr_map<
+            typename BaseParser::type_t::value_type, 
+            detail::GenericTLVParserRegistry_EntryBase<BaseParser> > Map;
+        Map map_;
+        
+        GenericTLVParserRegistry() {};
+    public:
+        using senf::singleton<GenericTLVParserRegistry<BaseParser> >::instance;
+        friend class senf::singleton<GenericTLVParserRegistry<BaseParser> >;
+        
+        template <class PacketParser>
+        struct RegistrationProxy {
+            RegistrationProxy();
+        };
+
+        template <typename Parser>
+        void registerParser();
+        
+        void dump(GenericTLVParserBase<BaseParser> const & parser, std::ostream & os) const;
+    };
+        
+    /** \brief Statically add an entry to a TLV parser registry
+
+        This macro will declare an anonymous global variable in such a way, that constructing 
+        this variable will register the given tlv parser.
+
+        \hideinitializer
+        \see senf::GenericTLVParserRegistry
+     */
+#   define SENF_PACKET_TLV_REGISTRY_REGISTER( ConreteTLVParser )                \
+        namespace {                                                             \
+            ConreteTLVParser::Registry::RegistrationProxy<ConreteTLVParser>     \
+                    BOOST_PP_CAT(tlvparserRegistration_, __LINE__);             \
+        }
+        
+}
 
 ///////////////////////////////hh.e////////////////////////////////////////
 //#include "GenericTLV.cci"