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