Packets: Fix VariantParser invalid parser access bug
[senf.git] / Packets / VariantParser.hh
index bd3e914..17b0ca4 100644 (file)
 /** \file
     \brief VariantParser public header */
 
-#ifndef HH_VariantParser_
-#define HH_VariantParser_ 1
+#ifndef HH_SENF_Packets_VariantParser_
+#define HH_SENF_Packets_VariantParser_ 1
 
-#ifndef HH_Packets_
+#ifndef HH_SENF_Packets_Packets_
 #error "Don't include 'VariantParser.hh' directly, include 'Packets.hh'"
 #endif
 
@@ -39,7 +39,6 @@
 #include "PacketParser.hh"
 
 //#include "VariantParser.mpp"
-#include "VariantParser.ih"
 ///////////////////////////////hh.p////////////////////////////////////////
 
 namespace senf {
@@ -62,8 +61,8 @@ namespace senf {
         packet change depending on some condition.
         \code
         typedef senf::VariantParser< 
-            MyVariantPolicy, 
-            senf::VoidPacketParser, TypeAParser, TypeBParser> MyVariantParser;
+            MyAuxPolicy, 
+            senf::mpl::vector<senf::VoidPacketParser, TypeAParser, TypeBParser> > MyVariantParser;
         \endcode
         This typedef defines a variant parser choosing one of three sub
         parsers. senf::VoidPacketParser is an empty parser, it effectively makes this parser
@@ -73,28 +72,29 @@ namespace senf {
         initialized to the first sub-parser.
 
         \see 
-            ExampleVariantPolicy on how to implement the \a VariantPolicy \n
+            ExampleAuxPolicy on how to implement the \a AuxPolicy \n
             \ref SENF_PARSER_VARIANT() on how to integrate the parser into another parser
         \ingroup parsecollection
      */
-    template <class VariantPolicy, SENF_PARSE_VARIANT_TPL_ARGS_DFL(class P)>
+    template <class AuxPolicy, class Parsers>
     class VariantParser 
-        : public PacketParserBase, private VariantPolicy
+        : public PacketParserBase, private AuxPolicy
     {
-        typedef boost::mpl::vector< SENF_PARSE_VARIANT_TPL_ARGS(P) > parsers;
+        typedef Parsers parsers;
 
     public:
         ///\name Parser interface
         ///\{
 
         VariantParser(data_iterator i, state_type s);
-        VariantParser(VariantPolicy policy, data_iterator i, state_type s);
+        VariantParser(AuxPolicy policy, data_iterator i, state_type s);
 
         size_type bytes() const;
         void init();
         
-        static const size_type init_bytes = 
-            senf::init_bytes<P0>::value + VariantPolicy::init_bytes;
+        static const size_type init_bytes = senf::init_bytes< 
+            typename boost::mpl::at<parsers, boost::mpl::int_<0> >::type>::value 
+                + AuxPolicy::aux_bytes;
 
         ///\}
         ///////////////////////////////////////////////////////////////////////////
@@ -123,169 +123,142 @@ namespace senf {
                                              \post variant() == \a N */
     };
 
-    /** \brief Variant with direct, fixed distance type field
-        
-        This struct is a template typedef defining a senf::Parser_Variant instantiation. It defines
-        a variant parser which interprets the value returned by some other parser directly as index
-        into the list of sub parsers (the numeric template argument to senf::VariantParser::get()
-        and senf::Parser_Variant::init()).
+    /** \brief Define VariantParser field
 
+        This macro is a special helper to define a senf::VariantParser type field.
         \code
-            // Define a variant choosing between FooParser and BarParser depending on the directly
-            // preceding 1-byte 8bit uint value
-            typedef senf::DirectVariantParser< senf::UInt8Parser, 1u, 
-                                                FooParser, BarParser >::parser MyVariant;
-        \endcode
+        struct SomeParser : public PacketParserBase
+        {
+        #   include SENF_PARSER()
+        
+            SENF_PARSER_PRIVATE_FIELD( type, senf::UInt8Parser );
+            SENF_PARSER_VARIANT( content, type,
+                                    (novalue( disable,      senf::VoidPacketParser ))
+                                    (     id( uint8value,   senf::UInt8Parser      ))
+                                    (     id( uint16value,  senf::UInt16Parser     ))
+                                    (     id( uint24value,  senf::UInt24Parser     ))
+                                    (     id( uint32value,  senf::UInt32Parser     )) );
 
-        \a ChooserType defines the type of the field used to choose the sub parser. This must be a
-        fixed-size value parser. \a Distance gives the \e fixed distance of this field \e before the
-        currently defined field.
+            SENF_PARSER_FINALIZE(SomeParser);
+        };
+        \endcode 
+            
+        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 best to define a field of this type using \ref SENF_PARSER_VARIANT() or \ref
-        SENF_PARSER_PRIVATE_VARIANT().
+        \warning Realize, that the \a chooser field is controlled by the variant parser. This field
+            should therefore be declared either read-only or private and must be changed only via
+            the variant parser.
 
-        \param[in] ChooserType type of chooser field (a value parser)
-        \param[in] Distance    fixed distance of the chooser field before the current field
-        \param[in] P           any number of sub parsers
+        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:
 
-        \see senf::Parser_Variant
-        \ingroup parsecollection
-     */
-    template <class ChooserType, unsigned Distance, class Translator,
-              SENF_PARSE_VARIANT_TPL_ARGS_DFL(class P)>
-    struct DirectVariantParser
-    {
-        typedef VariantParser< detail::DirectVariantParser<ChooserType, Distance, Translator>,
-                               SENF_PARSE_VARIANT_TPL_ARGS(P) > parser;
-    };
+        <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>
 
-    /** \brief Define DirectVariantParser field
+        <tr><td>\c id(\a name, \a type)</td><td>Automatically create an accessor \a name, a test
+        function <tt>has_</tt>\a name and a function to switch to this type <tt>init_</tt>\a name
+        for this type. Identical to \c ids(\a name, <tt>has_</tt>\a name, <tt>init_</tt>\a name, \a
+        type)</td></tr>
 
-        This macro is a special helper to define a senf::DirectVariantParser type field. This is a
-        variant field which chooses the sub-type by directly taking the value of some other field.
+        <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. Identical to \c ids(\c na, \c na, \a name, \a
+        type)</td></tr>
 
-        \warning
-          This is a dynamically sized parser. Nevertheless, the chooser field \e must have a
-          \e fixed distance to this field, the \a chooser must be a fixed-size value parser.
+        <tr><td>\c ids(\a accessorId, \a testId, \a initId, \a type)</td><td>This is again like \c
+        id but the names of the accessor, test function and init function are given
+        explicitly. Setting any of the id's to \c na will disable that function.</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>
+
+        Whenever an id is specified for any type, the variant itself will automatically be made
+        private so the only access to the variant from the outside is via the accessors.
+
+        The functions defined by specifying an id are:
+
+        <table class="senf fixedcolumn">
+        <tr><td><em>name</em><tt>_t</tt></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 \c key specs 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 chooser)</td><td>The \a transform is applied to the \a
+        chooser value, the value is not used directly</td>
+        </table>
+
+        The optional \a transform is a class with the following layout
 
         \code
-        struct SomeParser : public PacketParserBase
+        struct MyTransform
         {
-        #   include SENF_PARSER()
-        
-            SENF_PARSER_PRIVATE_FIELD( type, senf::UInt8Parser );
-            SENF_PARSER_PRIVATE_VARIANT( content, type,
+            typedef ... value_type;
+            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 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::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>(); }
-
-            SENF_PARSER_FINALIZE(SomeParser);
-        };
         \endcode
-
-        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.
-
+        
         \param[in] name name of the field
         \param[in] chooser name of the field choosing the variant to use
         \param[in] types a Boost.Preprocessor style sequence of sub-parser types
 
         \see 
-            senf::VariantParser \n 
+            senf::VariantParser for the VariantParser API\n 
             \ref SENF_PARSER_PRIVATE_VARIANT()
         \hideinitializer
         \ingroup packetparsermacros
      */
-#   define SENF_PARSER_VARIANT(name, chooser, types)                                              \
-        SENF_PARSER_VARIANT_I(SENF_PARSER_FIELD,                                                  \
-                              name,                                                               \
-                              chooser,                                                            \
-                              senf::detail::VariantParser_IdentityTranslator,                     \
-                              types)
-
-    /** \brief Define DirectVariantParser field (private)
-        
-        \see \ref SENF_PARSER_VARIANT()
-        \hideinitializer
-        \ingroup packetparsermacros
-     */
-#   define SENF_PARSER_PRIVATE_VARIANT(name, chooser, types)                                      \
-        SENF_PARSER_VARIANT_I(SENF_PARSER_PRIVATE_FIELD,                                          \
-                              name,                                                               \
-                              chooser,                                                            \
-                              senf::detail::VariantParser_IdentityTranslator,                     \
-                              types)
-
-    /** \brief Define DirectVariantParser field with translator
-        
-        This is like \ref SENF_PARSER_VARIANT(), however it allows to specify a \a translator
-        argument which translates between \a chooser values and type indices:
-        \code
-        struct SomeTranslator {
-            static unsigned fromChooser(chooser_field_t::value_type value) {
-                switch (value) {
-                case 1  : return 0 ;
-                case 5  : return 1 ;
-                default : return 2 ;
-                }
-            }
-            static chooser_field_t::value_type toChooser(unsigned value) {
-                static chooser_field_t::value_type table[] const = { 1, 5, 0 };
-                return table[value];
-            }
-        };
-        \endcode
-        The \a translator class must have two publicly accessible static members, \c fromChooser and
-        \c toChooser. \c fromChooser takes the value as returned by the \a chooser field and must
-        return the corresponding class index whereas \c toChooser takes the class index and must
-        return the value to write into the \a chooser field.
+#   define SENF_PARSER_VARIANT(name, chooser, types) \
+        SENF_PARSER_VARIANT_I(public, name, chooser, types)
 
-        \see \ref SENF_PARSER_VARIANT()
-        \hideinitializer
-        \ingroup packetparsermacros
-     */
-#   define SENF_PARSER_VARIANT_TRANS(name, chooser, translator, types)                            \
-        SENF_PARSER_VARIANT_I(SENF_PARSER_FIELD,                                                  \
-                              name,                                                               \
-                              chooser,                                                            \
-                              translator,                                                         \
-                              types)
-
-    /** \brief Define DirectVariantParser field with translator (private)
+    /** \brief Define private VariantParser field
         
-        \see \ref SENF_PARSER_VARIANT_TRANS()
+        \see \ref SENF_PARSER_VARIANT()
         \hideinitializer
         \ingroup packetparsermacros
      */
-#   define SENF_PARSER_PRIVATE_VARIANT_TRANS(name, chooser, types)                                \
-        SENF_PARSER_VARIANT_I(SENF_PARSER_PRIVATE_FIELD,                                          \
-                              name,                                                               \
-                              chooser,                                                            \
-                              translator,                                                         \
-                              types)
-
+#   define SENF_PARSER_PRIVATE_VARIANT(name, chooser, types) \
+        SENF_PARSER_VARIANT_I(private, name, chooser, types)
 }
 
 ///////////////////////////////hh.e////////////////////////////////////////
 #endif
-#if !defined(HH_Packets__decls_) && !defined(HH_VariantParser_i_)
-#define HH_VariantParser_i_
+#if !defined(HH_SENF_Packets_Packets__decls_) && !defined(HH_SENF_Packets_VariantParser_i_)
+#define HH_SENF_Packets_VariantParser_i_
 //#include "VariantParser.cci"
 #include "VariantParser.ct"
 #include "VariantParser.cti"