From: g0dil Date: Wed, 11 Jun 2008 13:28:56 +0000 (+0000) Subject: Packets: Add some public/private commands to parser helper macros X-Git-Url: http://g0dil.de/git?a=commitdiff_plain;h=734c0be097d831c8b6e1e797bae08262fc9b4dfe;p=senf.git Packets: Add some public/private commands to parser helper macros Packets: Adjust/rewrite SENF_PARSER_VARIANT documentation Packets: Add internal documentation page about helper macro expansion git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@876 270642c3-0616-0410-b53a-bc976706d245 --- diff --git a/Packets/ParseHelpers.dox b/Packets/ParseHelpers.dox new file mode 100644 index 0000000..c0c7981 --- /dev/null +++ b/Packets/ParseHelpers.dox @@ -0,0 +1,279 @@ +// $Id$ +// +// Copyright (C) 2008 +// Fraunhofer Institute for Open Communication Systems (FOKUS) +// Competence Center NETwork research (NET), St. Augustin, GERMANY +// Stefan Bund +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the +// Free Software Foundation, Inc., +// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +/** \page parsermacro_expand_example Example macro-expansion of packet parser helper macros + + The following packet parser definition (taken from VariantParser.test.cc) has been subject to + macro-expansion (and a lot of reformatting) to show the inner workings of the packet parser + macros: + \code + struct TestParser : public senf::PacketParserBase + { + # include SENF_PARSER() + + SENF_PARSER_SKIP_BITS( 4 ); + SENF_PARSER_BITFIELD_RO( type, 4, unsigned ); + SENF_PARSER_PRIVATE_VARIANT( content_, type, + ( novalue( nocontent, key(10, senf::VoidPacketParser)) ) + ( id( content, SubParser ) ) + ); + + SENF_PARSER_FINALIZE(TestParser); + }; + \endcode + + Here the reformated and sparsly commented expansion. I have left all the \c SENF_MPL_SLOT_ calls + unexpanded, otherwise the code would be absolutely unreadable. This is quite a lot of + source-code which however should create only a small amount of additional compiled code. + + Also remember, that all this code is generated by C++ makros. Some detours are needed to work + around makro problems (e.g. templates with multiple arguments are parsed as seperate makro + arguments at each komma, inability to redefine a makro from another makro ...). + + \code + struct TestParser : public senf::PacketParserBase + { + // ///////////////////////////////////////////////////////////////////////// + // #include SENF_PARSER() + + private: + SENF_MPL_SLOT_INIT_ZERO(index); + SENF_MPL_SLOT_INIT_ZERO(init_bytes); + SENF_MPL_SLOT_INIT_ZERO(bit); + SENF_MPL_SLOT_INIT_ZERO(bitfield_size); + SENF_MPL_SLOT_INIT_ZERO(group); + + void init_chain (senf::mpl::rv <0> *) const {} + size_type field_offset_ (senf::mpl::rv <0> *) const { return 0; } + + // ///////////////////////////////////////////////////////////////////////// + // SENF_PARSER_SKIP_BITS( 4 ); + + SENF_MPL_SLOT_SET(bit, SENF_MPL_SLOT_GET(bit) + 4); + + // ///////////////////////////////////////////////////////////////////////// + // SENF_PARSER_BITFIELD_RO( type, 4, unsigned ); + + public: + static size_type const type_bit = SENF_MPL_SLOT_GET(bit); + + private: + SENF_MPL_SLOT_SET(bit, type_bit + 4); + typedef senf::UIntFieldParser type_bit_t; + + public: + typedef type_bit_t type_t; + static size_type const type_index = SENF_MPL_SLOT_GET(index) + 1; + + private: + SENF_MPL_SLOT_SET(index, type_index); + void init_chain (senf::mpl::rv *) const + { + init_chain (static_cast *>(0)); + } + + public: + size_type type_offset () const + { + return field_offset_(static_cast *>(0)) - + SENF_MPL_SLOT_GET(bitfield_size); + } + static size_type const type_init_bytes = + SENF_MPL_SLOT_GET(init_bytes) - SENF_MPL_SLOT_GET(bitfield_size); + size_type type_next_offset () const + { + return type_offset() + type_t::fixed_bytes; + } + static size_type const type_next_init_bytes = type_init_bytes + type_t::fixed_bytes; + + private: + size_type field_offset_(senf::mpl::rv *) const + { + return type_next_offset(); + } + SENF_MPL_SLOT_SET(init_bytes, type_next_init_bytes); + static size_type const type_group = SENF_MPL_SLOT_GET(group) + 0; + SENF_MPL_SLOT_SET(group, type_group); + SENF_MPL_SLOT_SET(bitfield_size, type_t::fixed_bytes); + type_t type_ () const + { + return parse (type_offset ()); + } + + public: + type_t::value_type type () const + { + return type_(); + } + + // ///////////////////////////////////////////////////////////////////////// + // SENF_PARSER_PRIVATE_VARIANT( content_, type, + // ( novalue( nocontent, key(10, senf::VoidPacketParser)) ) + // ( id( content, SubParser ) ) + // ); + + private: + typedef boost::mpl::vector content__parsers; + typedef type_t::value_type content__chooser_value_type; + static content__chooser_value_type content__key_0 () + { + return 10; + } + static content__chooser_value_type content__key_1 () + { + return 1; + } + template + struct content__key_value_template + : public senf::detail::VariantKey {}; + template friend class senf::detail::VariantKey; + typedef senf::detail::VariantKeyTransform< + content__chooser_value_type, + boost::mpl::vector< content__key_value_template<&content__key_0>, + content__key_value_template<&content__key_1> > > + content__transform; + typedef senf::detail::VariantParserTraits + content__traits; + + // start SENF_PARSER_COLLECTION_I + static bool const content__aux_fixed = (SENF_MPL_SLOT_GET(group) - type_group) == 0; + typedef senf::detail::ParserAuxPolicySelect < + type_t, + SENF_MPL_SLOT_GET(init_bytes) - type_init_bytes, + content__aux_fixed + >::type content__aux_policy; + typedef content__traits::parser::type + content__collection_t; + SENF_MPL_SLOT_SET(bit, 0); + SENF_MPL_SLOT_SET(bitfield_size, 0); + typedef content__collection_t content__t; + static size_type const content__index = SENF_MPL_SLOT_GET(index) + 1; + SENF_MPL_SLOT_SET(index, content__index); + void init_chain (senf::mpl::rv *) const + { + init_chain (static_cast *>(0)); + content_().init(); + } + size_type content__offset() const + { + return field_offset_ (static_cast *>(0)); + } + static size_type const content__init_bytes = SENF_MPL_SLOT_GET(init_bytes); + size_type content__next_offset () const + { + return content__offset() + senf::bytes(content__()); + } + static size_type const content__next_init_bytes = + content__init_bytes + senf::init_bytes::value; + size_type field_offset_(senf::mpl::rv *) const + { + return content__next_offset(); + } + SENF_MPL_SLOT_SET(init_bytes, content__next_init_bytes); + static size_type const content__group = + SENF_MPL_SLOT_GET(group) + (senf::is_fixed::value ? 0 : 1); + SENF_MPL_SLOET_SET(group, content__group); + template < class T > + T content__dispatch (boost::true_type) const + { + return parse(content__offset()); + } + template < class T > + T content__dispatch (boost::false_type) const + { + return parse(type(), content__offset()); + } + + content__t content__() const + { + return content__dispatch( + boost::integral_constant()); + } + content__t content_ () const + { + return content__ (); + } + // end SENF_PARSER_COLLECTION_I + + public: + void nocontent() const + { + content_().init<0>(); + } + typedef SubParser content_t; + SubParser content() const + { + return content_().get<1>(); + } + void init_content() const + { + content_().init<1>(); + } + bool has_content() const + { + return content_().variant() == 1; + }; + + // ///////////////////////////////////////////////////////////////////////// + // SENF_PARSER_FINALIZE(TestParser); + + void defaultInit () const + { + init_chain(static_cast *>(0)); + } + TestParser(data_iterator i, state_type s) + : parser_base_type (i, s) + {} + + private: + template + void init(T) const + { + defaultInit (); + } + + public: + void init() const + { + init (0); + } + size_type bytes() const + { + return field_offset_(static_cast *>(0)); + } + static size_type const init_bytes = SENF_MPL_SLOT_GET(init_bytes); + }; + \endcode + */ + + +// Local Variables: +// mode: c++ +// fill-column: 100 +// comment-column: 40 +// c-file-style: "senf" +// indent-tabs-mode: nil +// ispell-local-dictionary: "american" +// compile-command: "scons -u test" +// mode: flyspell +// mode: auto-fill +// End: diff --git a/Packets/ParseHelpers.ih b/Packets/ParseHelpers.ih index 31f0984..02520f5 100644 --- a/Packets/ParseHelpers.ih +++ b/Packets/ParseHelpers.ih @@ -327,7 +327,9 @@ # define SENF_PARSER_SKIP_BITS_fix(bits) SENF_PARSER_I_SKIP_BITS(bits, fix) # # define SENF_PARSER_I_SKIP_BITS(bits, ofstype) \ - SENF_MPL_SLOT_SET(bit, SENF_MPL_SLOT_GET(bit) + bits) + private: \ + SENF_MPL_SLOT_SET(bit, SENF_MPL_SLOT_GET(bit) + bits); \ + public: # # /////////////////////////////////////////////////////////////////////////// # // SENF_PARSER_GOTO_* diff --git a/Packets/VariantParser.hh b/Packets/VariantParser.hh index 1887cd9..8516a9f 100644 --- a/Packets/VariantParser.hh +++ b/Packets/VariantParser.hh @@ -135,22 +135,11 @@ namespace senf { SENF_PARSER_PRIVATE_FIELD( type, senf::UInt8Parser ); SENF_PARSER_PRIVATE_VARIANT( content, type, - (senf::VoidPacketParser) - (senf::UInt8Parser) - (senf::UInt16Parser) - (senf::UInt24Parser) - (senf::UInt32Parser) ); - - senf::UInt8Parser uint8() const { return content().get<1>(); } - senf::UInt16Parser uint16() const { return content().get<2>(); } - senf::UInt24Parser uint24() const { return content().get<3>(); } - senf::UInt32Parser 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>(); } + (novalue( disable, senf::VoidPacketParser )) + ( id( uint8, senf::UInt8Parser )) + ( id( uint16, senf::UInt16Parser )) + ( id( uint24, senf::UInt24Parser )) + ( id( uint32, senf::UInt32Parser )) ); SENF_PARSER_FINALIZE(SomeParser); }; @@ -159,14 +148,54 @@ namespace senf { 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::UInt8Parser and so on. - It is customary, to hide the variant parser (by defining it private) and provide more - conveniently named accessors. + The \a types parameter specifies the types of sub-objects supported by this variant + parser. This parameter is a (Boost.Preprocessor style) sequence +
(\a type) (\a type) ...
+ of parser types with additional optional information: + + + + + + + + + + +
\a typeDo not provide accessor and use the 0-based type index as + key.
\c id(\a name, \a type)Automatically create an accessor \a name for this + type
\c novalue(\a name, \a type)This is like \c id but only provides an + initializer called \a name and no accessor
\c key(\a value, \a type)Use \a value to identity this type. The type is + selected, when the \a chooser is equal to \a value
\c id(\a name, \c key(\a value, \a type))
\c novalue(\a name, \c key(\a value, + \a type))
The options may be nested in this way.
+ + It is customary, to hide the variant parser (by defining it private) and provide + more conveniently named accessors. In above example, these accessors are automatically + generated using the id's given. The exact members defined are: + + + + + + + + + +
\a name \c _tThe type for this specific variant value if not \c + novalue.
name_t name()Return the variant value at this id + if not \c novalue.
void init_name()Set the variant to have a value + of this type. If the field is \c novalue, the \c init_ prefix is omitted.
bool has_name()Return \c true, if the variant + currently holds this kind of value, \c false otherwise. Only if not \c novalue.
+ + If \a value keys are given, they designate the value to expect in the \a chooser field to + select a specific variant type. If the \a chooser value does not match any key, the variant + will be initialized to the \e first type. Further additional tags are supported which modify the way, the \a chooser field is interpreted: -
\c transform(\a transform, \a size)The \a transform is applied to the \a +
\c transform(\a transform, \a chooser)The \a transform is applied to the \a chooser value, the value is not used directly
@@ -179,12 +208,12 @@ namespace senf { static value_type get(other_type v); static other_type set(value_type v); }; - \endcode \c other_type is the \a chooser ::\c value_type where as the \c value_type typedef + \endcode \c other_type is the \a chooser ::\c value_type whereas the \c value_type typedef is the arbitrary return type of the transform. The tags are applied to the \a chooser parameter: \code - SENF_PARSER_VARIANT ( content, transform(MyTransform, type_), + SENF_PARSER_VARIANT ( content, transform(MyTransform, type), (senf::VoidPacketParser) (senf::UInt8Parser) (senf::UInt16Parser) diff --git a/Packets/VariantParser.ih b/Packets/VariantParser.ih index 5a85944..fa8acdc 100644 --- a/Packets/VariantParser.ih +++ b/Packets/VariantParser.ih @@ -122,6 +122,7 @@ namespace detail { # define SENF_PARSER_VARIANT_I(access, name, chooser, types) \ SENF_PARSER_REQUIRE_VAR(variant) \ + private: \ 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 \ @@ -133,6 +134,7 @@ namespace detail { typedef senf::detail::VariantParserTraits< BOOST_PP_CAT(name, _parsers), \ BOOST_PP_CAT(name, _transform) > \ BOOST_PP_CAT(name, _traits); \ + public: \ SENF_PARSER_COLLECTION_I( \ access, name, chooser, BOOST_PP_CAT(name, _traits) ); \ BOOST_PP_SEQ_FOR_EACH_I(SENF_PARSER_VARIANT_ACCESSOR, name, types) @@ -142,6 +144,7 @@ namespace detail { template \ struct BOOST_PP_CAT(name, _key_value_template) \ : public senf::detail::VariantKey {}; \ + template friend class senf::detail::VariantKey; \ typedef senf::detail::VariantKeyTransform< \ BOOST_PP_CAT(name,_chooser_value_type), \ boost::mpl::vector< \ @@ -175,15 +178,17 @@ namespace detail { 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)() \ + typedef SENF_PARSER_VARIANT_GETTYPE(elem) \ + BOOST_PP_CAT(SENF_PARSER_VARIANT_GETID(elem), _t); \ + SENF_PARSER_VARIANT_GETTYPE(elem) SENF_PARSER_VARIANT_GETID(elem)() const \ { return name().get(); } \ - void BOOST_PP_CAT(init_, SENF_PARSER_VARIANT_GETID(elem))() \ + void BOOST_PP_CAT(init_, SENF_PARSER_VARIANT_GETID(elem))() const \ { name().init(); } \ - bool BOOST_PP_CAT(has_, SENF_PARSER_VARIANT_GETID(elem))() \ + bool BOOST_PP_CAT(has_, SENF_PARSER_VARIANT_GETID(elem))() const \ { return name().variant() == i; } # define SENF_PARSER_VARIANT_MAKENVACCESSOR(name, i, elem) \ - void SENF_PARSER_VARIANT_GETID(elem)() \ + void SENF_PARSER_VARIANT_GETID(elem)() const \ { name().init(); } # define SENF_PARSER_VARIANT_KEY_GOBBLE__key(key, type)