--- /dev/null
+// $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
+ */
+
+\f
+// 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:
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);
};
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>
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)
# 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 \
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)
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< \
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)