Really fix termination status for boost unit tests
[senf.git] / Packets / ParserBase.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 /** \file
24     \brief Parser framework
25  */
26
27 #ifndef HH_ParserBase_
28 #define HH_ParserBase_ 1
29
30 // Custom includes
31 #include <utility>
32 #include <boost/type_traits/is_member_function_pointer.hpp>
33
34 #include "ParserBase.ih"
35 ///////////////////////////////hh.p////////////////////////////////////////
36
37 namespace satcom {
38 namespace pkf {
39     
40     namespace impl { struct ParserBase; }
41
42     struct nil {};
43
44     /** \brief Parser framework
45
46         This class is the baseclass for all parser classes of the
47         parser framework. The parser framework is used to interpret
48         byte-oriented data from arbitrary random access iterators. The
49         framework is hierarchical in the sense, that parsers can be
50         arbitrarily nested.
51
52         All parser framework classes are as lightweight as
53         possible. Most parser classes only have a single iterator as
54         data member and (depending on the container) therefore have
55         the same size as a single pointer. Parsers are therefore
56         conceptually and in essence simply pointers decorated with
57         type information.
58
59         It is very important for parser classes to be lightweight and
60         to have only simple constructors since parsers are passed
61         around by value. Parser instances most of the time are
62         temporaries. However, since they are only 'decorated'
63         pointers, this should not have any performance impact.
64
65         To implement a new parser, write a template implementing the
66         following members:
67         
68         \code
69             template <class Iterator=nil, class IPacket=nil>
70             struct Parser_Example
71                 : protected satcom::pkf::ParserBase<Iterator,IPacket>
72             {
73                 // fixed interface of all parser classes
74
75                 template <class I=nil, class P=nil>
76                 struct rebind { typedef Parse_Example<I,P> parser; }
77                 typedef Iterator byte_iterator;
78
79                 Parse_Example() {}
80                 Parse_Example(Iterator const & i) : ParserBase<Iterator,IPacket>(i) {}
81         
82                 [static] unsigned bytes()
83                 {
84                     // return the size of the parsed header. This
85                     // method must be declared static if the size is
86                     // constant, otherwise it must be a non-static
87                     // member
88                     return 14;
89                 }
90
91                 static bool check(Iterator const & begin, Iterator const & end)
92                 {
93                     BOOST_ASSERT( end>=begin );
94                     // return true, if the data in the range [begin,end)
95                     // can be safely interpreted by the parser without
96                     // causing invalid memory access. This means,
97                     // check, wether the data is truncated
98                     return static_cast<unsigned>(end-begin) >= bytes();
99                 }
100
101                 // optional, only needed if bytes() is non-static
102                 static unsigned min_bytes()
103                 {
104                     // return the minimum size of the header. This
105                     // is the amount of space needed to allocate
106                     // an otherwise empty packet
107                     return 10;
108                 }
109
110                 // optional
111                 void init()
112                 {
113                     // initialize the packet if necessary
114                 }
115
116                 // optional
117                 void init(Iterator b, Iterator e)
118                 {
119                     // initialize the packet with given payload
120                 }
121
122                 // example methods to parse fields
123
124                 typedef Parse_UInt16 < Iterator >                    Parse_Field1;
125                 typedef Parse_Array  < 3, Parse_UInt32<>, Iterator > Parser_Field2
126
127                 Parse_Field1 field1() const { return Parse_Field1 (this->i()); }
128                 Parse_Field2 field2() const { return Parse_Field2 (this->i()+2); }
129             };
130         \endcode
131         
132         Every parser must have some mandatory fixed members which are:
133         
134         - struct rebind: This structure allows the parser to be
135           converted to a parser of the same type but with a different
136           iterator. Parser may have more than the two standard
137           template parameters. These parameters must then be added in
138           front of the standard parameters. The rebind structure must
139           however always have only two parameters. Additional
140           parameters must be provided from the outside template
141
142         - byte_iterator: A typedef for the Iterator class used
143         
144         - Non Iterator constructor: This constructor is only used when
145           the parser is inherited into a Packet class.
146         
147         - Iterator constructor: This constructor must call the
148           corresponding ParserBase constructor.
149
150         - unsigned bytes() member: This member must return the number
151           of bytes the parser interprets. This will be the size of the
152           implemented header. If the header has a fixed size, this
153           member must be static, if it is dynamic the member must be
154           non-static
155
156         - static bool check(Iterator b, Iterator e) member: This
157           method must return true \e only if the range [b,e) contains
158           a \e complete packet, that is, e-b >= bytes(). However, the
159           call to bytes() might involve accessing data bytes which
160           might not exist. The bytes() call cannot check this (it has
161           no access to the \e end of the valid range). To keep the
162           performance up, the validity check is performed once. The
163           parser has to ensure, that validity is maintained even when
164           changing the values. Validity in this context does not
165           imply, that the packet is semantically correct, it only
166           implies, that the packet can be parsed without risking
167           invalid memory access.
168
169         - The min_bytes() member is optional. It is only used, if the
170           Parser implements a non-fixed-size Packet, that is, if the
171           bytes() member is non-static. In this case, min_bytes() has
172           to be implemented and must return the amount of space
173           necessary to construct an empty instance. The construction
174           will proceed by first allocating the necessary space
175           somewhere, initializing this space with all zeros. Then a
176           Parser instance is created at that space and the Parsers
177           init() method is called.
178
179         - The init() member is optional. If all-zero initialization of
180           a new Packet is enough, this member can be
181           skipped. Otherwise, the init() member can assume to have
182           access to a min_buytes() sized area which is all-zero
183           initialized.
184
185         - The init(Packet::ptr payload) member is optional. By default
186           it just calls the init() member. Here, special
187           initialization regarding the payload may be done. As for
188           min_bytes(Packet::ptr), the argument type is allowed to be
189           templatized or may be a specific packet ptr thereby
190           restricting the permissible payload packet types.
191
192         - The parser then contains any additional methods to parse the
193           header constituents.
194
195         ParserBase provides the parser classes with access to the
196         packet iterator. This class is templatized on the Iterator
197         type and an optional baseclass type.
198
199         If the baseclass is given, it is used to access the iterator
200         directly using 'begin'. If it is not given, the instance has
201         to be constructed with an iterator.
202
203         This implementation ensures, that a parser can either be
204         inherited into a Packet class or be used as a temporary.
205       */
206     template <class Iterator, class IPacket=nil>
207     class ParserBase : public impl::ParserBase
208     {
209     public:
210         ///////////////////////////////////////////////////////////////////////////
211         ///\name Structors and default members
212         ///@{
213         
214         // default default constructor
215         // default copy constructor
216         // default copy assignment
217         // default destructor
218         // no conversion constructors
219
220         ///@}
221         ///////////////////////////////////////////////////////////////////////////
222
223         Iterator i() const;
224         static void init() {};
225
226     private:
227         
228     };
229
230     template <class Iterator>
231     class ParserBase<Iterator,nil> : public impl::ParserBase
232     {
233     public:
234         ///////////////////////////////////////////////////////////////////////////
235         ///\name Structors and default members
236         ///@{
237
238         explicit ParserBase(Iterator const & i);
239
240         // no default constructor
241         // default copy constructor
242         // default copy assignment
243         // default destructor
244         // no conversion constructors
245
246         ///@}
247         ///////////////////////////////////////////////////////////////////////////
248
249         Iterator i() const;
250         static void init() {}
251         template <class SomePacket>
252         static void init(typename SomePacket::ptr) {}
253         
254     private:
255
256         Iterator i_;
257     };
258
259     /** \brief Addtiional Parser information
260         
261         Parser_traits provids abstract information about an unknown
262         parser. Besides the information already available within the
263         Parser it provides an additional 'fixed_sized' member which is
264         true if and only if the Parser has a static bytes() member.
265      */
266     template <class Parser>
267     struct Parser_traits {
268         typedef Parser parser;
269         typedef typename Parser::byte_iterator byte_iterator;
270         static const bool fixed_size = impl::Parser_traits_fixed_size<Parser>::fixed_size;
271
272         template <class I=nil, class P=nil>
273         struct rebind {
274             typedef typename Parser::template rebind<I,P>::parser parser;
275         };
276     };
277
278     template <class Parser, class Iterator>
279     bool check(Iterator const & b, Iterator const & e);
280
281     template <class Parser>
282     unsigned min_bytes();
283     
284 }}
285
286 ///////////////////////////////hh.e////////////////////////////////////////
287 //#include "ParserBase.cci"
288 //#include "ParserBase.ct"
289 #include "ParserBase.cti"
290 #endif
291
292 \f
293 // Local Variables:
294 // mode: c++
295 // c-file-style: "satcom"
296 // End: