Skip to content
Snippets Groups Projects
Commit d986f94d authored by g0dil's avatar g0dil
Browse files

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
parent eb7b97a3
No related branches found
No related tags found
No related merge requests found
// $Id$
//
// Copyright (C) 2008
// Fraunhofer Institute for Open Communication Systems (FOKUS)
// Competence Center NETwork research (NET), St. Augustin, GERMANY
// Stefan Bund <g0dil@berlios.de>
//
// 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, type_bit + 4> 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<type_index> *) const
{
init_chain (static_cast<senf::mpl::rv<type_index - 1> *>(0));
}
public:
size_type type_offset () const
{
return field_offset_(static_cast<senf::mpl::rv<type_index - 1> *>(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<type_index> *) 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_bit_t> (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 <senf::VoidPacketParser, SubParser> 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 <content__chooser_value_type (*KeyFn) ()>
struct content__key_value_template
: public senf::detail::VariantKey<content__chooser_value_type, KeyFn> {};
template <class T, T (*K)()> 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__parsers, content__transform>
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<content__aux_policy, senf::detail::auxtag::none>::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<content__index> *) const
{
init_chain (static_cast<senf::mpl::rv<content__index - 1> *>(0));
content_().init();
}
size_type content__offset() const
{
return field_offset_ (static_cast<senf::mpl::rv<content__index - 1> *>(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<content__collection_t>::value;
size_type field_offset_(senf::mpl::rv<content__index> *) 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<content__collection_t>::value ? 0 : 1);
SENF_MPL_SLOET_SET(group, content__group);
template < class T >
T content__dispatch (boost::true_type) const
{
return parse<T>(content__offset());
}
template < class T >
T content__dispatch (boost::false_type) const
{
return parse<T>(type(), content__offset());
}
content__t content__() const
{
return content__dispatch<content__t>(
boost::integral_constant<bool, content__aux_fixed>());
}
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<senf::mpl::rv<SENF_MPL_SLOT_GET(index)> *>(0));
}
TestParser(data_iterator i, state_type s)
: parser_base_type (i, s)
{}
private:
template <class T>
void init(T) const
{
defaultInit ();
}
public:
void init() const
{
init (0);
}
size_type bytes() const
{
return field_offset_(static_cast<senf::mpl::rv<SENF_MPL_SLOT_GET(index)> *>(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:
......@@ -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_*
......
......@@ -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
<pre>(\a type) (\a type) ...</pre>
of parser types with additional optional information:
<table class="senf fixedcolumn">
<tr><td>\a type</td><td>Do not provide accessor and use the 0-based type index as
key.</td></tr>
<tr><td>\c id(\a name, \a type)</td><td>Automatically create an accessor \a name for this
type</td></tr>
<tr><td>\c novalue(\a name, \a type)</td><td>This is like \c id but only provides an
initializer called \a name and no accessor</td></tr>
<tr><td>\c key(\a value, \a type)</td><td>Use \a value to identity this type. The type is
selected, when the \a chooser is equal to \a value</td></tr>
<tr><td>\c id(\a name, \c key(\a value, \a type))<br/>\c novalue(\a name, \c key(\a value,
\a type))</td><td>The options may be nested in this way.</td></tr> </table>
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:
<table class="senf fixedcolumn">
<tr><td>\a name \c _t</td><td>The type for this specific variant value if not \c
novalue.</td></tr>
<tr><td><em>name</em><tt>_t</tt> <em>name</em>()</td><td>Return the variant value at this id
if not \c novalue.</td></tr>
<tr><td><tt>void</tt> <tt>init_</tt><em>name</em>()</td><td>Set the variant to have a value
of this type. If the field is \c novalue, the \c init_ prefix is omitted.</td></tr>
<tr><td><tt>bool</tt> <tt>has_</tt><em>name</em>()</td><td>Return \c true, if the variant
currently holds this kind of value, \c false otherwise. Only if not \c novalue.</td></tr>
</table>
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:
<table class="senf fixedcolumn">
<tr><td>\c transform(\a transform, \a size)</td><td>The \a transform is applied to the \a
<tr><td>\c transform(\a transform, \a chooser)</td><td>The \a transform is applied to the \a
chooser value, the value is not used directly</td>
</table>
......@@ -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)
......
......@@ -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 <BOOST_PP_CAT(name, _chooser_value_type) (*KeyFn)()> \
struct BOOST_PP_CAT(name, _key_value_template) \
: public senf::detail::VariantKey<BOOST_PP_CAT(name, _chooser_value_type), KeyFn> {}; \
template <class T, T (*K)()> 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<i>(); } \
void BOOST_PP_CAT(init_, SENF_PARSER_VARIANT_GETID(elem))() \
void BOOST_PP_CAT(init_, SENF_PARSER_VARIANT_GETID(elem))() const \
{ name().init<i>(); } \
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<i>(); }
# define SENF_PARSER_VARIANT_KEY_GOBBLE__key(key, type)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment