Add new file-variable 'comment-column'
[senf.git] / Packets / PacketRegistry.hh
1 // $Id$
2 //
3 // Copyright (C) 2006
4 // Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
5 // Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
6 //     Stefan Bund <stefan.bund@fokus.fraunhofer.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
24 #ifndef HH_PacketRegistryImpl_
25 #define HH_PacketRegistryImpl_ 1
26
27 // Custom includes
28 #include <map>
29 #include <boost/utility.hpp> // for boost::noncopyable
30 #include <boost/shared_ptr.hpp>
31 #include "Packet.hh"
32
33 //#include "PacketRegistry.mpp"
34 ///////////////////////////////hh.p////////////////////////////////////////
35
36 namespace senf {
37
38
39     namespace impl { template <class key> class PacketRegistryImpl; }
40
41     /** \brief Packet registration facility
42
43         The PacketRegistry provides a generic facility to associate an
44         arbitrary key with Packets. Example keys are Ethertype or IP
45         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
54         for this Tag can then be accessed using
55         <code>PacketRegistry<SomeTag>::</code>.
56
57         The PacketRegistry class has only static members and provides
58         access to the packet registry. It allows to register Packet
59         classes and to create new Packets given a key. Methods are
60         also provided to find the key of a Packet type.
61
62         \code
63             PacketRegistry<SomeTag>::registerPacket<SomePacket>(key_of_somePacket);
64             p = PacketRegistry<SomeTag>::create(some_key,begin,end);
65             SomeTag::key_t key = PacketRegistry<SomeTag>::key<SomePacket>();
66         \endcode
67
68         Normally, packet classes are registered statically and not
69         procedurally. To this end, the RegistrationProxy is provided:
70         \code
71           PacketRegistry<SomeTag>::RegistrationProxy<SomePacket>
72               registerSomePacket (key_of_somePacket);
73         \endcode
74         This global variable declaration will register \c SomePacket
75         with the \c SomeTag registry under the key \c
76         key_of_somePacket. The variable \c registerSomePacket is a
77         dummy. It's only function is to force the call of it's
78         constructor during global construction time.
79
80         The PacketRegistry's purpose is mostly to assist in
81         implementing the v_nextInterpreter() member of packet
82         facades. This is further supported by the PacketRegistryMixin
83         class.
84
85         \todo Add parameterless create() method
86      */
87     template <class Tag>
88     class PacketRegistry
89     {
90     public:
91         /** \brief Statically register a packet type in a PacketRegistry
92          */
93         template <class OtherPacket>
94         struct RegistrationProxy
95         {
96             RegistrationProxy(typename Tag::key_t key);
97         };
98
99         /** \brief Register new packet type
100
101             Register \c OtherPacket in the packet registry \c Tag
102             under the given \c key.
103
104             \par Preconditions:
105                 The given \c key must be unique and not be assigned to
106                 any other packet class in this registry.
107                 The Packet must not already be registered in the registry.
108
109             \param OtherPacket packet to register
110             \param key key of the packet
111          */
112         template <class OtherPacket>
113         static void registerPacket(typename Tag::key_t key);
114
115         /** \brief Find key of a packet
116
117             Return the key of \c OtherPacket as registered in the \c
118             Tag registry
119
120             \param OtherPacket packet of which the key is requested
121             \returns key of the packet
122             \throws PacketTypeNotRegistered if the packet type is not
123                 found in the registry.
124          */
125         template <class OtherPacket>
126         static typename Tag::key_t key();
127
128         /** \brief Create new Packet
129
130             \param key Key of packet type to create instance of
131             \param b begin iterator argument to Packet::create()
132             \param e end iterator argument to Packet::create()
133             \returns new Instance of the packet type registered under
134                 key or DataPacket, if the key is not registered.
135          */
136         template <class InputIterator>
137         static Packet::ptr create(typename Tag::key_t key, InputIterator b, InputIterator e);
138
139     private:
140         typedef impl::PacketRegistryImpl<typename Tag::key_t> Registry;
141         static Registry & registry();
142
143         template <class T, class D> friend class PacketRegistryMixin;
144     };
145
146     /** \brief Helper class for v_nextInterpreter implementations
147
148         This class is a helper class which is to be inherited from in
149         a packet facade which wants to register a new interpreter with
150         the packet framework depending on a packet registry.
151
152         This mixin class provides a new registerInterpreter
153         implementation which can be used besides the methods provided
154         by senf::Packet to add a new interpreter to the
155         interpreter chain.
156
157         \code
158           class SomePacket
159               : public Packet,
160                 private PacketRegistryMixin<SomeTag,SomePacket>
161           {
162               using Packet::retgisterInterpreter;
163               using PacketRegistryMixin<SomeTag,SomePacket>::registerInterpreter;
164
165               virtual void v_nextInterpreter()
166               {
167                   registerInterpreter(some_key_value, subpacket_begin, subpacket_end);
168               }
169           };
170         \endcode
171         This example is not complete, it only contains the parts
172         concerned with PacketRegistryMixin.
173      */
174     template <class Tag, class Derived>
175     class PacketRegistryMixin
176     {
177     protected:
178         /** \brief add interpreter to interpreter chain
179
180             This method is used by v_nextInterpreter() to add a new
181             interpreter to the interpreter chain (see the Packet
182             reference for more). Instead of specifying the type of
183             packet to use as a template argument it is specified using
184             the \c key value from the \c Tag registry
185          */
186         void registerInterpreter(typename Tag::key_t key,
187                                  Packet::iterator b, Packet::iterator e) const;
188     };
189
190     struct PacketTypeNotRegistered : public std::exception
191     { virtual char const * what() const throw() { return "packet type not registered"; } };
192
193 }
194
195 ///////////////////////////////hh.e////////////////////////////////////////
196 //#include "PacketRegistry.cci"
197 #include "PacketRegistry.ct"
198 #include "PacketRegistry.cti"
199 #endif
200
201 \f
202 // Local Variables:
203 // mode: c++
204 // fill-column: 100
205 // c-file-style: "senf"
206 // indent-tabs-mode: nil
207 // ispell-local-dictionary: "american"
208 // compile-command: "scons -u test"
209 // comment-column: 40
210 // End: