DTCP
[senf.git] / Packets / ParseVariant.hh
1 // $Id$
2 //
3 // Copyright (C) 2007 
4 // Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
5 // Kompetenzzentrum fuer NETwork research (NET)
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 ParseVariant public header */
25
26 #ifndef HH_ParseVariant_
27 #define HH_ParseVariant_ 1
28
29 #ifndef HH_Packets_
30 #error "Don't include 'ParseVariant.hh' directly, include 'Packets.hh'"
31 #endif
32
33 // Custom includes
34 #include <boost/mpl/vector.hpp>
35 #include <boost/mpl/at.hpp>
36 #include <boost/preprocessor/repetition/enum_params_with_a_default.hpp>
37 #include <boost/preprocessor/repetition/enum_params.hpp>
38 #include <boost/preprocessor/seq/for_each.hpp>
39 #include "PacketParser.hh"
40
41 //#include "ParseVariant.mpp"
42 #include "ParseVariant.ih"
43 ///////////////////////////////hh.p////////////////////////////////////////
44
45 namespace senf {
46
47 #   ifndef SENF_LIMIT_PARSE_VARIANT
48         /** \brief Maximum number of senf::Parse_Variant sub-parsers.
49
50             This number defines the maximum number of parser arguments senf::Parse_Variant takes.
51          */
52 #       define SENF_LIMIT_PARSE_VARIANT 6
53 #   endif
54
55     /** \brief Variant parser
56
57         This is not really a collection parser (it does not provide a collection
58         interface). However, it is not a composite parser or value parser either.
59
60         A variant parser will parse any number of sub-parsers discriminated by an arbitrary, policy
61         defined condition. This is the parser to use, if the type and/or number of fields of a
62         packet change depending on some condition.
63         \code
64         typedef senf::Parse_Variant< 
65             MyVariantPolicy, 
66             senf::VoidPacketParser, Parse_TypeA, Parse_TypeB> MyVariant;
67         \endcode
68         This typedef defines a variant parser choosing one of three sub
69         parsers. senf::VoidPacketParser is an empty parser, it effectively makes this parser
70         optional.
71
72         When creating a new packet containing a variant parser, the variant parser will always be
73         initialized to the first sub-parser.
74
75         \see 
76             ExampleVariantPolicy on how to implement the \a VariantPolicy \n
77             \ref SENF_PARSER_VARIANT() on how to integrate the parser into another parser
78         \ingroup parsecollection
79      */
80     template <class VariantPolicy, SENF_PARSE_VARIANT_TPL_ARGS_DFL(class P)>
81     class Parse_Variant 
82         : public PacketParserBase, private VariantPolicy
83     {
84         typedef boost::mpl::vector< SENF_PARSE_VARIANT_TPL_ARGS(P) > parsers;
85
86     public:
87         ///\name Parser interface
88         ///\{
89
90         Parse_Variant(data_iterator i, state_type s);
91         Parse_Variant(VariantPolicy policy, data_iterator i, state_type s);
92
93         size_type bytes() const;
94         void init();
95         
96         static const size_type init_bytes = 
97             senf::init_bytes<P0>::value + VariantPolicy::init_bytes;
98
99         ///\}
100         ///////////////////////////////////////////////////////////////////////////
101
102         unsigned variant() const;       ///< Get current variant
103                                         /**< Get the currently selected variant index. The returned
104                                              number directly indexes the list of sub parsers.
105                                              \returns Index of currently selected variant. Integer
106                                                  in the range from 0 to (number-of-sub-parsers - 1)
107                                           */
108         
109         template <unsigned N>
110         typename boost::mpl::at< parsers, boost::mpl::int_<N> >::type get() const;
111                                         ///< Access sub-parser
112                                         /**< This call will return the sub-parser at index \a
113                                              N. This call will fail, if the currently active
114                                              variant() is not \a N.
115                                              \pre variant() == \a N
116                                              \returns sub-parser at index \a N */
117
118         template <unsigned N>
119         void init();                    ///< Re-initialize field
120                                         /**< This will reinitialize the field to the variant
121                                              sub-parser at index \a N changing the currently
122                                              selected variant.
123                                              \post variant() == \a N */
124     };
125
126     /** \brief Variant with direct, fixed distance type field
127         
128         This struct is a template typedef defining a senf::Parser_Variant instantiation. It defines
129         a variant parser which interprets the value returned by some other parser directly as index
130         into the list of sub parsers (the numeric template argument to senf::Parse_Variant::get()
131         and senf::Parser_Variant::init()).
132
133         \code
134             // Define a variant choosing between Parse_Foo and Parse_Bar depending on the directly
135             // preceding 1-byte 8bit uint value
136             typedef senf::Parse_Variant_Direct< senf::Parse_UInt8, 1u, 
137                                                 Parse_Foo, Parse_Bar >::parser MyVariant;
138         \endcode
139
140         \a ChooserType defines the type of the field used to choose the sub parser. This must be a
141         fixed-size value parser. \a Distance gives the \e fixed distance of this field \e before the
142         currently defined field.
143
144         It is best to define a field of this type using \ref SENF_PARSER_VARIANT() or \ref
145         SENF_PARSER_PRIVATE_VARIANT().
146
147         \param[in] ChooserType type of chooser field (a value parser)
148         \param[in] Distance    fixed distance of the chooser field before the current field
149         \param[in] P           any number of sub parsers
150
151         \see senf::Parser_Variant
152         \ingroup parsecollection
153      */
154     template <class ChooserType, unsigned Distance, class Translator,
155               SENF_PARSE_VARIANT_TPL_ARGS_DFL(class P)>
156     struct Parse_Variant_Direct
157     {
158         typedef Parse_Variant< detail::Parse_Variant_Direct<ChooserType, Distance, Translator>,
159                                SENF_PARSE_VARIANT_TPL_ARGS(P) > parser;
160     };
161
162     /** \brief Define Parse_Variant_Direct field
163
164         This macro is a special helper to define a senf::Parse_Variant_Direct type field. This is a
165         variant field which chooses the sub-type by directly taking the value of some other field.
166
167         This is a dynamically sized parser. Nevertheless, the chooser field \e must have a \e fixed
168         distance to this field, the \a chooser must be a fixed-size value parser.
169
170         \code
171         struct SomeParser : public PacketParserBase
172         {
173         #   include SENF_PARSER()
174         
175             SENF_PARSER_PRIVATE_FIELD( type, senf::Parse_UInt8 );
176             SENF_PARSER_PRIVATE_VARIANT( content, type,
177                                             (senf::VoidPacketParser)
178                                             (senf::Parse_UInt8)
179                                             (senf::Parse_UInt16)
180                                             (senf::Parse_UInt24)
181                                             (senf::Parse_UInt32) );
182
183             senf::Parse_UInt8 uint8()  const { return content().get<1>(); }
184             senf::Parse_UInt16 uint16() const { return content().get<2>(); }
185             senf::Parse_UInt24 uint24() const { return content().get<3>(); }
186             senf::Parse_UInt32 uint32() const { return content().get<4>(); }
187
188             void disable()    const { content().init<0>(); }
189             void set_uint8()  const { content().init<1>(); }
190             void set_uint16() const { content().init<2>(); }
191             void set_uint24)  const { content().init<3>(); }
192             void set_uint23() const { content().init<4>(); }
193
194             SENF_PARSER_FINALIZE(SomeParser);
195         };
196         \endcode
197
198         The variant \c content chooses one of the sub parsers depending on the \c type field. If \c
199         type is 0, senf::VoidPacketParser is selected, if it is 1, senf::Parse_UInt8 and so on. 
200
201         It is customary, to hide the variant parser (by defining it private) and provide more
202         conveniently named accessors.
203
204         \param[in] name name of the field
205         \param[in] chooser name of the field choosing the variant to use
206         \param[in] types a Boost.Preprocessor style sequence of sub-parser types
207
208         \see 
209             senf::Parse_Variant \n 
210             \ref SENF_PARSER_PRIVATE_VARIANT()
211         \hideinitializer
212         \ingroup packetparsermacros
213      */
214 #   define SENF_PARSER_VARIANT(name, chooser, types)                                              \
215         SENF_PARSER_VARIANT_I(SENF_PARSER_FIELD,                                                  \
216                               name,                                                               \
217                               chooser,                                                            \
218                               senf::detail::Parse_Variant_IdentityTranslator,                     \
219                               types)
220
221     /** \brief Define Parse_Variant_Direct field (private)
222         
223         \see \ref SENF_PARSER_VARIANT()
224         \hideinitializer
225         \ingroup packetparsermacros
226      */
227 #   define SENF_PARSER_PRIVATE_VARIANT(name, chooser, types)                                      \
228         SENF_PARSER_VARIANT_I(SENF_PARSER_PRIVATE_FIELD,                                          \
229                               name,                                                               \
230                               chooser,                                                            \
231                               senf::detail::Parse_Variant_IdentityTranslator,                     \
232                               types)
233
234     /** \brief Define Parse_Variant_Direct field with translator
235         
236         This is like \ref SENF_PARSER_VARIANT(), however it allows to specify a \a translator
237         argument which translates between \a chooser values and type indices:
238         \code
239         struct SomeTranslator {
240             static unsigned fromChooser(chooser_field_t::value_type value) {
241                 switch (value) {
242                 case 1  : return 0 ;
243                 case 5  : return 1 ;
244                 default : return 2 ;
245                 }
246             }
247
248             static chooser_field_t::value_type foChooser(unsigned value) {
249                 static chooser_field_t::value_type table[] const = { 1, 5, 0 };
250                 return table[value];
251             }
252         };
253         \endcode
254         The \a translator class must have two publicly accessible static members, \c fromChooser and
255         \c toChooser. \c fromChooser takes the value as returned by the \a chooser field and must
256         return the corresponding class index whereas \c toChooser takes the class index and must
257         return the value to write into the \a chooser field.
258
259         \see \ref SENF_PARSER_VARIANT()
260         \hideinitializer
261         \ingroup packetparsermacros
262      */
263 #   define SENF_PARSER_VARIANT_TRANS(name, chooser, translator, types)                            \
264         SENF_PARSER_VARIANT_I(SENF_PARSER_FIELD,                                                  \
265                               name,                                                               \
266                               chooser,                                                            \
267                               translator,                                                         \
268                               types)
269
270     /** \brief Define Parse_Variant_Direct field with translator (private)
271         
272         \see \ref SENF_PARSER_VARIANT_TRANS()
273         \hideinitializer
274         \ingroup packetparsermacros
275      */
276 #   define SENF_PARSER_PRIVATE_VARIANT_TRANS(name, chooser, types)                                \
277         SENF_PARSER_VARIANT_I(SENF_PARSER_PRIVATE_FIELD,                                          \
278                               name,                                                               \
279                               chooser,                                                            \
280                               translator,                                                         \
281                               types)
282
283 }
284
285 ///////////////////////////////hh.e////////////////////////////////////////
286 #endif
287 #if !defined(HH_Packets__decls_) && !defined(HH_ParseVariant_i_)
288 #define HH_ParseVariant_i_
289 //#include "ParseVariant.cci"
290 #include "ParseVariant.ct"
291 #include "ParseVariant.cti"
292 #endif
293
294 \f
295 // Local Variables:
296 // mode: c++
297 // fill-column: 100
298 // comment-column: 40
299 // c-file-style: "senf"
300 // indent-tabs-mode: nil
301 // ispell-local-dictionary: "american"
302 // compile-command: "scons -u test"
303 // End: