Packets: Macros and unit-tests for the PacketRegistry priority 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         typedef typename detail::PacketRegistryImpl<typename Tag::key_t>::Entry Entry;
95
96         /** \brief Statically register a packet type in a PacketRegistry
97
98             To use this class, define a global symbol in the following way:
99             \code
100             namespace {
101                 senf::PacketRegistry<Tag>::RegistrationProxy<PacketType>
102                     registerPacketType (key);
103             }
104             \endcode Here  \a Tag  is the type  tag of the  registry to  register the packet  in, \a
105             PacketType is the packet to register (this  is the ConcretePacket of that packet) and \a
106             key is  the key of  type \c Tag::key_t  under which the packet  is to be  registered. \a
107             registerPacketType is an arbitrary name for the global symbol.
108          */
109         template <class PacketType>
110         struct RegistrationProxy
111         {
112             RegistrationProxy(typename Tag::key_t key, int priority=0);
113             ~RegistrationProxy();
114         };
115
116         /** \brief Register new packet type
117
118             Register \a PacketType in the packet registry \a Tag under the given \a key.
119
120             \par Preconditions:
121                 The given \a key must be unique and not be assigned to any other
122                 packet class in this registry.  The %Packet must not already be registered in the
123                 registry.
124
125             \tparam PacketType ConcretePacket instantiation of packet to register
126             \param key The key of the packet
127          */
128         template <class PacketType>
129         static void registerPacket(typename Tag::key_t key, int priority=0);
130
131         template <class PacketType>
132         static void unregisterPacket();
133         static void unregisterPacket(typename Tag::key_t key, int priority=0);
134
135         /** \brief Find key of a packet type
136
137             Return the key of \a PacketType as registered in the \a Tag registry
138
139             \tparam PacketType packet of which the key is requested
140             \returns key of the packet
141             \throws PacketTypeNotRegistered if the packet type is not found in the registry.
142          */
143         template <class PacketType>
144         static typename Tag::key_t key();
145
146         /** \brief Find key of a packet type
147
148             Return the key of \a PacketType as registered in the \a Tag registry
149
150             \tparam PacketType packet of which the key is requested
151             \returns key of the packet wrapped in a <a
152                 href="http://www.boost.org/libs/optional/doc/optional.html">boost::optional</a> or
153                 an unbound optional, if the key is not found.
154          */
155         template <class PacketType>
156         static typename boost::optional<typename Tag::key_t> key(NoThrow_t);
157
158         /** \brief Find key of a packet
159
160             Return the key of \a packet, an arbitrary packet, as registered in the \a Tag registry.
161
162             \param packet The packet of which the key is requested
163             \returns key of the packet
164             \throws PacketTypeNotRegistered if the packet type is not found in the registry.
165          */
166         static typename Tag::key_t key(Packet const & packet);
167
168         /** \brief Find key of a packet
169
170             Return the key of \a packet, an arbitrary packet, as registered in the \a Tag registry.
171
172             \param packet The packet of which the key is requested
173             \returns key of the packet wrapped in a <a
174                 href="http://www.boost.org/libs/optional/doc/optional.html">boost::optional</a> or
175                 an unbound optional, if the key is not found.
176          */
177         static typename boost::optional<typename Tag::key_t> key(Packet const & packet, NoThrow_t);
178
179         /** \brief Lookup a packet by it's key
180
181             \throws PacketTypeNotRegistered if the \a key is not found in the registry
182             \return %Packet entry for given \a key
183          */
184         static Entry const & lookup(typename Tag::key_t key);
185
186         /** \brief Lookup a packet by it's key
187             \return Pointer to packet entry for given \a key or 0, if the key is not found in the
188                 registry.
189          */
190         static Entry const * lookup(typename Tag::key_t key, NoThrow_t);
191
192         /** \brief Beginning iterator to list of registered keys
193          */
194         static iterator begin();
195
196         /** \brief End iterator to list of registered keys
197          */
198         static iterator end();
199
200     private:
201         typedef detail::PacketRegistryImpl<typename Tag::key_t> Registry;
202         static Registry & registry();
203     };
204
205     /** \brief Statically add an entry to a packet registry
206
207         This macro will declare an anonymous global variable in such a way, that constructing this
208         variable will add a registration to the given packet registry.
209
210         \ingroup packet_module
211         \hideinitializer
212      */
213 #   define SENF_PACKET_REGISTRY_REGISTER( registry, value, type )       \
214         namespace {                                                     \
215             senf::PacketRegistry< registry >::RegistrationProxy< type > \
216             BOOST_PP_CAT(packetRegistration_, __LINE__) ( value );      \
217         }
218
219     /** \brief Statically add an entry to a packet registry
220
221         This macro will declare an anonymous global variable in such a way, that constructing this
222         variable will add a registration to the given packet registry.
223
224         \ingroup packet_module
225         \hideinitializer
226      */
227 #   define SENF_PACKET_REGISTRY_REGISTER_PRIORITY( registry, value, priority, type ) \
228         namespace {                                                     \
229             senf::PacketRegistry< registry >::RegistrationProxy< type > \
230             BOOST_PP_CAT(packetRegistration_, __LINE__) ( value, priority ); \
231         }
232
233     /** \brief Dump all packet registries
234
235         This command will dump all packet registries to the given stream. This is to help debugging
236         registration problems.
237      */
238     void dumpPacketRegistries(std::ostream & os);
239
240     /** \brief Entry not found in registry
241
242         This exception is signaled whenever a throwing lookup operation fails.
243      */
244     struct PacketTypeNotRegisteredException : public senf::Exception
245     { PacketTypeNotRegisteredException() : senf::Exception("packet type not registered") {} };
246
247 }
248
249 ///////////////////////////////hh.e////////////////////////////////////////
250 #endif
251 #if !defined(HH_SENF_Packets_Packets__decls_) && !defined(HH_SENF_Packets_PacketRegistry_i_)
252 #define HH_SENF_Packets_PacketRegistry_i_
253 #include "PacketRegistry.cci"
254 #include "PacketRegistry.ct"
255 #include "PacketRegistry.cti"
256 #endif
257
258 \f
259 // Local Variables:
260 // mode: c++
261 // fill-column: 100
262 // c-file-style: "senf"
263 // indent-tabs-mode: nil
264 // ispell-local-dictionary: "american"
265 // compile-command: "scons -u test"
266 // comment-column: 40
267 // End: