f69d4f9c61c14456a718ab4c88d66f4dab92593f
[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 <boost/optional.hpp>
31 #include <boost/preprocessor/cat.hpp>
32 #include <senf/Utils/Exception.hh>
33 #include <senf/Utils/singleton.hh>
34 #include "Packet.hh"
35
36 #include "PacketRegistry.ih"
37 //#include "PacketRegistry.mpp"
38 //-/////////////////////////////////////////////////////////////////////////////////////////////////
39
40 namespace senf {
41
42     /** \brief %Packet registration facility
43
44         The %PacketRegistry provides a generic facility to associate an arbitrary key with
45         Packets. Example keys are Ethertype or IP protocols.
46
47         Every %PacketRegistry is identified by a type tag:
48         \code
49         struct SomeTag {
50             typedef some_key_type key_t;
51         };
52         \endcode
53         The key type can be an arbitrary value type. The %PacketRegistry for this Tag can then be
54         accessed using <code>senf::PacketRegistry<SomeTag>::</code>.
55
56         The %PacketRegistry class has only static members and provides access to the packet
57         registry. It allows two-way lookup either by key or by packet type.
58
59         \code
60         senf::Packet::factory_t factory (senf::PacketRegistry<SomeTag>::lookup(some_key).factory());
61         SomeTag::key_t key = PacketRegistry<SomeTag>::key<SomePacket>();
62         \endcode
63
64         Packets can be registered either dynamically or statically. Dynamic:
65         \code
66         // dynamic registration
67         senf::PacketRegistry<SomeTag>::registerPacket<SomePacket>(key_of_somePacket);
68
69         // static registration. 'registerSomePacket' is an arbitrary symbol name
70         SENF_PACKET_REGISTRY_REGISTER( SomeTag, key_of_somePacket, SomePacket );
71         \endcode
72
73         SENF_PACKET_REGISTRY_REGISTER will declare an anonymous global variable which will ensure,
74         the packet is registered automatically during global initialization (as long as the object
75         file is linked into the final executable).
76
77         \section packet_registry_priority Multiple registration for a single key
78
79         Ordinarily, the PacketRegistry will reject registering the same key twice. However, the
80         registry supports an additional priority parameter when registering a packet. You may
81         register multiple Packets with the same \a key as long as the \a priority is unique. The
82         registration with the highest \a priority value will take precedence on key lookup.
83
84         \ingroup packet_module
85      */
86     template <class Tag>
87     class PacketRegistry
88         : private senf::singleton< PacketRegistry<Tag> >
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/doc/libs/release/libs/optional/index.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/doc/libs/release/libs/optional/index.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         using singleton<PacketRegistry>::instance;
223         using singleton<PacketRegistry>::alive;
224
225         PacketRegistry();
226
227         typedef detail::PacketRegistryImpl<typename Tag::key_t> Registry;
228         static Registry & registry();
229         Registry registry_;
230
231         friend class senf::singleton< PacketRegistry >;
232     };
233
234     /** \brief Statically add an entry to a packet registry
235
236         This macro will declare an anonymous global variable in such a way, that constructing this
237         variable will add a registration to the given packet registry.
238
239         \ingroup packet_module
240         \hideinitializer
241      */
242 #   define SENF_PACKET_REGISTRY_REGISTER( registry, value, type )       \
243         namespace {                                                     \
244             senf::PacketRegistry< registry >::ScopedRegistrationProxy< type > \
245             BOOST_PP_CAT(packetRegistration_, __LINE__) ( value );      \
246         }
247
248     /** \brief Statically add an entry to a packet registry with explicit priority
249
250         This macro will declare an anonymous global variable in such a way, that constructing this
251         variable will add a registration to the given packet registry.
252
253         \ingroup packet_module
254         \hideinitializer
255      */
256 #   define SENF_PACKET_REGISTRY_REGISTER_PRIORITY( registry, value, priority, type ) \
257         namespace {                                                     \
258             senf::PacketRegistry< registry >::ScopedRegistrationProxy< type > \
259             BOOST_PP_CAT(packetRegistration_, __LINE__) ( value, priority ); \
260         }
261
262     /** \brief Dump all packet registries
263
264         This command will dump all packet registries to the given stream. This is to help debugging
265         registration problems.
266      */
267     void dumpPacketRegistries(std::ostream & os);
268
269     /** \brief Entry not found in registry
270
271         This exception is signaled whenever a throwing lookup operation fails.
272      */
273     struct PacketTypeNotRegisteredException : public senf::Exception
274     { PacketTypeNotRegisteredException() : senf::Exception("packet type not registered") {} };
275
276 }
277
278 //-/////////////////////////////////////////////////////////////////////////////////////////////////
279 #endif
280 #if !defined(HH_SENF_Packets_Packets__decls_) && !defined(HH_SENF_Packets_PacketRegistry_i_)
281 #define HH_SENF_Packets_PacketRegistry_i_
282 #include "PacketRegistry.cci"
283 #include "PacketRegistry.ct"
284 #include "PacketRegistry.cti"
285 #endif
286
287 \f
288 // Local Variables:
289 // mode: c++
290 // fill-column: 100
291 // c-file-style: "senf"
292 // indent-tabs-mode: nil
293 // ispell-local-dictionary: "american"
294 // compile-command: "scons -u test"
295 // comment-column: 40
296 // End: