1f748a140588e191adcbeefaf78df3360977c575
[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 <senf/Utils/singleton.hh>
36 #include "Packet.hh"
37
38 #include "PacketRegistry.ih"
39 //#include "PacketRegistry.mpp"
40 ///////////////////////////////hh.p////////////////////////////////////////
41
42 namespace senf {
43
44     /** \brief %Packet registration facility
45
46         The %PacketRegistry provides a generic facility to associate an arbitrary key with
47         Packets. Example keys are Ethertype or IP protocols.
48
49         Every %PacketRegistry is identified by a type tag:
50         \code
51         struct SomeTag {
52             typedef some_key_type key_t;
53         };
54         \endcode
55         The key type can be an arbitrary value type. The %PacketRegistry for this Tag can then be
56         accessed using <code>senf::PacketRegistry<SomeTag>::</code>.
57
58         The %PacketRegistry class has only static members and provides access to the packet
59         registry. It allows two-way lookup either by key or by packet type.
60
61         \code
62         senf::Packet::factory_t factory (senf::PacketRegistry<SomeTag>::lookup(some_key).factory());
63         SomeTag::key_t key = PacketRegistry<SomeTag>::key<SomePacket>();
64         \endcode
65
66         Packets can be registered either dynamically or statically. Dynamic:
67         \code
68         // dynamic registration
69         senf::PacketRegistry<SomeTag>::registerPacket<SomePacket>(key_of_somePacket);
70
71         // static registration. 'registerSomePacket' is an arbitrary symbol name
72         SENF_PACKET_REGISTRY_REGISTER( SomeTag, key_of_somePacket, SomePacket );
73         \endcode
74
75         SENF_PACKET_REGISTRY_REGISTER will declare an anonymous global variable which will ensure,
76         the packet is registered automatically during global initialization (as long as the object
77         file is linked into the final executable).
78
79         \section packet_registry_priority Multiple registration for a single key
80
81         Ordinarily, the PacketRegistry will reject registering the same key twice. However, the
82         registry supports an additional priority parameter when registering a packet. You may
83         register multiple Packets with the same \a key as long as the \a priority is unique. The
84         registration with the highest \a priority value will take precedence on key lookup.
85
86         \ingroup packet_module
87      */
88     template <class Tag>
89     class PacketRegistry
90         : private senf::singleton< PacketRegistry<Tag> >
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             This class is normally used via SENF_PACKET_REGISTRY_REGISTER. To use this class
99             directly, define a symbol in the following way:
100             \code
101             namespace {
102                 senf::PacketRegistry<Tag>::ScopedRegistrationProxy<PacketType>
103                     registerPacketType (key, optional_priority);
104             }
105             \endcode
106             Here  \a Tag  is the type  tag of the  registry to  register the packet  in, \a
107             PacketType is the packet to register (this  is the ConcretePacket of that packet) and \a
108             key is  the key of  type \c Tag::key_t  under which the packet  is to be  registered. \a
109             registerPacketType is an arbitrary name for the global symbol.
110
111             The packet will be registered in the constructor and will be unregistered when the scope
112             of \c registerPacketType ends.
113          */
114         template <class PacketType>
115         struct ScopedRegistrationProxy
116         {
117             ScopedRegistrationProxy(typename Tag::key_t key, int priority=0);
118             ~ScopedRegistrationProxy();
119         };
120
121         /** \brief Register new packet type
122
123             Register \a PacketType in the packet registry \a Tag under the given \a key.
124
125             \par Preconditions:
126                 The given pair \a key, \a priority must be unique and not be assigned to any other
127                 packet class in this registry.  The %Packet must not already be registered in the
128                 registry.
129
130             \tparam PacketType ConcretePacket instantiation of packet to register
131             \param[in] key The key of the packet
132             \param [in] priority Optional priority
133          */
134         template <class PacketType>
135         static void registerPacket(typename Tag::key_t key, int priority=0);
136
137         /** \brief Unregister packet by packet type
138
139             Removes \a PacketType from the packet registry. If the packet type is not registered,
140             this is a no-op.
141
142             \tparam PacketType ConcretePacket instantiation of packet to remove from registry
143          */
144         template <class PacketType>
145         static void unregisterPacket();
146
147         /** \brief Unregister packet by key
148
149             Removes the packet registration for \a key (and \a priority) from the registry. If no
150             packet is registered with the given pair \a key, \a priority, this operation is a
151             no-op.
152
153             \param[in] key Key to remove from the registry
154             \param[in] priority Optional priority of the key to remove
155          */
156         static void unregisterPacket(typename Tag::key_t key, int priority=0);
157
158         /** \brief Find key of a packet type
159
160             Return the key of \a PacketType as registered in the \a Tag registry
161
162             \tparam PacketType 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         template <class PacketType>
167         static typename Tag::key_t key();
168
169         /** \brief Find key of a packet type
170
171             Return the key of \a PacketType as registered in the \a Tag registry
172
173             \tparam PacketType packet of which the key is requested
174             \returns key of the packet wrapped in a <a
175                 href="http://www.boost.org/doc/libs/release/libs/optional/index.html">boost::optional</a> or
176                 an unbound optional, if the key is not found.
177          */
178         template <class PacketType>
179         static typename boost::optional<typename Tag::key_t> key(NoThrow_t);
180
181         /** \brief Find key of a packet
182
183             Return the key of \a packet, an arbitrary packet, as registered in the \a Tag registry.
184
185             \param packet The packet of which the key is requested
186             \returns key of the packet
187             \throws PacketTypeNotRegistered if the packet type is not found in the registry.
188          */
189         static typename Tag::key_t key(Packet const & packet);
190
191         /** \brief Find key of a packet
192
193             Return the key of \a packet, an arbitrary packet, as registered in the \a Tag registry.
194
195             \param packet The packet of which the key is requested
196             \returns key of the packet wrapped in a <a
197                 href="http://www.boost.org/doc/libs/release/libs/optional/index.html">boost::optional</a> or
198                 an unbound optional, if the key is not found.
199          */
200         static typename boost::optional<typename Tag::key_t> key(Packet const & packet, NoThrow_t);
201
202         /** \brief Lookup a packet by it's key
203
204             \throws PacketTypeNotRegistered if the \a key is not found in the registry
205             \return %Packet entry for given \a key
206          */
207         static Entry const & lookup(typename Tag::key_t key);
208
209         /** \brief Lookup a packet by it's key
210             \return Pointer to packet entry for given \a key or 0, if the key is not found in the
211                 registry.
212          */
213         static Entry const * lookup(typename Tag::key_t key, NoThrow_t);
214
215         /** \brief Beginning iterator to list of registered entries
216          */
217         static iterator begin();
218
219         /** \brief End iterator to list of registered entries
220          */
221         static iterator end();
222
223     private:
224         using singleton<PacketRegistry>::instance;
225         using singleton<PacketRegistry>::alive;
226
227         PacketRegistry();
228
229         typedef detail::PacketRegistryImpl<typename Tag::key_t> Registry;
230         static Registry & registry();
231         Registry registry_;
232
233         friend class senf::singleton< PacketRegistry >;
234     };
235
236     /** \brief Statically add an entry to a packet registry
237
238         This macro will declare an anonymous global variable in such a way, that constructing this
239         variable will add a registration to the given packet registry.
240
241         \ingroup packet_module
242         \hideinitializer
243      */
244 #   define SENF_PACKET_REGISTRY_REGISTER( registry, value, type )       \
245         namespace {                                                     \
246             senf::PacketRegistry< registry >::ScopedRegistrationProxy< type > \
247             BOOST_PP_CAT(packetRegistration_, __LINE__) ( value );      \
248         }
249
250     /** \brief Statically add an entry to a packet registry with explicit priority
251
252         This macro will declare an anonymous global variable in such a way, that constructing this
253         variable will add a registration to the given packet registry.
254
255         \ingroup packet_module
256         \hideinitializer
257      */
258 #   define SENF_PACKET_REGISTRY_REGISTER_PRIORITY( registry, value, priority, type ) \
259         namespace {                                                     \
260             senf::PacketRegistry< registry >::ScopedRegistrationProxy< type > \
261             BOOST_PP_CAT(packetRegistration_, __LINE__) ( value, priority ); \
262         }
263
264     /** \brief Dump all packet registries
265
266         This command will dump all packet registries to the given stream. This is to help debugging
267         registration problems.
268      */
269     void dumpPacketRegistries(std::ostream & os);
270
271     /** \brief Entry not found in registry
272
273         This exception is signaled whenever a throwing lookup operation fails.
274      */
275     struct PacketTypeNotRegisteredException : public senf::Exception
276     { PacketTypeNotRegisteredException() : senf::Exception("packet type not registered") {} };
277
278 }
279
280 ///////////////////////////////hh.e////////////////////////////////////////
281 #endif
282 #if !defined(HH_SENF_Packets_Packets__decls_) && !defined(HH_SENF_Packets_PacketRegistry_i_)
283 #define HH_SENF_Packets_PacketRegistry_i_
284 #include "PacketRegistry.cci"
285 #include "PacketRegistry.ct"
286 #include "PacketRegistry.cti"
287 #endif
288
289 \f
290 // Local Variables:
291 // mode: c++
292 // fill-column: 100
293 // c-file-style: "senf"
294 // indent-tabs-mode: nil
295 // ispell-local-dictionary: "american"
296 // compile-command: "scons -u test"
297 // comment-column: 40
298 // End: