Packets: Add some public/private commands to parser helper macros
g0dil [Wed, 11 Jun 2008 13:28:56 +0000 (13:28 +0000)]
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

Packets/ParseHelpers.dox [new file with mode: 0644]
Packets/ParseHelpers.ih
Packets/VariantParser.hh
Packets/VariantParser.ih

diff --git a/Packets/ParseHelpers.dox b/Packets/ParseHelpers.dox
new file mode 100644 (file)
index 0000000..c0c7981
--- /dev/null
@@ -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 <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:
index 31f0984..02520f5 100644 (file)
 # 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_*
index 1887cd9..8516a9f 100644 (file)
@@ -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)
index 5a85944..fa8acdc 100644 (file)
@@ -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)