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