switch to new MPL based Fraunhofer FOKUS Public License
[senf.git] / senf / Packets / PacketRegistry.hh
index 2311f3e..60de344 100644 (file)
@@ -2,23 +2,28 @@
 //
 // Copyright (C) 2006
 // 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
-// the Free Software Foundation; either version 2 of the License, or
-// (at your option) any later version.
+// The contents of this file are subject to the Fraunhofer FOKUS Public License
+// Version 1.0 (the "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at 
+// http://senf.berlios.de/license.html
 //
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
+// The Fraunhofer FOKUS Public License Version 1.0 is based on, 
+// but modifies the Mozilla Public License Version 1.1.
+// See the full license text for the amendments.
 //
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the
-// Free Software Foundation, Inc.,
-// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+// Software distributed under the License is distributed on an "AS IS" basis, 
+// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 
+// for the specific language governing rights and limitations under the License.
+//
+// The Original Code is Fraunhofer FOKUS code.
+//
+// The Initial Developer of the Original Code is Fraunhofer-Gesellschaft e.V. 
+// (registered association), Hansastraße 27 c, 80686 Munich, Germany.
+// All Rights Reserved.
+//
+// Contributor(s):
+//   Stefan Bund <g0dil@berlios.de>
 
 /** \file
     \brief PacketRegistry public header */
 #define HH_SENF_Packets_PacketRegistry_ 1
 
 // Custom includes
-#include <map>
-#include <boost/utility.hpp> // for boost::noncopyable
 #include <boost/optional.hpp>
 #include <boost/preprocessor/cat.hpp>
-#include "../Utils/Exception.hh"
+#include <senf/Utils/Exception.hh>
+#include <senf/Utils/singleton.hh>
 #include "Packet.hh"
 
 #include "PacketRegistry.ih"
 //#include "PacketRegistry.mpp"
-///////////////////////////////hh.p////////////////////////////////////////
+//-/////////////////////////////////////////////////////////////////////////////////////////////////
 
 namespace senf {
 
@@ -68,42 +72,53 @@ namespace senf {
         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);
+        SENF_PACKET_REGISTRY_REGISTER( SomeTag, key_of_somePacket, SomePacket );
         \endcode
 
-        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.
+        SENF_PACKET_REGISTRY_REGISTER will declare an anonymous global variable which will ensure,
+        the packet is registered automatically during global initialization (as long as the object
+        file is linked into the final executable).
+
+        \section packet_registry_priority Multiple registration for a single key
+
+        Ordinarily, the PacketRegistry will reject registering the same key twice. However, the
+        registry supports an additional priority parameter when registering a packet. You may
+        register multiple Packets with the same \a key as long as the \a priority is unique. The
+        registration with the highest \a priority value will take precedence on key lookup.
 
         \ingroup packet_module
      */
     template <class Tag>
     class PacketRegistry
+        : private senf::singleton< PacketRegistry<Tag> >
     {
     public:
         typedef typename detail::PacketRegistryImpl<typename Tag::key_t>::iterator iterator;
+        typedef typename detail::PacketRegistryImpl<typename Tag::key_t>::Entry Entry;
 
         /** \brief Statically register a packet type in a PacketRegistry
 
-            To use this class, define a global symbol in the following way:
+            This class is normally used via SENF_PACKET_REGISTRY_REGISTER. To use this class
+            directly, define a symbol in the following way:
             \code
             namespace {
-                senf::PacketRegistry<Tag>::RegistrationProxy<PacketType>
-                    registerPacketType (key);
+                senf::PacketRegistry<Tag>::ScopedRegistrationProxy<PacketType>
+                    registerPacketType (key, optional_priority);
             }
-            \endcode Here  \a Tag  is the type  tag of the  registry to  register the packet  in, \a
+            \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.
+
+            The packet will be registered in the constructor and will be unregistered when the scope
+            of \c registerPacketType ends.
          */
         template <class PacketType>
-        struct RegistrationProxy
+        struct ScopedRegistrationProxy
         {
-            RegistrationProxy(typename Tag::key_t key);
+            ScopedRegistrationProxy(typename Tag::key_t key, int priority=0);
+            ~ScopedRegistrationProxy();
         };
 
         /** \brief Register new packet type
@@ -111,15 +126,37 @@ namespace senf {
             Register \a PacketType in the packet registry \a Tag under the given \a key.
 
             \par Preconditions:
-                The given \a key must be unique and not be assigned to any other
+                The given pair \a key, \a priority 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.
 
             \tparam PacketType ConcretePacket instantiation of packet to register
-            \param key The key of the packet
+            \param[in] key The key of the packet
+            \param [in] priority Optional priority
          */
         template <class PacketType>
-        static void registerPacket(typename Tag::key_t key);
+        static void registerPacket(typename Tag::key_t key, int priority=0);
+
+        /** \brief Unregister packet by packet type
+
+            Removes \a PacketType from the packet registry. If the packet type is not registered,
+            this is a no-op.
+
+            \tparam PacketType ConcretePacket instantiation of packet to remove from registry
+         */
+        template <class PacketType>
+        static void unregisterPacket();
+
+        /** \brief Unregister packet by key
+
+            Removes the packet registration for \a key (and \a priority) from the registry. If no
+            packet is registered with the given pair \a key, \a priority, this operation is a
+            no-op.
+
+            \param[in] key Key to remove from the registry
+            \param[in] priority Optional priority of the key to remove
+         */
+        static void unregisterPacket(typename Tag::key_t key, int priority=0);
 
         /** \brief Find key of a packet type
 
@@ -138,7 +175,7 @@ namespace senf {
 
             \tparam 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
+                href="http://www.boost.org/doc/libs/release/libs/optional/index.html">boost::optional</a> or
                 an unbound optional, if the key is not found.
          */
         template <class PacketType>
@@ -160,7 +197,7 @@ namespace senf {
 
             \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
+                href="http://www.boost.org/doc/libs/release/libs/optional/index.html">boost::optional</a> or
                 an unbound optional, if the key is not found.
          */
         static typename boost::optional<typename Tag::key_t> key(Packet const & packet, NoThrow_t);
@@ -170,25 +207,33 @@ namespace senf {
             \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);
+        static 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);
+        static Entry const * lookup(typename Tag::key_t key, NoThrow_t);
 
-        /** \brief Beginning iterator to list of registered keys
+        /** \brief Beginning iterator to list of registered entries
          */
         static iterator begin();
 
-        /** \brief End iterator to list of registered keys
+        /** \brief End iterator to list of registered entries
          */
         static iterator end();
 
     private:
+        using singleton<PacketRegistry>::instance;
+        using singleton<PacketRegistry>::alive;
+
+        PacketRegistry();
+
         typedef detail::PacketRegistryImpl<typename Tag::key_t> Registry;
         static Registry & registry();
+        Registry registry_;
+
+        friend class senf::singleton< PacketRegistry >;
     };
 
     /** \brief Statically add an entry to a packet registry
@@ -196,12 +241,27 @@ namespace senf {
         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.
 
+        \ingroup packet_module
         \hideinitializer
      */
-#   define SENF_PACKET_REGISTRY_REGISTER( registry, value, type )                                 \
-        namespace {                                                                               \
-            senf::PacketRegistry< registry >::RegistrationProxy< type >                           \
-                BOOST_PP_CAT(packetRegistration_, __LINE__) ( value );                            \
+#   define SENF_PACKET_REGISTRY_REGISTER( registry, value, type )       \
+        namespace {                                                     \
+            senf::PacketRegistry< registry >::ScopedRegistrationProxy< type > \
+            BOOST_PP_CAT(packetRegistration_, __LINE__) ( value );      \
+        }
+
+    /** \brief Statically add an entry to a packet registry with explicit priority
+
+        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.
+
+        \ingroup packet_module
+        \hideinitializer
+     */
+#   define SENF_PACKET_REGISTRY_REGISTER_PRIORITY( registry, value, priority, type ) \
+        namespace {                                                     \
+            senf::PacketRegistry< registry >::ScopedRegistrationProxy< type > \
+            BOOST_PP_CAT(packetRegistration_, __LINE__) ( value, priority ); \
         }
 
     /** \brief Dump all packet registries
@@ -216,11 +276,11 @@ namespace senf {
         This exception is signaled whenever a throwing lookup operation fails.
      */
     struct PacketTypeNotRegisteredException : public senf::Exception
-    { PacketTypeNotRegisteredException() : senf::Exception("packet type not registered"){} };
+    { PacketTypeNotRegisteredException() : senf::Exception("packet type not registered") {} };
 
 }
 
-///////////////////////////////hh.e////////////////////////////////////////
+//-/////////////////////////////////////////////////////////////////////////////////////////////////
 #endif
 #if !defined(HH_SENF_Packets_Packets__decls_) && !defined(HH_SENF_Packets_PacketRegistry_i_)
 #define HH_SENF_Packets_PacketRegistry_i_
@@ -229,7 +289,7 @@ namespace senf {
 #include "PacketRegistry.cti"
 #endif
 
-
+\f
 // Local Variables:
 // mode: c++
 // fill-column: 100
@@ -239,4 +299,3 @@ namespace senf {
 // compile-command: "scons -u test"
 // comment-column: 40
 // End:
-