a82e7b34cb637894803a3ae091e13eae002a32a2
[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_PACKET_REGISTRY_REGISTER( SomeTag, key_of_somePacket, SomePacket );
72         \endcode
73
74         SENF_PACKET_REGISTRY_REGISTER will declare an anonymous global variable which will ensure,
75         the packet is registered automatically during global initialization (as long as the object
76         file is linked into the final executable).
77
78         \section packet_registry_priority Multiple registration for a single key
79
80         Ordinarily, the PacketRegistry will reject registering the same key twice. However, the
81         registry supports an additional priority parameter when registering a packet. You may
82         register multiple Packets with the same \a key as long as the \a priority is unique. The
83         registration with the highest \a priority value will take precedence on key lookup.
84
85         \ingroup packet_module
86      */
87     template <class Tag>
88     class PacketRegistry
89     {
90     public:
91         typedef typename detail::PacketRegistryImpl<typename Tag::key_t>::iterator iterator;
92         typedef typename detail::PacketRegistryImpl<typename Tag::key_t>::Entry Entry;
93
94         /** \brief Statically register a packet type in a PacketRegistry
95
96             This class is normally used via SENF_PACKET_REGISTRY_REGISTER. To use this class
97             directly, define a symbol in the following way:
98             \code
99             namespace {
100                 senf::PacketRegistry<Tag>::ScopedRegistrationProxy<PacketType>
101                     registerPacketType (key, optional_priority);
102             }
103             \endcode
104             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             The packet will be registered in the constructor and will be unregistered when the scope
110             of \c registerPacketType ends.
111          */
112         template <class PacketType>
113         struct ScopedRegistrationProxy
114         {
115             ScopedRegistrationProxy(typename Tag::key_t key, int priority=0);
116             ~ScopedRegistrationProxy();
117         };
118
119         /** \brief Register new packet type
120
121             Register \a PacketType in the packet registry \a Tag under the given \a key.
122
123             \par Preconditions:
124                 The given pair \a key, \a priority must be unique and not be assigned to any other
125                 packet class in this registry.  The %Packet must not already be registered in the
126                 registry.
127
128             \tparam PacketType ConcretePacket instantiation of packet to register
129             \param[in] key The key of the packet
130             \param [in] priority Optional priority
131          */
132         template <class PacketType>
133         static void registerPacket(typename Tag::key_t key, int priority=0);
134
135         /** \brief Unregister packet by packet type
136
137             Removes \a PacketType from the packet registry. If the packet type is not registered,
138             this is a no-op.
139
140             \tparam PacketType ConcretePacket instantiation of packet to remove from registry
141          */
142         template <class PacketType>
143         static void unregisterPacket();
144
145         /** \brief Unregister packet by key
146
147             Removes the packet registration for \a key (and \a priority) from the registry. If no
148             packet is registered with the given pair \a key, \a priority, this operation is a
149             no-op.
150
151             \param[in] key Key to remove from the registry
152             \param[in] priority Optional priority of the key to remove
153          */
154         static void unregisterPacket(typename Tag::key_t key, int priority=0);
155
156         /** \brief Find key of a packet type
157
158             Return the key of \a PacketType as registered in the \a Tag registry
159
160             \tparam PacketType packet of which the key is requested
161             \returns key of the packet
162             \throws PacketTypeNotRegistered if the packet type is not found in the registry.
163          */
164         template <class PacketType>
165         static typename Tag::key_t key();
166
167         /** \brief Find key of a packet type
168
169             Return the key of \a PacketType as registered in the \a Tag registry
170
171             \tparam PacketType 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         template <class PacketType>
177         static typename boost::optional<typename Tag::key_t> key(NoThrow_t);
178
179         /** \brief Find key of a packet
180
181             Return the key of \a packet, an arbitrary packet, as registered in the \a Tag registry.
182
183             \param packet The packet of which the key is requested
184             \returns key of the packet
185             \throws PacketTypeNotRegistered if the packet type is not found in the registry.
186          */
187         static typename Tag::key_t key(Packet const & packet);
188
189         /** \brief Find key of a packet
190
191             Return the key of \a packet, an arbitrary packet, as registered in the \a Tag registry.
192
193             \param packet The packet of which the key is requested
194             \returns key of the packet wrapped in a <a
195                 href="http://www.boost.org/libs/optional/doc/optional.html">boost::optional</a> or
196                 an unbound optional, if the key is not found.
197          */
198         static typename boost::optional<typename Tag::key_t> key(Packet const & packet, NoThrow_t);
199
200         /** \brief Lookup a packet by it's key
201
202             \throws PacketTypeNotRegistered if the \a key is not found in the registry
203             \return %Packet entry for given \a key
204          */
205         static Entry const & lookup(typename Tag::key_t key);
206
207         /** \brief Lookup a packet by it's key
208             \return Pointer to packet entry for given \a key or 0, if the key is not found in the
209                 registry.
210          */
211         static Entry const * lookup(typename Tag::key_t key, NoThrow_t);
212
213         /** \brief Beginning iterator to list of registered entries
214          */
215         static iterator begin();
216
217         /** \brief End iterator to list of registered entries
218          */
219         static iterator end();
220
221     private:
222         typedef detail::PacketRegistryImpl<typename Tag::key_t> Registry;
223         static Registry & registry();
224     };
225
226     /** \brief Statically add an entry to a packet registry
227
228         This macro will declare an anonymous global variable in such a way, that constructing this
229         variable will add a registration to the given packet registry.
230
231         \ingroup packet_module
232         \hideinitializer
233      */
234 #   define SENF_PACKET_REGISTRY_REGISTER( registry, value, type )       \
235         namespace {                                                     \
236             senf::PacketRegistry< registry >::ScopedRegistrationProxy< type > \
237             BOOST_PP_CAT(packetRegistration_, __LINE__) ( value );      \
238         }
239
240     /** \brief Statically add an entry to a packet registry with explicit priority
241
242         This macro will declare an anonymous global variable in such a way, that constructing this
243         variable will add a registration to the given packet registry.
244
245         \ingroup packet_module
246         \hideinitializer
247      */
248 #   define SENF_PACKET_REGISTRY_REGISTER_PRIORITY( registry, value, priority, type ) \
249         namespace {                                                     \
250             senf::PacketRegistry< registry >::ScopedRegistrationProxy< type > \
251             BOOST_PP_CAT(packetRegistration_, __LINE__) ( value, priority ); \
252         }
253
254     /** \brief Dump all packet registries
255
256         This command will dump all packet registries to the given stream. This is to help debugging
257         registration problems.
258      */
259     void dumpPacketRegistries(std::ostream & os);
260
261     /** \brief Entry not found in registry
262
263         This exception is signaled whenever a throwing lookup operation fails.
264      */
265     struct PacketTypeNotRegisteredException : public senf::Exception
266     { PacketTypeNotRegisteredException() : senf::Exception("packet type not registered") {} };
267
268 }
269
270 ///////////////////////////////hh.e////////////////////////////////////////
271 #endif
272 #if !defined(HH_SENF_Packets_Packets__decls_) && !defined(HH_SENF_Packets_PacketRegistry_i_)
273 #define HH_SENF_Packets_PacketRegistry_i_
274 #include "PacketRegistry.cci"
275 #include "PacketRegistry.ct"
276 #include "PacketRegistry.cti"
277 #endif
278
279 \f
280 // Local Variables:
281 // mode: c++
282 // fill-column: 100
283 // c-file-style: "senf"
284 // indent-tabs-mode: nil
285 // ispell-local-dictionary: "american"
286 // compile-command: "scons -u test"
287 // comment-column: 40
288 // End: