diff --git a/Packets/ParseVariant.hh b/Packets/ParseVariant.hh index 9deb622679e990f0dda5ba6c37afb81957bf0185..0c33791864bb1c10f88ea6dbe4bf270e565c89f0 100644 --- a/Packets/ParseVariant.hh +++ b/Packets/ParseVariant.hh @@ -151,10 +151,11 @@ namespace senf { \see senf::Parser_Variant \ingroup parsecollection */ - template <class ChooserType, unsigned Distance, SENF_PARSE_VARIANT_TPL_ARGS_DFL(class P)> + template <class ChooserType, unsigned Distance, class Translator, + SENF_PARSE_VARIANT_TPL_ARGS_DFL(class P)> struct Parse_Variant_Direct { - typedef Parse_Variant< detail::Parse_Variant_Direct<ChooserType, Distance>, + typedef Parse_Variant< detail::Parse_Variant_Direct<ChooserType, Distance, Translator>, SENF_PARSE_VARIANT_TPL_ARGS(P) > parser; }; @@ -210,8 +211,12 @@ namespace senf { \hideinitializer \ingroup packetparsermacros */ -# define SENF_PARSER_VARIANT(name, chooser, types) \ - SENF_PARSER_VARIANT_I(SENF_PARSER_FIELD, name, chooser, types) +# define SENF_PARSER_VARIANT(name, chooser, types) \ + SENF_PARSER_VARIANT_I(SENF_PARSER_FIELD, \ + name, \ + chooser, \ + senf::detail::Parse_Variant_IdentityTranslator, \ + types) /** \brief Define Parse_Variant_Direct field (private) @@ -219,8 +224,61 @@ namespace senf { \hideinitializer \ingroup packetparsermacros */ -# define SENF_PARSER_PRIVATE_VARIANT(name, chooser, types) \ - SENF_PARSER_VARIANT_I(SENF_PARSER_PRIVATE_FIELD, name, chooser, types) +# define SENF_PARSER_PRIVATE_VARIANT(name, chooser, types) \ + SENF_PARSER_VARIANT_I(SENF_PARSER_PRIVATE_FIELD, \ + name, \ + chooser, \ + senf::detail::Parse_Variant_IdentityTranslator, \ + types) + + /** \brief Define Parse_Variant_Direct field with translator + + This is like \ref SENF_PARSER_VARIANT(), however it allows to specify a \a translator + argument which translates between \a chooser values and type indices: + \code + struct SomeTranslator { + static unsigned fromChooser(chooser_field_t::value_type value) { + switch (value) { + case 1 : return 0 ; + case 5 : return 1 ; + default : return 2 ; + } + } + + static chooser_field_t::value_type foChooser(unsigned value) { + static chooser_field_t::value_type table[] const = { 1, 5, 0 }; + return table[value]; + } + }; + \endcode + The \a translator class must have two publicly accessible static members, \c fromChooser and + \c toChooser. \c fromChooser takes the value as returned by the \a chooser field and must + return the corresponding class index whereas \c toChooser takes the class index and must + return the value to write into the \a chooser field. + + \see \ref SENF_PARSER_VARIANT() + \hideinitializer + \ingroup packetparsermacros + */ +# define SENF_PARSER_VARIANT_TRANS(name, chooser, translator, types) \ + SENF_PARSER_VARIANT_I(SENF_PARSER_FIELD, \ + name, \ + chooser, \ + translator, \ + types) + + /** \brief Define Parse_Variant_Direct field with translator (private) + + \see \ref SENF_PARSER_VARIANT_TRANS() + \hideinitializer + \ingroup packetparsermacros + */ +# define SENF_PARSER_PRIVATE_VARIANT_TRANS(name, chooser, types) \ + SENF_PARSER_VARIANT_I(SENF_PARSER_PRIVATE_FIELD, \ + name, \ + chooser, \ + translator, \ + types) } diff --git a/Packets/ParseVariant.ih b/Packets/ParseVariant.ih index 0e33da0ea092ee9a3d86b68210439a7f69eabfca..11660770f7f4272a81911ba6e5b7795c11f3e8af 100644 --- a/Packets/ParseVariant.ih +++ b/Packets/ParseVariant.ih @@ -56,7 +56,7 @@ namespace detail { # endif /** \brief Internal: Variant Policy used by senf::Parse_Variant_Direct */ - template <class ChooserType, unsigned Distance> + template <class ChooserType, unsigned Distance, class Translator> struct Parse_Variant_Direct { typedef PacketParserBase::data_iterator data_iterator; @@ -72,20 +72,27 @@ namespace detail { } unsigned variant(data_iterator i, state_type s) const { - return chooser(i,s).value(); + return Translator::fromChooser(chooser(i,s).value()); } void variant(unsigned v, data_iterator i, state_type s) { - chooser(i,s).value(v); + chooser(i,s).value(Translator::toChooser(v)); } }; + /** \brief Internal: Identity chooser translator */ + struct Parse_Variant_IdentityTranslator { + static unsigned fromChooser(unsigned value) { return value; } + static unsigned toChooser(unsigned value) { return value; } + }; + # define SENF_PARSER_VARIANT_(r, data, elem) ,elem -# define SENF_PARSER_VARIANT_I(field, name, chooser, types) \ +# define SENF_PARSER_VARIANT_I(field, name, chooser, translator, types) \ typedef senf::Parse_Variant_Direct< \ BOOST_PP_CAT(chooser, _t), \ - SENF_PARSER_CURRENT_FIXED_OFFSET() - SENF_PARSER_FIXED_OFFSET(chooser) \ + SENF_PARSER_CURRENT_FIXED_OFFSET() - SENF_PARSER_FIXED_OFFSET(chooser), \ + translator \ BOOST_PP_SEQ_FOR_EACH( SENF_PARSER_VARIANT_, _, types ) \ >::parser BOOST_PP_CAT(name, _variant_t); \ field( name, BOOST_PP_CAT(name, _variant_t) ) diff --git a/Packets/ParseVariant.test.cc b/Packets/ParseVariant.test.cc index e795e49a920dd19b87c45367b0486315997abf5a..41935d55f613924be283ff1c78dd845659a89f66 100644 --- a/Packets/ParseVariant.test.cc +++ b/Packets/ParseVariant.test.cc @@ -38,7 +38,7 @@ BOOST_AUTO_UNIT_TEST(parseVariant) { typedef senf::Parse_Array<10, senf::Parse_UInt8> Array10; - typedef senf::Parse_Variant_Direct< senf::Parse_UInt8, 1, + typedef senf::Parse_Variant_Direct< senf::Parse_UInt8, 1, senf::detail::Parse_Variant_IdentityTranslator, senf::VoidPacketParser, Array10, senf:: Parse_UInt32