Packets: Fix VariantParser invalid parser access bug
[senf.git] / Packets / PacketRegistry.hh
index 9bdfa75..1fa7d99 100644 (file)
@@ -1,9 +1,9 @@
 // $Id$
 //
 // Copyright (C) 2006
-// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
-// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-//     Stefan Bund <stefan.bund@fokus.fraunhofer.de>
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+//     Stefan Bund <g0dil@berlios.de>
 //
 // This program is free software; you can redistribute it and/or modify
 // it under the terms of the GNU General Public License as published by
 // Free Software Foundation, Inc.,
 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
+/** \file
+    \brief PacketRegistry public header */
 
-#ifndef HH_PacketRegistryImpl_
-#define HH_PacketRegistryImpl_ 1
+#ifndef HH_SENF_Packets_PacketRegistry_
+#define HH_SENF_Packets_PacketRegistry_ 1
 
 // Custom includes
 #include <map>
 #include <boost/utility.hpp> // for boost::noncopyable
-#include <boost/shared_ptr.hpp>
+#include <boost/optional.hpp>
+#include <boost/preprocessor/cat.hpp>
+#include "../Utils/Exception.hh"
 #include "Packet.hh"
 
+#include "PacketRegistry.ih"
 //#include "PacketRegistry.mpp"
 ///////////////////////////////hh.p////////////////////////////////////////
 
 namespace senf {
 
-
-    namespace impl { template <class key> class PacketRegistryImpl; }
-
     /** \brief Packet registration facility
 
-        The PacketRegistry provides a generic facility to associate an
-        arbitrary key with Packets. Example keys are Ethertype or IP
-        protocols.
+        The PacketRegistry provides a generic facility to associate an arbitrary key with
+        Packets. Example keys are Ethertype or IP protocols.
 
         Every PacketRegistry is identified by a type tag:
         \code
-          struct SomeTag {
-              typedef some_key_type key_t;
-          };
+        struct SomeTag {
+            typedef some_key_type key_t;
+        };
         \endcode
-        The key type can be an arbitrary value type. The PacketRegistry
-        for this Tag can then be accessed using
-        <code>PacketRegistry<SomeTag>::</code>.
+        The key type can be an arbitrary value type. The PacketRegistry for this Tag can then be
+        accessed using <code>senf::PacketRegistry<SomeTag>::</code>.
 
-        The PacketRegistry class has only static members and provides
-        access to the packet registry. It allows to register Packet
-        classes and to create new Packets given a key. Methods are
-        also provided to find the key of a Packet type.
+        The PacketRegistry class has only static members and provides access to the packet
+        registry. It allows two-way lookup either by key or by packet type. 
 
         \code
-            PacketRegistry<SomeTag>::registerPacket<SomePacket>(key_of_somePacket);
-            p = PacketRegistry<SomeTag>::create(some_key,begin,end);
-            SomeTag::key_t key = PacketRegistry<SomeTag>::key<SomePacket>();
+        senf::Packet::factory_t factory (senf::PacketRegistry<SomeTag>::lookup(some_key).factory());
+        SomeTag::key_t key = PacketRegistry<SomeTag>::key<SomePacket>();
         \endcode
 
-        Normally, packet classes are registered statically and not
-        procedurally. To this end, the RegistrationProxy is provided:
+        Packets can be registered either dynamically or statically. Dynamic:
         \code
-          PacketRegistry<SomeTag>::RegistrationProxy<SomePacket>
-              registerSomePacket (key_of_somePacket);
+        // dynamic registration
+        senf::PacketRegistry<SomeTag>::registerPacket<SomePacket>(key_of_somePacket);
+
+        // static registration. 'registerSomePacket' is an arbitrary symbol name
+        senf::PacketRegistry<SomeTag>::RegistrationProxy<SomePacket>
+            registerSomePacket (key_of_somePacket);
         \endcode
-        This global variable declaration will register \c SomePacket
-        with the \c SomeTag registry under the key \c
-        key_of_somePacket. The variable \c registerSomePacket is a
-        dummy. It's only function is to force the call of it's
-        constructor during global construction time.
-
-        The PacketRegistry's purpose is mostly to assist in
-        implementing the v_nextInterpreter() member of packet
-        facades. This is further supported by the PacketRegistryMixin
-        class.
-
-        \todo Add parameterless create() method
+
+        This global variable declaration will register \a SomePacket with the \a SomeTag registry
+        under the key \a key_of_somePacket. The variable \a registerSomePacket 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 force
+        this inclusion, you should not put packet registrations into a library but into an object
+        file.
+        
+        \ingroup packet_module
      */
     template <class Tag>
     class PacketRegistry
     {
     public:
+        typedef typename detail::PacketRegistryImpl<typename Tag::key_t>::iterator iterator;
+
         /** \brief Statically register a packet type in a PacketRegistry
+
+            To use this class, define a global symbol in the following way:
+            \code
+            namespace {
+                senf::PacketRegistry<Tag>::RegistrationProxy<PacketType>
+                    registerPacketType (key);
+            }
+            \endcode Here  \a Tag  is the type  tag of the  registry to  register the packet  in, \a
+            PacketType is the packet to register (this  is the ConcretePacket of that packet) and \a
+            key is  the key of  type \c Tag::key_t  under which the packet  is to be  registered. \a
+            registerPacketType is an arbitrary name for the global symbol.
          */
-        template <class OtherPacket>
+        template <class PacketType>
         struct RegistrationProxy
         {
             RegistrationProxy(typename Tag::key_t key);
@@ -98,102 +108,123 @@ namespace senf {
 
         /** \brief Register new packet type
 
-            Register \c OtherPacket in the packet registry \c Tag
-            under the given \c key.
+            Register \a PacketType in the packet registry \a Tag under the given \a key.
 
-            \par Preconditions:
-                The given \c key must be unique and not be assigned to
-                any other packet class in this registry.
-                The Packet must not already be registered in the registry.
+            \par Preconditions: The given \a key must be unique and not be assigned to any other
+                packet class in this registry.  The Packet must not already be registered in the
+                registry.
 
-            \param OtherPacket packet to register
-            \param key key of the packet
+            \param PacketType ConcretePacket instantiation of packet to register
+            \param key The key of the packet
          */
-        template <class OtherPacket>
+        template <class PacketType>
         static void registerPacket(typename Tag::key_t key);
 
-        /** \brief Find key of a packet
+        /** \brief Find key of a packet type
 
-            Return the key of \c OtherPacket as registered in the \c
-            Tag registry
+            Return the key of \a PacketType as registered in the \a Tag registry
 
-            \param OtherPacket packet of which the key is requested
+            \param PacketType packet of which the key is requested
             \returns key of the packet
-            \throws PacketTypeNotRegistered if the packet type is not
-                found in the registry.
+            \throws PacketTypeNotRegistered if the packet type is not found in the registry.
          */
-        template <class OtherPacket>
+        template <class PacketType>
         static typename Tag::key_t key();
 
-        /** \brief Create new Packet
+        /** \brief Find key of a packet type
+
+            Return the key of \a PacketType as registered in the \a Tag registry
+
+            \param PacketType packet of which the key is requested
+            \returns key of the packet wrapped in a <a
+                href="http://www.boost.org/libs/optional/doc/optional.html">boost::optional</a> or
+                an unbound optional, if the key is not found.
+         */
+        template <class PacketType>
+        static typename boost::optional<typename Tag::key_t> key(NoThrow_t);
+
+        /** \brief Find key of a packet
+
+            Return the key of \a packet, an arbitrary packet, as registered in the \a Tag registry.
+
+            \param packet The packet of which the key is requested
+            \returns key of the packet
+            \throws PacketTypeNotRegistered if the packet type is not found in the registry.
+         */        
+        static typename Tag::key_t key(Packet packet);
+
+        /** \brief Find key of a packet
 
-            \param key Key of packet type to create instance of
-            \param b begin iterator argument to Packet::create()
-            \param e end iterator argument to Packet::create()
-            \returns new Instance of the packet type registered under
-                key or DataPacket, if the key is not registered.
+            Return the key of \a packet, an arbitrary packet, as registered in the \a Tag registry.
+
+            \param packet The 
+packet of which the key is requested
+            \returns key of the packet wrapped in a <a
+                href="http://www.boost.org/libs/optional/doc/optional.html">boost::optional</a> or
+                an unbound optional, if the key is not found.
          */
-        template <class InputIterator>
-        static Packet::ptr create(typename Tag::key_t key, InputIterator b, InputIterator e);
+        static typename boost::optional<typename Tag::key_t> key(Packet packet, NoThrow_t);
+
+        /** \brief Lookup a packet by it's key
+            
+            \throws PacketTypeNotRegistered if the \a key is not found in the registry
+            \return Packet entry for given \a key
+         */
+        static PkReg_Entry const & lookup(typename Tag::key_t key);
+
+        /** \brief Lookup a packet by it's key
+            \return Pointer to packet entry for given \a key or 0, if the key is not found in the
+                registry.
+         */
+        static PkReg_Entry const * lookup(typename Tag::key_t key, NoThrow_t);
+
+        /** \brief Beginning iterator to list of registered keys
+         */
+        static iterator begin();
+
+        /** \brief End iterator to list of registered keys
+         */
+        static iterator end();
 
     private:
-        typedef impl::PacketRegistryImpl<typename Tag::key_t> Registry;
+        typedef detail::PacketRegistryImpl<typename Tag::key_t> Registry;
         static Registry & registry();
-
-        template <class T, class D> friend class PacketRegistryMixin;
     };
 
-    /** \brief Helper class for v_nextInterpreter implementations
+    /** \brief Statically add an entry to a packet registry
 
-        This class is a helper class which is to be inherited from in
-        a packet facade which wants to register a new interpreter with
-        the packet framework depending on a packet registry.
+        This macro will declare an anonymous global variable in such a way, that constructing this
+        variable will add a registration to the given packet registry.
 
-        This mixin class provides a new registerInterpreter
-        implementation which can be used besides the methods provided
-        by senf::Packet to add a new interpreter to the
-        interpreter chain.
+        \hideinitializer
+     */
+#   define SENF_PACKET_REGISTRY_REGISTER( registry, value, type )                                 \
+        namespace {                                                                               \
+            senf::PacketRegistry< registry >::RegistrationProxy< type >                           \
+                BOOST_PP_CAT(packetRegistration_, __LINE__) ( value );                            \
+        }
 
-        \code
-          class SomePacket
-              : public Packet,
-                private PacketRegistryMixin<SomeTag,SomePacket>
-          {
-              using Packet::retgisterInterpreter;
-              using PacketRegistryMixin<SomeTag,SomePacket>::registerInterpreter;
-
-              virtual void v_nextInterpreter()
-              {
-                  registerInterpreter(some_key_value, subpacket_begin, subpacket_end);
-              }
-          };
-        \endcode
-        This example is not complete, it only contains the parts
-        concerned with PacketRegistryMixin.
+    /** \brief Dump all packet registries
+
+        This command will dump all packet registries to the given stream. This is to help debugging
+        registration problems.
      */
-    template <class Tag, class Derived>
-    class PacketRegistryMixin
-    {
-    protected:
-        /** \brief add interpreter to interpreter chain
-
-            This method is used by v_nextInterpreter() to add a new
-            interpreter to the interpreter chain (see the Packet
-            reference for more). Instead of specifying the type of
-            packet to use as a template argument it is specified using
-            the \c key value from the \c Tag registry
-         */
-        void registerInterpreter(typename Tag::key_t key,
-                                 Packet::iterator b, Packet::iterator e) const;
-    };
+    void dumpPacketRegistries(std::ostream & os);
 
-    struct PacketTypeNotRegistered : public std::exception
-    { virtual char const * what() const throw() { return "packet type not registered"; } };
+    /** \brief Entry not found in registry
+
+        This exception is signaled whenever a throwing lookup operation fails.
+     */
+    struct PacketTypeNotRegisteredException : public senf::Exception
+    { PacketTypeNotRegisteredException() : senf::Exception("packet type not registered"){} };
 
 }
 
 ///////////////////////////////hh.e////////////////////////////////////////
-//#include "PacketRegistry.cci"
+#endif
+#if !defined(HH_SENF_Packets_Packets__decls_) && !defined(HH_SENF_Packets_PacketRegistry_i_)
+#define HH_SENF_Packets_PacketRegistry_i_
+#include "PacketRegistry.cci"
 #include "PacketRegistry.ct"
 #include "PacketRegistry.cti"
 #endif
@@ -206,4 +237,6 @@ namespace senf {
 // indent-tabs-mode: nil
 // ispell-local-dictionary: "american"
 // compile-command: "scons -u test"
+// comment-column: 40
 // End:
+