Packets: Packet Registry unregister() support
[senf.git] / senf / Packets / PacketRegistry.hh
1 // $Id$
2 //
3 // Copyright (C) 2006
4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 //     Stefan Bund <g0dil@berlios.de>
7 //
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 // GNU General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the
20 // Free Software Foundation, Inc.,
21 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22
23 /** \file
24     \brief PacketRegistry public header */
25
26 #ifndef HH_SENF_Packets_PacketRegistry_
27 #define HH_SENF_Packets_PacketRegistry_ 1
28
29 // Custom includes
30 #include <map>
31 #include <boost/utility.hpp> // for boost::noncopyable
32 #include <boost/optional.hpp>
33 #include <boost/preprocessor/cat.hpp>
34 #include <senf/Utils/Exception.hh>
35 #include "Packet.hh"
36
37 #include "PacketRegistry.ih"
38 //#include "PacketRegistry.mpp"
39 ///////////////////////////////hh.p////////////////////////////////////////
40
41 namespace senf {
42
43     /** \brief %Packet registration facility
44
45         The %PacketRegistry provides a generic facility to associate an arbitrary key with
46         Packets. Example keys are Ethertype or IP protocols.
47
48         Every %PacketRegistry is identified by a type tag:
49         \code
50         struct SomeTag {
51             typedef some_key_type key_t;
52         };
53         \endcode
54         The key type can be an arbitrary value type. The %PacketRegistry for this Tag can then be
55         accessed using <code>senf::PacketRegistry<SomeTag>::</code>.
56
57         The %PacketRegistry class has only static members and provides access to the packet
58         registry. It allows two-way lookup either by key or by packet type.
59
60         \code
61         senf::Packet::factory_t factory (senf::PacketRegistry<SomeTag>::lookup(some_key).factory());
62         SomeTag::key_t key = PacketRegistry<SomeTag>::key<SomePacket>();
63         \endcode
64
65         Packets can be registered either dynamically or statically. Dynamic:
66         \code
67         // dynamic registration
68         senf::PacketRegistry<SomeTag>::registerPacket<SomePacket>(key_of_somePacket);
69
70         // static registration. 'registerSomePacket' is an arbitrary symbol name
71         senf::PacketRegistry<SomeTag>::RegistrationProxy<SomePacket>
72             registerSomePacket (key_of_somePacket);
73         \endcode
74
75         This global variable declaration will register \a SomePacket with the \a SomeTag registry
76         under the key \a key_of_somePacket. The variable \a registerSomePacket is a dummy. It's only
77         function is to force the call of it's constructor during global construction time. This
78         static registration only works when the symbol is included into the final binary. To force
79         this inclusion, you should not put packet registrations into a library but into an object
80         file.
81
82         To simplify static registration the SENF_PACKET_REGISTRY_REGISTER macro can be used:
83         \code
84         SENF_PACKET_REGISTRY_REGISTER(SomeTag, SomePacket, key_of_somePacket);
85         \endcode
86
87         \ingroup packet_module
88      */
89     template <class Tag>
90     class PacketRegistry
91     {
92     public:
93         typedef typename detail::PacketRegistryImpl<typename Tag::key_t>::iterator iterator;
94
95         /** \brief Statically register a packet type in a PacketRegistry
96
97             To use this class, define a global symbol in the following way:
98             \code
99             namespace {
100                 senf::PacketRegistry<Tag>::RegistrationProxy<PacketType>
101                     registerPacketType (key);
102             }
103             \endcode Here  \a Tag  is the type  tag of the  registry to  register the packet  in, \a
104             PacketType is the packet to register (this  is the ConcretePacket of that packet) and \a
105             key is  the key of  type \c Tag::key_t  under which the packet  is to be  registered. \a
106             registerPacketType is an arbitrary name for the global symbol.
107          */
108         template <class PacketType>
109         struct RegistrationProxy
110         {
111             RegistrationProxy(typename Tag::key_t key);
112             ~RegistrationProxy();
113         };
114
115         /** \brief Register new packet type
116
117             Register \a PacketType in the packet registry \a Tag under the given \a key.
118
119             \par Preconditions:
120                 The given \a key must be unique and not be assigned to any other
121                 packet class in this registry.  The %Packet must not already be registered in the
122                 registry.
123
124             \tparam PacketType ConcretePacket instantiation of packet to register
125             \param key The key of the packet
126          */
127         template <class PacketType>
128         static void registerPacket(typename Tag::key_t key);
129
130         template <class PacketType>
131         static void unregisterPacket();
132         static void unregisterPacket(typename Tag::key_t key);
133
134         /** \brief Find key of a packet type
135
136             Return the key of \a PacketType as registered in the \a Tag registry
137
138             \tparam PacketType packet of which the key is requested
139             \returns key of the packet
140             \throws PacketTypeNotRegistered if the packet type is not found in the registry.
141          */
142         template <class PacketType>
143         static typename Tag::key_t key();
144
145         /** \brief Find key of a packet type
146
147             Return the key of \a PacketType as registered in the \a Tag registry
148
149             \tparam PacketType packet of which the key is requested
150             \returns key of the packet wrapped in a <a
151                 href="http://www.boost.org/libs/optional/doc/optional.html">boost::optional</a> or
152                 an unbound optional, if the key is not found.
153          */
154         template <class PacketType>
155         static typename boost::optional<typename Tag::key_t> key(NoThrow_t);
156
157         /** \brief Find key of a packet
158
159             Return the key of \a packet, an arbitrary packet, as registered in the \a Tag registry.
160
161             \param packet The packet of which the key is requested
162             \returns key of the packet
163             \throws PacketTypeNotRegistered if the packet type is not found in the registry.
164          */
165         static typename Tag::key_t key(Packet const & packet);
166
167         /** \brief Find key of a packet
168
169             Return the key of \a packet, an arbitrary packet, as registered in the \a Tag registry.
170
171             \param packet The packet of which the key is requested
172             \returns key of the packet wrapped in a <a
173                 href="http://www.boost.org/libs/optional/doc/optional.html">boost::optional</a> or
174                 an unbound optional, if the key is not found.
175          */
176         static typename boost::optional<typename Tag::key_t> key(Packet const & packet, NoThrow_t);
177
178         /** \brief Lookup a packet by it's key
179
180             \throws PacketTypeNotRegistered if the \a key is not found in the registry
181             \return %Packet entry for given \a key
182          */
183         static PkReg_Entry const & lookup(typename Tag::key_t key);
184
185         /** \brief Lookup a packet by it's key
186             \return Pointer to packet entry for given \a key or 0, if the key is not found in the
187                 registry.
188          */
189         static PkReg_Entry const * lookup(typename Tag::key_t key, NoThrow_t);
190
191         /** \brief Beginning iterator to list of registered keys
192          */
193         static iterator begin();
194
195         /** \brief End iterator to list of registered keys
196          */
197         static iterator end();
198
199     private:
200         typedef detail::PacketRegistryImpl<typename Tag::key_t> Registry;
201         static Registry & registry();
202     };
203
204     /** \brief Statically add an entry to a packet registry
205
206         This macro will declare an anonymous global variable in such a way, that constructing this
207         variable will add a registration to the given packet registry.
208
209         \ingroup packet_module
210         \hideinitializer
211      */
212 #   define SENF_PACKET_REGISTRY_REGISTER( registry, value, type )                                 \
213         namespace {                                                                               \
214             senf::PacketRegistry< registry >::RegistrationProxy< type >                           \
215                 BOOST_PP_CAT(packetRegistration_, __LINE__) ( value );                            \
216         }
217
218     /** \brief Dump all packet registries
219
220         This command will dump all packet registries to the given stream. This is to help debugging
221         registration problems.
222      */
223     void dumpPacketRegistries(std::ostream & os);
224
225     /** \brief Entry not found in registry
226
227         This exception is signaled whenever a throwing lookup operation fails.
228      */
229     struct PacketTypeNotRegisteredException : public senf::Exception
230     { PacketTypeNotRegisteredException() : senf::Exception("packet type not registered") {} };
231
232 }
233
234 ///////////////////////////////hh.e////////////////////////////////////////
235 #endif
236 #if !defined(HH_SENF_Packets_Packets__decls_) && !defined(HH_SENF_Packets_PacketRegistry_i_)
237 #define HH_SENF_Packets_PacketRegistry_i_
238 #include "PacketRegistry.cci"
239 #include "PacketRegistry.ct"
240 #include "PacketRegistry.cti"
241 #endif
242
243 \f
244 // Local Variables:
245 // mode: c++
246 // fill-column: 100
247 // c-file-style: "senf"
248 // indent-tabs-mode: nil
249 // ispell-local-dictionary: "american"
250 // compile-command: "scons -u test"
251 // comment-column: 40
252 // End: