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