Packets: Migrate VariantParser to use AuxParser/container infrstructure
[senf.git] / Packets / VariantParser.hh
1 // $Id$
2 //
3 // Copyright (C) 2007
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 VariantParser public header */
25
26 #ifndef HH_VariantParser_
27 #define HH_VariantParser_ 1
28
29 #ifndef HH_Packets_
30 #error "Don't include 'VariantParser.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 "VariantParser.mpp"
42 ///////////////////////////////hh.p////////////////////////////////////////
43
44 namespace senf {
45
46 #   ifndef SENF_LIMIT_PARSE_VARIANT
47         /** \brief Maximum number of senf::VariantParser sub-parsers.
48
49             This number defines the maximum number of parser arguments senf::VariantParser takes.
50          */
51 #       define SENF_LIMIT_PARSE_VARIANT 6
52 #   endif
53
54     /** \brief Variant parser
55
56         This is not really a collection parser (it does not provide a collection
57         interface). However, it is not a composite parser or value parser either.
58
59         A variant parser will parse any number of sub-parsers discriminated by an arbitrary, policy
60         defined condition. This is the parser to use, if the type and/or number of fields of a
61         packet change depending on some condition.
62         \code
63         typedef senf::VariantParser< 
64             MyAuxPolicy, 
65             senf::VoidPacketParser, TypeAParser, TypeBParser> MyVariantParser;
66         \endcode
67         This typedef defines a variant parser choosing one of three sub
68         parsers. senf::VoidPacketParser is an empty parser, it effectively makes this parser
69         optional.
70
71         When creating a new packet containing a variant parser, the variant parser will always be
72         initialized to the first sub-parser.
73
74         \see 
75             ExampleAuxPolicy on how to implement the \a AuxPolicy \n
76             \ref SENF_PARSER_VARIANT() on how to integrate the parser into another parser
77         \ingroup parsecollection
78      */
79     template <class AuxPolicy, class Parsers>
80     class VariantParser 
81         : public PacketParserBase, private AuxPolicy
82     {
83         typedef Parsers parsers;
84
85     public:
86         ///\name Parser interface
87         ///\{
88
89         VariantParser(data_iterator i, state_type s);
90         VariantParser(AuxPolicy policy, data_iterator i, state_type s);
91
92         size_type bytes() const;
93         void init();
94         
95         static const size_type init_bytes = senf::init_bytes< 
96             typename boost::mpl::at<parsers, boost::mpl::int_<0> >::type>::value 
97                 + AuxPolicy::aux_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 Define DirectVariantParser field
127
128         This macro is a special helper to define a senf::DirectVariantParser type field. This is a
129         variant field which chooses the sub-type by directly taking the value of some other field.
130
131         \warning
132           This is a dynamically sized parser. Nevertheless, the chooser field \e must have a
133           \e fixed distance to this field, the \a chooser must be a fixed-size value parser.
134
135         \code
136         struct SomeParser : public PacketParserBase
137         {
138         #   include SENF_PARSER()
139         
140             SENF_PARSER_PRIVATE_FIELD( type, senf::UInt8Parser );
141             SENF_PARSER_PRIVATE_VARIANT( content, type,
142                                             (senf::VoidPacketParser)
143                                             (senf::UInt8Parser)
144                                             (senf::UInt16Parser)
145                                             (senf::UInt24Parser)
146                                             (senf::UInt32Parser) );
147
148             senf::UInt8Parser  uint8()  const { return content().get<1>(); }
149             senf::UInt16Parser uint16() const { return content().get<2>(); }
150             senf::UInt24Parser uint24() const { return content().get<3>(); }
151             senf::UInt32Parser uint32() const { return content().get<4>(); }
152
153             void disable()    const { content().init<0>(); }
154             void set_uint8()  const { content().init<1>(); }
155             void set_uint16() const { content().init<2>(); }
156             void set_uint24)  const { content().init<3>(); }
157             void set_uint23() const { content().init<4>(); }
158
159             SENF_PARSER_FINALIZE(SomeParser);
160         };
161         \endcode
162
163         The variant \c content chooses one of the sub parsers depending on the \c type field. If \c
164         type is 0, senf::VoidPacketParser is selected, if it is 1, senf::UInt8Parser and so on. 
165
166         It is customary, to hide the variant parser (by defining it private) and provide more
167         conveniently named accessors.
168
169         \param[in] name name of the field
170         \param[in] chooser name of the field choosing the variant to use
171         \param[in] types a Boost.Preprocessor style sequence of sub-parser types
172
173         \see 
174             senf::VariantParser \n 
175             \ref SENF_PARSER_PRIVATE_VARIANT()
176         \hideinitializer
177         \ingroup packetparsermacros
178      */
179 #   define SENF_PARSER_VARIANT(name, chooser, types) \
180         SENF_PARSER_VARIANT_I(public, name, chooser, types)
181
182     /** \brief Define DirectVariantParser field (private)
183         
184         \see \ref SENF_PARSER_VARIANT()
185         \hideinitializer
186         \ingroup packetparsermacros
187      */
188 #   define SENF_PARSER_PRIVATE_VARIANT(name, chooser, types) \
189         SENF_PARSER_VARIANT_I(private, name, chooser, types)
190
191     /** \brief Define DirectVariantParser field with translator
192         
193         This is like \ref SENF_PARSER_VARIANT(), however it allows to specify a \a translator
194         argument which translates between \a chooser values and type indices:
195         \code
196         struct SomeTranslator {
197             static unsigned fromChooser(chooser_field_t::value_type value) {
198                 switch (value) {
199                 case 1  : return 0 ;
200                 case 5  : return 1 ;
201                 default : return 2 ;
202                 }
203             }
204             static chooser_field_t::value_type toChooser(unsigned value) {
205                 static chooser_field_t::value_type table[] const = { 1, 5, 0 };
206                 return table[value];
207             }
208         };
209         \endcode
210         The \a translator class must have two publicly accessible static members, \c fromChooser and
211         \c toChooser. \c fromChooser takes the value as returned by the \a chooser field and must
212         return the corresponding class index whereas \c toChooser takes the class index and must
213         return the value to write into the \a chooser field.
214
215         \see \ref SENF_PARSER_VARIANT()
216         \hideinitializer
217         \ingroup packetparsermacros
218      */
219
220
221 }
222
223 ///////////////////////////////hh.e////////////////////////////////////////
224 #endif
225 #if !defined(HH_Packets__decls_) && !defined(HH_VariantParser_i_)
226 #define HH_VariantParser_i_
227 //#include "VariantParser.cci"
228 #include "VariantParser.ct"
229 #include "VariantParser.cti"
230 #endif
231
232 \f
233 // Local Variables:
234 // mode: c++
235 // fill-column: 100
236 // comment-column: 40
237 // c-file-style: "senf"
238 // indent-tabs-mode: nil
239 // ispell-local-dictionary: "american"
240 // compile-command: "scons -u test"
241 // End: