Packets: Add PacketRegistry::begin()/end() and senf::dumpPacketRegistries() utility
[senf.git] / 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_PacketRegistryImpl_
27 #define HH_PacketRegistryImpl_ 1
28
29 // Custom includes
30 #include <map>
31 #include <boost/utility.hpp> // for boost::noncopyable
32 #include <boost/optional.hpp>
33 #include "../Utils/Exception.hh"
34 #include "Packet.hh"
35
36 #include "PacketRegistry.ih"
37 //#include "PacketRegistry.mpp"
38 ///////////////////////////////hh.p////////////////////////////////////////
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::PacketRegistry<SomeTag>::RegistrationProxy<SomePacket>
71             registerSomePacket (key_of_somePacket);
72         \endcode
73
74         This global variable declaration will register \a SomePacket with the \a SomeTag registry
75         under the key \a key_of_somePacket. The variable \a registerSomePacket is a dummy. It's only
76         function is to force the call of it's constructor during global construction time. This
77         static registration only works when the symbol is included into the final binary. To force
78         this inclusion, you should not put packet registrations into a library but into an object
79         file.
80         
81         \ingroup packet_module
82      */
83     template <class Tag>
84     class PacketRegistry
85     {
86     public:
87         typedef typename detail::PacketRegistryImpl<typename Tag::key_t>::iterator iterator;
88
89         /** \brief Statically register a packet type in a PacketRegistry
90
91             To use this class, define a global symbol in the following way:
92             \code
93             namespace {
94                 senf::PacketRegistry<Tag>::RegistrationProxy<PacketType>
95                     registerPacketType (key);
96             }
97             \endcode Here  \a Tag  is the type  tag of the  registry to  register the packet  in, \a
98             PacketType is the packet to register (this  is the ConcretePacket of that packet) and \a
99             key is  the key of  type \c Tag::key_t  under which the packet  is to be  registered. \a
100             registerPacketType is an arbitrary name for the global symbol.
101          */
102         template <class PacketType>
103         struct RegistrationProxy
104         {
105             RegistrationProxy(typename Tag::key_t key);
106         };
107
108         /** \brief Register new packet type
109
110             Register \a PacketType in the packet registry \a Tag under the given \a key.
111
112             \par Preconditions: The given \a key must be unique and not be assigned to any other
113                 packet class in this registry.  The Packet must not already be registered in the
114                 registry.
115
116             \param PacketType ConcretePacket instantiation of packet to register
117             \param key The key of the packet
118          */
119         template <class PacketType>
120         static void registerPacket(typename Tag::key_t key);
121
122         /** \brief Find key of a packet type
123
124             Return the key of \a PacketType as registered in the \a Tag registry
125
126             \param PacketType packet of which the key is requested
127             \returns key of the packet
128             \throws PacketTypeNotRegistered if the packet type is not found in the registry.
129          */
130         template <class PacketType>
131         static typename Tag::key_t key();
132
133         /** \brief Find key of a packet type
134
135             Return the key of \a PacketType as registered in the \a Tag registry
136
137             \param PacketType packet of which the key is requested
138             \returns key of the packet wrapped in a <a
139                 href="http://www.boost.org/libs/optional/doc/optional.html">boost::optional</a> or
140                 an unbound optional, if the key is not found.
141          */
142         template <class PacketType>
143         static typename boost::optional<typename Tag::key_t> key(NoThrow_t);
144
145         /** \brief Find key of a packet
146
147             Return the key of \a packet, an arbitrary packet, as registered in the \a Tag registry.
148
149             \param packet The packet of which the key is requested
150             \returns key of the packet
151             \throws PacketTypeNotRegistered if the packet type is not found in the registry.
152          */        
153         static typename Tag::key_t key(Packet packet);
154
155         /** \brief Find key of a packet
156
157             Return the key of \a packet, an arbitrary packet, as registered in the \a Tag registry.
158
159             \param packet The 
160 packet of which the key is requested
161             \returns key of the packet wrapped in a <a
162                 href="http://www.boost.org/libs/optional/doc/optional.html">boost::optional</a> or
163                 an unbound optional, if the key is not found.
164          */
165         static typename boost::optional<typename Tag::key_t> key(Packet packet, NoThrow_t);
166
167         /** \brief Lookup a packet by it's key
168             
169             \throws PacketTypeNotRegistered if the \a key is not found in the registry
170             \return Packet entry for given \a key
171          */
172         static PkReg_Entry const & lookup(typename Tag::key_t key);
173
174         /** \brief Lookup a packet by it's key
175             \return Pointer to packet entry for given \a key or 0, if the key is not found in the
176                 registry.
177          */
178         static PkReg_Entry const * lookup(typename Tag::key_t key, NoThrow_t);
179
180         /** \brief Beginning iterator to list of registered keys
181          */
182         static iterator begin();
183
184         /** \brief End iterator to list of registered keys
185          */
186         static iterator end();
187
188     private:
189         typedef detail::PacketRegistryImpl<typename Tag::key_t> Registry;
190         static Registry & registry();
191     };
192
193     /** \brief Statically add an entry to a packet registry
194
195         This macro will declare an anonymous global variable in such a way, that constructing this
196         variable will add a registration to the given packet registry.
197
198         \hideinitializer
199      */
200 #   define SENF_PACKET_REGISTRY_REGISTER( registry, value, type )                                 \
201         namespace {                                                                               \
202             senf::PacketRegistry< registry >::RegistrationProxy< type >                           \
203                 packetRegistration_ ## __LINE__ ( value );                                        \
204         }
205
206     /** \brief Dump all packet registries
207
208         This command will dump all packet registries to the given stream. This is to help debugging
209         registration problems.
210      */
211     void dumpPacketRegistries(std::ostream & os);
212
213     /** \brief Entry not found in registry
214
215         This exception is signaled whenever a throwing lookup operation fails.
216      */
217     struct PacketTypeNotRegisteredException : public std::exception
218     { virtual char const * what() const throw() { return "packet type not registered"; } };
219
220 }
221
222 ///////////////////////////////hh.e////////////////////////////////////////
223 #endif
224 #if !defined(HH_Packets__decls_) && !defined(HH_PacketRegistryImpl_i_)
225 #define HH_PacketRegistryImpl_i_
226 #include "PacketRegistry.cci"
227 #include "PacketRegistry.ct"
228 #include "PacketRegistry.cti"
229 #endif
230
231 \f
232 // Local Variables:
233 // mode: c++
234 // fill-column: 100
235 // c-file-style: "senf"
236 // indent-tabs-mode: nil
237 // ispell-local-dictionary: "american"
238 // compile-command: "scons -u test"
239 // comment-column: 40
240 // End:
241