X-Git-Url: http://g0dil.de/git?a=blobdiff_plain;f=Packets%2FParseVariant.hh;h=9deb622679e990f0dda5ba6c37afb81957bf0185;hb=70218c843c757e3ed781d9576d7a429673a6d6e2;hp=84564a46d9ac7bbb26306958c2c39cc1436e208c;hpb=9f6bb706cb491d4da38f6472746b3076a66202e0;p=senf.git diff --git a/Packets/ParseVariant.hh b/Packets/ParseVariant.hh index 84564a4..9deb622 100644 --- a/Packets/ParseVariant.hh +++ b/Packets/ParseVariant.hh @@ -44,17 +44,39 @@ namespace senf { -# ifndef SENF_LIMIT_PARSER_VARIANT -# define SENF_LIMIT_PARSE_VARIANT 10 -# endif - -# define SENF_PARSE_VARIANT_TPL_ARGS_DFL(n) \ - BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT( SENF_LIMIT_PARSE_VARIANT, \ - n, \ - boost::mpl::na ) +# ifndef SENF_LIMIT_PARSE_VARIANT + /** \brief Maximum number of senf::Parse_Variant sub-parsers. -# define SENF_PARSE_VARIANT_TPL_ARGS(n) BOOST_PP_ENUM_PARAMS( SENF_LIMIT_PARSE_VARIANT, n ) + This number defines the maximum number of parser arguments senf::Parse_Variant takes. + */ +# define SENF_LIMIT_PARSE_VARIANT 6 +# endif + /** \brief Variant parser + + This is not really a collection parser (it does not provide a collection + interface). However, it is not a composite parser or value parser either. + + A variant parser will parse any number of sub-parsers discriminated by an arbitrary, policy + defined condition. This is the parser to use, if the type and/or number of fields of a + packet change depending on some condition. + \code + typedef senf::Parse_Variant< + MyVariantPolicy, + senf::VoidPacketParser, Parse_TypeA, Parse_TypeB> MyVariant; + \endcode + This typedef defines a variant parser choosing one of three sub + parsers. senf::VoidPacketParser is an empty parser, it effectively makes this parser + optional. + + When creating a new packet containing a variant parser, the variant parser will always be + initialized to the first sub-parser. + + \see + ExampleVariantPolicy on how to implement the \a VariantPolicy \n + \ref SENF_PARSER_VARIANT() on how to integrate the parser into another parser + \ingroup parsecollection + */ template class Parse_Variant : public PacketParserBase, private VariantPolicy @@ -62,6 +84,9 @@ namespace senf { typedef boost::mpl::vector< SENF_PARSE_VARIANT_TPL_ARGS(P) > parsers; public: + ///\name Parser interface + ///\{ + Parse_Variant(data_iterator i, state_type s); Parse_Variant(VariantPolicy policy, data_iterator i, state_type s); @@ -71,19 +96,61 @@ namespace senf { static const size_type init_bytes = senf::init_bytes::value + VariantPolicy::init_bytes; + ///\} /////////////////////////////////////////////////////////////////////////// - unsigned variant() const; + unsigned variant() const; ///< Get current variant + /**< Get the currently selected variant index. The returned + number directly indexes the list of sub parsers. + \returns Index of currently selected variant. Integer + in the range from 0 to (number-of-sub-parsers - 1) + */ template typename boost::mpl::at< parsers, boost::mpl::int_ >::type get() const; + ///< Access sub-parser + /**< This call will return the sub-parser at index \a + N. This call will fail, if the currently active + variant() is not \a N. + \pre variant() == \a N + \returns sub-parser at index \a N */ template - void init(); - - private: + void init(); ///< Re-initialize field + /**< This will reinitialize the field to the variant + sub-parser at index \a N changing the currently + selected variant. + \post variant() == \a N */ }; + /** \brief Variant with direct, fixed distance type field + + This struct is a template typedef defining a senf::Parser_Variant instantiation. It defines + a variant parser which interprets the value returned by some other parser directly as index + into the list of sub parsers (the numeric template argument to senf::Parse_Variant::get() + and senf::Parser_Variant::init()). + + \code + // Define a variant choosing between Parse_Foo and Parse_Bar depending on the directly + // preceding 1-byte 8bit uint value + typedef senf::Parse_Variant_Direct< senf::Parse_UInt8, 1u, + Parse_Foo, Parse_Bar >::parser MyVariant; + \endcode + + \a ChooserType defines the type of the field used to choose the sub parser. This must be a + fixed-size value parser. \a Distance gives the \e fixed distance of this field \e before the + currently defined field. + + It is best to define a field of this type using \ref SENF_PARSER_VARIANT() or \ref + SENF_PARSER_PRIVATE_VARIANT(). + + \param[in] ChooserType type of chooser field (a value parser) + \param[in] Distance fixed distance of the chooser field before the current field + \param[in] P any number of sub parsers + + \see senf::Parser_Variant + \ingroup parsecollection + */ template struct Parse_Variant_Direct { @@ -91,23 +158,69 @@ namespace senf { SENF_PARSE_VARIANT_TPL_ARGS(P) > parser; }; -# define SENF_PARSER_VARIANT_(r, data, elem) ,elem - -# define SENF_PARSER_VARIANT(name, chooser, types) \ - typedef senf::Parse_Variant_Direct< \ - BOOST_PP_CAT(chooser, _t), \ - SENF_PARSER_CURRENT_FIXED_OFFSET() - SENF_PARSER_FIXED_OFFSET(chooser) \ - BOOST_PP_SEQ_FOR_EACH( SENF_PARSER_VARIANT_, _, types ) \ - >::parser BOOST_PP_CAT(name, _variant_t); \ - SENF_PARSER_FIELD( name, BOOST_PP_CAT(name, _variant_t) ) - -# define SENF_PARSER_PRIVATE_VARIANT(name, chooser, types) \ - typedef senf::Parse_Variant_Direct< \ - BOOST_PP_CAT(chooser, _t), \ - SENF_PARSER_CURRENT_FIXED_OFFSET() - SENF_PARSER_FIXED_OFFSET(chooser) \ - BOOST_PP_SEQ_FOR_EACH( SENF_PARSER_VARIANT_, _, types ) \ - >::parser BOOST_PP_CAT(name, _variant_t); \ - SENF_PARSER_PRIVATE_FIELD( name, BOOST_PP_CAT(name, _variant_t) ) + /** \brief Define Parse_Variant_Direct field + + This macro is a special helper to define a senf::Parse_Variant_Direct type field. This is a + variant field which chooses the sub-type by directly taking the value of some other field. + + This is a dynamically sized parser. Nevertheless, the chooser field \e must have a \e fixed + distance to this field, the \a chooser must be a fixed-size value parser. + + \code + struct SomeParser : public PacketParserBase + { + # include SENF_PARSER() + + SENF_PARSER_PRIVATE_FIELD( type, senf::Parse_UInt8 ); + SENF_PARSER_PRIVATE_VARIANT( content, type, + (senf::VoidPacketParser) + (senf::Parse_UInt8) + (senf::Parse_UInt16) + (senf::Parse_UInt24) + (senf::Parse_UInt32) ); + + senf::Parse_UInt8 uint8() const { return content().get<1>(); } + senf::Parse_UInt16 uint16() const { return content().get<2>(); } + senf::Parse_UInt24 uint24() const { return content().get<3>(); } + senf::Parse_UInt32 uint32() const { return content().get<4>(); } + + void disable() const { content().init<0>(); } + void set_uint8() const { content().init<1>(); } + void set_uint16() const { content().init<2>(); } + void set_uint24) const { content().init<3>(); } + void set_uint23() const { content().init<4>(); } + + SENF_PARSER_FINALIZE(SomeParser); + }; + \endcode + + The variant \c content chooses one of the sub parsers depending on the \c type field. If \c + type is 0, senf::VoidPacketParser is selected, if it is 1, senf::Parse_UInt8 and so on. + + It is customary, to hide the variant parser (by defining it private) and provide more + conveniently named accessors. + + \param[in] name name of the field + \param[in] chooser name of the field choosing the variant to use + \param[in] types a Boost.Preprocessor style sequence of sub-parser types + + \see + senf::Parse_Variant \n + \ref SENF_PARSER_PRIVATE_VARIANT() + \hideinitializer + \ingroup packetparsermacros + */ +# define SENF_PARSER_VARIANT(name, chooser, types) \ + SENF_PARSER_VARIANT_I(SENF_PARSER_FIELD, name, chooser, types) + + /** \brief Define Parse_Variant_Direct field (private) + + \see \ref SENF_PARSER_VARIANT() + \hideinitializer + \ingroup packetparsermacros + */ +# define SENF_PARSER_PRIVATE_VARIANT(name, chooser, types) \ + SENF_PARSER_VARIANT_I(SENF_PARSER_PRIVATE_FIELD, name, chooser, types) }