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 VariantPolicy, SENF_PARSE_VARIANT_TPL_ARGS_DFL(class P)>
class Parse_Variant
: public PacketParserBase, private VariantPolicy
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);
static const size_type init_bytes =
senf::init_bytes<P0>::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 <unsigned N>
typename boost::mpl::at< parsers, boost::mpl::int_<N> >::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 <unsigned N>
- 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 <class ChooserType, unsigned Distance, SENF_PARSE_VARIANT_TPL_ARGS_DFL(class P)>
struct Parse_Variant_Direct
{
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)
}