2ae1fa3ceb91113d70876b4ef287a878aa8348d3
[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.mpp"
37 ///////////////////////////////hh.p////////////////////////////////////////
38
39 namespace senf {
40
41     /** \brief Registry entry
42
43         Value returned by a registry lookup
44      */
45     struct PkReg_Entry 
46         : public intrusive_refcount
47     {
48         virtual ~PkReg_Entry();
49         virtual Packet::factory_t factory() const = 0;
50                                         ///< Get factory of the registered packet type
51         virtual std::string name() const = 0;
52     };
53
54     namespace detail { template <class Key> class PacketRegistryImpl; }
55
56     /** \brief Packet registration facility
57
58         The PacketRegistry provides a generic facility to associate an arbitrary key with
59         Packets. Example keys are Ethertype or IP protocols.
60
61         Every PacketRegistry is identified by a type tag:
62         \code
63         struct SomeTag {
64             typedef some_key_type key_t;
65         };
66         \endcode
67         The key type can be an arbitrary value type. The PacketRegistry for this Tag can then be
68         accessed using <code>senf::PacketRegistry<SomeTag>::</code>.
69
70         The PacketRegistry class has only static members and provides access to the packet
71         registry. It allows two-way lookup either by key or by packet type. 
72
73         \code
74         senf::Packet::factory_t factory (senf::PacketRegistry<SomeTag>::lookup(some_key).factory());
75         SomeTag::key_t key = PacketRegistry<SomeTag>::key<SomePacket>();
76         \endcode
77
78         Packets can be registered either dynamically or statically. Dynamic:
79         \code
80         // dynamic registration
81         senf::PacketRegistry<SomeTag>::registerPacket<SomePacket>(key_of_somePacket);
82
83         // static registration. 'registerSomePacket' is an arbitrary symbol name
84         senf::PacketRegistry<SomeTag>::RegistrationProxy<SomePacket>
85             registerSomePacket (key_of_somePacket);
86         \endcode
87
88         This global variable declaration will register \a SomePacket with the \a SomeTag registry
89         under the key \a key_of_somePacket. The variable \a registerSomePacket is a dummy. It's only
90         function is to force the call of it's constructor during global construction time. This
91         static registration only works when the symbol is included into the final binary. To force
92         this inclusion, you should not put packet registrations into a library but into an object
93         file.
94         
95         \ingroup packet_module
96      */
97     template <class Tag>
98     class PacketRegistry
99     {
100     public:
101         /** \brief Statically register a packet type in a PacketRegistry
102
103             To use this class, define a global symbol in the following way:
104             \code
105             namespace {
106                 senf::PacketRegistry<Tag>::RegistrationProxy<PacketType>
107                     registerPacketType (key);
108             }
109             \endcode 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         template <class PacketType>
115         struct RegistrationProxy
116         {
117             RegistrationProxy(typename Tag::key_t key);
118         };
119
120         /** \brief Register new packet type
121
122             Register \a PacketType in the packet registry \a Tag under the given \a key.
123
124             \par Preconditions: The given \a key 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             \param PacketType ConcretePacket instantiation of packet to register
129             \param key The key of the packet
130          */
131         template <class PacketType>
132         static void registerPacket(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
140             \throws PacketTypeNotRegistered if the packet type is not found in the registry.
141          */
142         template <class PacketType>
143         static typename Tag::key_t key();
144
145         /** \brief Find key of a packet type
146
147             Return the key of \a PacketType as registered in the \a Tag registry
148
149             \param PacketType packet of which the key is requested
150             \returns key of the packet wrapped in a <a
151                 href="http://www.boost.org/libs/optional/doc/optional.html">boost::optional</a> or
152                 an unbound optional, if the key is not found.
153          */
154         template <class PacketType>
155         static typename boost::optional<typename Tag::key_t> key(NoThrow_t);
156
157         /** \brief Find key of a packet
158
159             Return the key of \a packet, an arbitrary packet, as registered in the \a Tag registry.
160
161             \param packet The packet of which the key is requested
162             \returns key of the packet
163             \throws PacketTypeNotRegistered if the packet type is not found in the registry.
164          */        
165         static typename Tag::key_t key(Packet packet);
166
167         /** \brief Find key of a packet
168
169             Return the key of \a packet, an arbitrary packet, as registered in the \a Tag registry.
170
171             \param packet The 
172 packet of which the key is requested
173             \returns key of the packet wrapped in a <a
174                 href="http://www.boost.org/libs/optional/doc/optional.html">boost::optional</a> or
175                 an unbound optional, if the key is not found.
176          */
177         static typename boost::optional<typename Tag::key_t> key(Packet packet, NoThrow_t);
178
179         /** \brief Lookup a packet by it's key
180             
181             \throws PacketTypeNotRegistered if the \a key is not found in the registry
182             \return Packet entry for given \a key
183          */
184         static PkReg_Entry const & lookup(typename Tag::key_t key);
185
186         /** \brief Lookup a packet by it's key
187             \return Pointer to packet entry for given \a key or 0, if the key is not found in the
188                 registry.
189          */
190         static PkReg_Entry const * lookup(typename Tag::key_t key, NoThrow_t);
191
192     private:
193         typedef detail::PacketRegistryImpl<typename Tag::key_t> Registry;
194         static Registry & registry();
195     };
196
197     /** \brief Statically add an entry to a packet registry
198
199         This macro will declare an anonymous global variable in such a way, that constructing this
200         variable will add a registration to the given packet registry.
201
202         \hideinitializer
203      */
204 #   define SENF_PACKET_REGISTRY_REGISTER( registry, value, type )                                       \
205         namespace {                                                                                     \
206             senf::PacketRegistry< registry >::RegistrationProxy< type >                                 \
207                 packetRegistration_ ## __LINE__ ( value );                                              \
208         }
209
210     /** \brief Entry not found in registry
211
212         This exception is signaled whenever a throwing lookup operation fails.
213      */
214     struct PacketTypeNotRegisteredException : public std::exception
215     { virtual char const * what() const throw() { return "packet type not registered"; } };
216
217 }
218
219 ///////////////////////////////hh.e////////////////////////////////////////
220 #endif
221 #if !defined(HH_Packets__decls_) && !defined(HH_PacketRegistryImpl_i_)
222 #define HH_PacketRegistryImpl_i_
223 //#include "PacketRegistry.cci"
224 #include "PacketRegistry.ct"
225 #include "PacketRegistry.cti"
226 #endif
227
228 \f
229 // Local Variables:
230 // mode: c++
231 // fill-column: 100
232 // c-file-style: "senf"
233 // indent-tabs-mode: nil
234 // ispell-local-dictionary: "american"
235 // compile-command: "scons -u test"
236 // comment-column: 40
237 // End:
238