From: g0dil Date: Wed, 11 Jun 2008 10:18:23 +0000 (+0000) Subject: Packets: Implement additional SENF_PARSER_VARIANT options (keys, accessors) X-Git-Url: http://g0dil.de/git?a=commitdiff_plain;h=0b019beda0f10ad880b3c08bae2851ca5b5d909e;p=senf.git Packets: Implement additional SENF_PARSER_VARIANT options (keys, accessors) git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@875 270642c3-0616-0410-b53a-bc976706d245 --- diff --git a/Packets/ParseHelpers.ih b/Packets/ParseHelpers.ih index 43f8b0f..31f0984 100644 --- a/Packets/ParseHelpers.ih +++ b/Packets/ParseHelpers.ih @@ -462,6 +462,8 @@ # define SENF_CAT_RECURS1_I(a, b) a ## b # define SENF_CAT_RECURS2(a, b) SENF_CAT_RECURS2_I(a,b) # define SENF_CAT_RECURS2_I(a, b) a ## b +# define SENF_CAT_RECURS3(a, b) SENF_CAT_RECURS3_I(a,b) +# define SENF_CAT_RECURS3_I(a, b) a ## b # # define SENF_PARSER_COLLECTION_TAG_GOBBLE__transform(x,y) # define SENF_PARSER_COLLECTION_TAG__transform(x,y) \ @@ -490,6 +492,11 @@ # define SENF_PARSER_COLLECTION_HAS_KEYWORD(x) \ BOOST_PP_IS_EMPTY( SENF_CAT_RECURS1(SENF_PARSER_COLLECTION_TAG_GOBBLE__, x) ) # +# define SENF_PARSER_COLLECTION_GETAUX(aux) \ + BOOST_PP_IF( SENF_PARSER_COLLECTION_HAS_KEYWORD(aux), \ + SENF_CAT_RECURS2(SENF_PARSER_COLLECTION_TAG_GETAUX__, aux), \ + aux ) + # define SENF_PARSER_COLLECTION_I(access, name, aux, traits) \ BOOST_PP_EXPAND( \ SENF_PARSER_COLLECTION_II \ diff --git a/Packets/VariantParser.cti b/Packets/VariantParser.cti index 78d232d..d694cf6 100644 --- a/Packets/VariantParser.cti +++ b/Packets/VariantParser.cti @@ -104,6 +104,54 @@ senf::detail::VariantBytes::bytes(Variant const & v, unsigned n) return senf::bytes(v.template get<0>()); } +/////////////////////////////////////////////////////////////////////////// +// senf::detail::VariantKeyTransform + +template +prefix_ unsigned senf::detail::VariantKeyTransform::get(input_type v) +{ + return VariantKeyTransformCheck< + input_type, value_type, Keys, boost::mpl::size::type::value-1>::get(v); +} + +template +prefix_ typename senf::detail::VariantKeyTransform::input_type +senf::detail::VariantKeyTransform::set(unsigned v) +{ + return VariantKeyTransformCheck< + input_type, value_type, Keys, boost::mpl::size::type::value-1>::set(v); +} + +template +prefix_ Out senf::detail::VariantKeyTransformCheck::get(In v) +{ + if (boost::mpl::at >::type::key() == v) + return N; + else + return VariantKeyTransformCheck::get(v); +} + +template +prefix_ In senf::detail::VariantKeyTransformCheck::set(Out v) +{ + if (v == N) + return boost::mpl::at >::type::key(); + else + return VariantKeyTransformCheck::set(v); +} + +template +prefix_ Out senf::detail::VariantKeyTransformCheck::get(In v) +{ + return 0; +} + +template +prefix_ In senf::detail::VariantKeyTransformCheck::set(Out v) +{ + return boost::mpl::at >::type::key(); +} + ///////////////////////////////cti.e/////////////////////////////////////// #undef prefix_ diff --git a/Packets/VariantParser.ih b/Packets/VariantParser.ih index f185800..5a85944 100644 --- a/Packets/VariantParser.ih +++ b/Packets/VariantParser.ih @@ -30,6 +30,10 @@ #include "PacketParser.hh" #include #include +#include +#include +#include +#include ///////////////////////////////ih.p//////////////////////////////////////// @@ -48,43 +52,201 @@ namespace detail { static PacketParserBase::size_type bytes(Variant const & v, unsigned n); }; + template + struct VariantParserPolicy; + template - struct VariantParserPolicy {}; + struct VariantParserPolicy + {}; + + template + struct VariantParserPolicy + : public VariantParserPolicy< void, + TransformAuxParserPolicy, AuxTag > + {}; template - struct VariantParserPolicy + struct VariantParserPolicy { typedef AuxPolicy type; }; - template - struct VariantParserPolicy > { typedef TransformAuxParserPolicy type; }; - template + template struct VariantParserTraits { template struct parser { typedef senf::VariantParser< - typename VariantParserPolicy::type, + typename VariantParserPolicy::type, Parsers> type; }; }; + + template + struct VariantKey + { + static T key() { return (*KeyFn)(); } + }; + + template + struct VariantKeyTransform + { + typedef unsigned value_type; + typedef T input_type; + static unsigned get(input_type v); + static input_type set(unsigned v); + }; + + template + struct VariantKeyTransformCheck + { + static Out get(In v); + static In set(Out v); + }; + + template + struct VariantKeyTransformCheck + { + static Out get(In v); + static In set(Out v); + }; # define SENF_PARSER_VARIANT_I(access, name, chooser, types) \ - typedef boost::mpl::vector< BOOST_PP_SEQ_ENUM(types) > BOOST_PP_CAT(name, _parsers); \ SENF_PARSER_REQUIRE_VAR(variant) \ + typedef boost::mpl::vector< BOOST_PP_SEQ_ENUM(SENF_PARSER_VARIANT_TYPES(types)) > \ + BOOST_PP_CAT(name, _parsers); \ + typedef BOOST_PP_CAT(SENF_PARSER_COLLECTION_GETAUX(chooser), _t)::value_type \ + BOOST_PP_CAT(name,_chooser_value_type); \ + BOOST_PP_IF( SENF_PARSER_VARIANT_NEEDTRANSFORM(types), \ + SENF_PARSER_VARIANT_MAKETRANSFORM, \ + SENF_PARSER_VARIANT_NOTRANSFORM )(name, \ + types) \ + typedef senf::detail::VariantParserTraits< BOOST_PP_CAT(name, _parsers), \ + BOOST_PP_CAT(name, _transform) > \ + BOOST_PP_CAT(name, _traits); \ SENF_PARSER_COLLECTION_I( \ - access, \ - name, \ - chooser, \ - senf::detail::VariantParserTraits< BOOST_PP_CAT(name, _parsers) > ) + access, name, chooser, BOOST_PP_CAT(name, _traits) ); \ + BOOST_PP_SEQ_FOR_EACH_I(SENF_PARSER_VARIANT_ACCESSOR, name, types) + +# define SENF_PARSER_VARIANT_MAKETRANSFORM(name, types) \ + BOOST_PP_SEQ_FOR_EACH_I(SENF_PARSER_VARIANT_KEYVALUE, name, types) \ + template \ + struct BOOST_PP_CAT(name, _key_value_template) \ + : public senf::detail::VariantKey {}; \ + typedef senf::detail::VariantKeyTransform< \ + BOOST_PP_CAT(name,_chooser_value_type), \ + boost::mpl::vector< \ + BOOST_PP_SEQ_ENUM(SENF_PARSER_VARIANT_KEYVALUES(name, types)) \ + > > BOOST_PP_CAT(name, _transform); + +# define SENF_PARSER_VARIANT_KEYVALUE(r, name, i, elem) \ + static BOOST_PP_CAT(name, _chooser_value_type) \ + BOOST_PP_CAT(BOOST_PP_CAT(name, _key_),i)() \ + { return SENF_PARSER_VARIANT_GETKEY(elem, i); } + +# define SENF_PARSER_VARIANT_NOTRANSFORM(name, types) \ + typedef void BOOST_PP_CAT(name, _transform); + +# define SENF_PARSER_VARIANT_KEYVALUES(name, types) \ + BOOST_PP_SEQ_FOR_EACH_I(SENF_PARSER_VARIANT_KEYVALUES_, name, types) + +# define SENF_PARSER_VARIANT_KEYVALUES_(r, name, i, elem) \ + (BOOST_PP_CAT(name,_key_value_template)< \ + & BOOST_PP_CAT(BOOST_PP_CAT(name, _key_), i) >) + +# define SENF_PARSER_VARIANT_ACCESSOR(r, name, i, elem) \ + BOOST_PP_IF( SENF_PARSER_VARIANT_HASID(elem), \ + SENF_PARSER_VARIANT_MAKEACCESSOR, \ + SENF_PARSER_VARIANT_NOACCESSOR )(name, i, elem) + +# define SENF_PARSER_VARIANT_NOACCESSOR(name, i, elem) +# define SENF_PARSER_VARIANT_MAKEACCESSOR(name, i, elem) \ + BOOST_PP_IF( SENF_PARSER_VARIANT_HASVALUE(elem), \ + SENF_PARSER_VARIANT_MAKEVACCESSOR, \ + SENF_PARSER_VARIANT_MAKENVACCESSOR )(name, i, elem) + +# define SENF_PARSER_VARIANT_MAKEVACCESSOR(name, i, elem) \ + SENF_PARSER_VARIANT_GETTYPE(elem) SENF_PARSER_VARIANT_GETID(elem)() \ + { return name().get(); } \ + void BOOST_PP_CAT(init_, SENF_PARSER_VARIANT_GETID(elem))() \ + { name().init(); } \ + bool BOOST_PP_CAT(has_, SENF_PARSER_VARIANT_GETID(elem))() \ + { return name().variant() == i; } + +# define SENF_PARSER_VARIANT_MAKENVACCESSOR(name, i, elem) \ + void SENF_PARSER_VARIANT_GETID(elem)() \ + { name().init(); } + +# define SENF_PARSER_VARIANT_KEY_GOBBLE__key(key, type) +# define SENF_PARSER_VARIANT_KEY_GETKEY__key(key, type) key +# define SENF_PARSER_VARIANT_KEY_GETTYPE__key(key, type) type + +# define SENF_PARSER_VARIANT_ID_GOBBLE__id(id, value) +# define SENF_PARSER_VARIANT_ID_GETID__id(id, value) id +# define SENF_PARSER_VARIANT_ID_GETVALUE__id(id, value) value + +# define SENF_PARSER_VARIANT_ID_GOBBLE__novalue(id, value) +# define SENF_PARSER_VARIANT_ID_GETID__novalue(id, value) id +# define SENF_PARSER_VARIANT_ID_GETVALUE__novalue(id, value) value + +# define SENF_PARSER_VARIANT_HASVALUE_GOBBLE__id(id, value) + +# define SENF_PARSER_VARIANT_HASKEY(x) \ + SENF_PARSER_VARIANT_HASKEY_( SENF_PARSER_VARIANT_GETVALUE(x) ) + +# define SENF_PARSER_VARIANT_HASKEY_(x) \ + BOOST_PP_IS_EMPTY( SENF_CAT_RECURS1(SENF_PARSER_VARIANT_KEY_GOBBLE__, x) ) + +# define SENF_PARSER_VARIANT_GETKEY(x, default) \ + SENF_PARSER_VARIANT_GETKEY_( SENF_PARSER_VARIANT_GETVALUE(x), default ) + +# define SENF_PARSER_VARIANT_GETKEY_(x, default) \ + BOOST_PP_IF( SENF_PARSER_VARIANT_HASKEY_(x), \ + BOOST_PP_CAT(SENF_PARSER_VARIANT_KEY_GETKEY__, x), \ + default ) + +# define SENF_PARSER_VARIANT_HASID(x) \ + BOOST_PP_IS_EMPTY( SENF_CAT_RECURS2(SENF_PARSER_VARIANT_ID_GOBBLE__, x) ) + +# define SENF_PARSER_VARIANT_GETID(x) \ + BOOST_PP_CAT(SENF_PARSER_VARIANT_ID_GETID__, x) + +# define SENF_PARSER_VARIANT_GETVALUE(x) \ + BOOST_PP_IF( SENF_PARSER_VARIANT_HASID(x), \ + BOOST_PP_CAT(SENF_PARSER_VARIANT_ID_GETVALUE__, x), \ + x ) + +# define SENF_PARSER_VARIANT_HASVALUE(x) \ + BOOST_PP_IS_EMPTY( SENF_CAT_RECURS3(SENF_PARSER_VARIANT_HASVALUE_GOBBLE__, x) ) + +# define SENF_PARSER_VARIANT_GETTYPE(x) \ + SENF_PARSER_VARIANT_GETTYPE_( SENF_PARSER_VARIANT_GETVALUE(x) ) + +# define SENF_PARSER_VARIANT_GETTYPE_(x) \ + BOOST_PP_IF( SENF_PARSER_VARIANT_HASKEY_(x), \ + BOOST_PP_CAT(SENF_PARSER_VARIANT_KEY_GETTYPE__, x), \ + x ) + +# define SENF_PARSER_VARIANT_NEEDTRANSFORM(types) \ + BOOST_PP_SEQ_FOLD_LEFT(SENF_PARSER_VARIANT_NEEDTRANSFORM_, 0, types) + +# define SENF_PARSER_VARIANT_NEEDTRANSFORM_(s, state, elem) \ + BOOST_PP_OR(state, SENF_PARSER_VARIANT_HASKEY(elem)) + +# define SENF_PARSER_VARIANT_TYPES(types) \ + BOOST_PP_SEQ_FOR_EACH(SENF_PARSER_VARIANT_TYPES_, _, types) + +# define SENF_PARSER_VARIANT_TYPES_(r, _, elem) \ + (SENF_PARSER_VARIANT_GETTYPE(elem)) #endif diff --git a/Packets/VariantParser.test.cc b/Packets/VariantParser.test.cc index 24c92ec..d330e5a 100644 --- a/Packets/VariantParser.test.cc +++ b/Packets/VariantParser.test.cc @@ -94,20 +94,12 @@ namespace { { # include SENF_PARSER() - struct TestTransform { - typedef unsigned value_type; - static unsigned get(unsigned v) { return v/2; } - static unsigned set(unsigned v) { return 2*v; } - }; - SENF_PARSER_SKIP_BITS( 4 ); SENF_PARSER_BITFIELD_RO( type, 4, unsigned ); - SENF_PARSER_PRIVATE_VARIANT( content_, transform(TestTransform, type), - (senf::VoidPacketParser)(SubParser) ); - - bool hasContent() const { return content_().variant() == 1; } - void hasContent(bool v) const { if (v) content_().init<1>(); else content_().init<0>(); } - SubParser content() const { return content_().get<1>(); } + SENF_PARSER_PRIVATE_VARIANT( content_, type, + ( novalue( nocontent, key(10, senf::VoidPacketParser)) ) + ( id( content, SubParser ) ) + ); SENF_PARSER_FINALIZE(TestParser); }; @@ -120,18 +112,21 @@ BOOST_AUTO_UNIT_TEST(VariantParserMacro) { TestParser v (p.data().begin(), & p.data()); - BOOST_CHECK( ! v.hasContent() ); + v.init(); + BOOST_CHECK( ! v.has_content() ); BOOST_CHECK_EQUAL( senf::bytes(v), 1u ); - BOOST_CHECK_EQUAL( v.type(), 0u ); - v.hasContent(true); + BOOST_CHECK_EQUAL( v.type(), 10u ); + v.init_content(); // Parser invalidated } { TestParser v (p.data().begin(), & p.data()); - BOOST_CHECK( v.hasContent() ); + BOOST_CHECK( v.has_content() ); BOOST_CHECK_EQUAL( senf::bytes(v), 7u ); BOOST_CHECK_EQUAL( v.content().foo(), 0u ); - BOOST_CHECK_EQUAL( v.type(), 2u ); + BOOST_CHECK_EQUAL( v.type(), 1u ); + v.nocontent(); + // Parser invalidated } }