Packets: Adjust SENF_PARSER_VARIANT implementation for better public/private support
[senf.git] / Packets / VariantParser.ih
index 053f4c8..79db6c7 100644 (file)
@@ -1,8 +1,8 @@
 // $Id$
 //
-// Copyright (C) 2007 
-// Fraunhofer Institute for Open Communication Systems (FOKUS) 
-// Competence Center NETwork research (NET), St. Augustin, GERMANY 
+// Copyright (C) 2007
+// 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
 
 // Custom includes
 #include "PacketParser.hh"
+#include <boost/preprocessor/cat.hpp>
+#include <boost/preprocessor/seq/enum.hpp>
+#include <boost/preprocessor/seq/fold_left.hpp>
+#include <boost/preprocessor/seq/for_each.hpp>
+#include <boost/preprocessor/logical/or.hpp>
+#include <boost/preprocessor/seq/for_each_i.hpp>
+#include <boost/preprocessor/logical/not.hpp>
+#include <boost/preprocessor/expr_if.hpp>
 
 ///////////////////////////////ih.p////////////////////////////////////////
 
 namespace senf {
 namespace detail {
 
-#   define SENF_PARSE_VARIANT_TPL_ARGS_DFL(n)                                                     \
-        BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT( SENF_LIMIT_PARSE_VARIANT,                            \
-                                             n,                                                   \
-                                             boost::mpl::na )
-
-#   define SENF_PARSE_VARIANT_TPL_ARGS(n) BOOST_PP_ENUM_PARAMS( SENF_LIMIT_PARSE_VARIANT, n )
-
-#   ifndef DOXYGEN
+#ifndef DOXYGEN
 
     template <class Variant, unsigned N>
     struct VariantBytes {
@@ -53,49 +54,242 @@ namespace detail {
         static PacketParserBase::size_type bytes(Variant const & v, unsigned n);
     };
 
-#   endif
-    
-    /** \brief Internal: Variant Policy used by senf::DirectVariantParser */
-    template <class ChooserType, unsigned Distance, class Translator>
-    struct DirectVariantParser
+    template <class Transform, class AuxPolicy, class AuxTag>
+    struct VariantParserPolicy;
+
+    template <class AuxPolicy, class AuxTag>
+    struct VariantParserPolicy<void, AuxPolicy, AuxTag>
+    {};
+
+    template <class Transform, class AuxPolicy, class AuxTag>
+    struct VariantParserPolicy
+        : public VariantParserPolicy< void, 
+                                      TransformAuxParserPolicy<AuxPolicy, Transform>, AuxTag >
+    {};
+
+    template <class AuxPolicy>
+    struct VariantParserPolicy<void, AuxPolicy, senf::detail::auxtag::none>
+    {
+        typedef AuxPolicy type;
+    };
+
+    template <class AuxPolicy, class Transform>
+    struct VariantParserPolicy<void,
+                               AuxPolicy, 
+                               senf::detail::auxtag::transform<Transform, 
+                                                               senf::detail::auxtag::none> >
+    {
+        typedef TransformAuxParserPolicy<AuxPolicy, Transform> type;
+    };
+
+    template <class Parsers, class Transform>
+    struct VariantParserTraits
+    {
+        template <class AuxPolicy, class AuxTag>
+        struct parser {
+            typedef senf::VariantParser<
+                typename VariantParserPolicy<Transform, AuxPolicy, AuxTag>::type,
+                Parsers> type;
+        };
+    };
+
+    template <class T, T (*KeyFn)()> 
+    struct VariantKey 
+    {
+        static T key() { return (*KeyFn)(); }
+    };
+
+    template <class T, class Keys>
+    struct VariantKeyTransform
+    {
+        typedef unsigned value_type;
+        typedef T input_type;
+        static unsigned get(input_type v);
+        static input_type set(unsigned v);
+    };
+
+    template <class In, class Out, class Keys, unsigned N>
+    struct VariantKeyTransformCheck
     {
-        typedef PacketParserBase::data_iterator data_iterator;
-        typedef PacketParserBase::state_type state_type;
-        typedef PacketParserBase::size_type size_type;
-
-        static size_type const init_bytes = 0;
-        size_type bytes(data_iterator i, state_type s) const { return 0; }
-        data_iterator begin(data_iterator i, state_type s) const { return i; }
-
-        ChooserType chooser(data_iterator i, state_type s) const {
-            return ChooserType(boost::prior(i, Distance),s);
-        }
-        
-        unsigned variant(data_iterator i, state_type s) const {
-            return Translator::fromChooser(chooser(i,s).value());
-        }
-
-        void variant(unsigned v, data_iterator i, state_type s) {
-            chooser(i,s).value(Translator::toChooser(v));
-        }
+        static Out get(In v);
+        static In set(Out v);
     };
 
-    /** \brief Internal: Identity chooser translator */
-    struct VariantParser_IdentityTranslator {
-        static unsigned fromChooser(unsigned value) { return value; }
-        static unsigned toChooser(unsigned value) { return value; }
+    template <class In, class Out, class Keys>
+    struct VariantKeyTransformCheck<In, Out, Keys, 0>
+    {
+        static Out get(In v);
+        static In set(Out v);
     };
+    
+#   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              \
+            BOOST_PP_CAT(name,_chooser_value_type);                                               \
+        BOOST_PP_IF( SENF_PARSER_VARIANT_NEEDTRANSFORM(types),                                    \
+                     SENF_PARSER_VARIANT_MAKETRANSFORM,                                           \
+                     SENF_PARSER_VARIANT_NOTRANSFORM )(name,                                      \
+                                                       types)                                     \
+        typedef senf::detail::VariantParserTraits< BOOST_PP_CAT(name, _parsers),                  \
+                                                   BOOST_PP_CAT(name, _transform) >               \
+            BOOST_PP_CAT(name, _traits);                                                          \
+    public:                                                                                       \
+        SENF_PARSER_COLLECTION_I(                                                                 \
+            BOOST_PP_IIF( SENF_PARSER_VARIANT_NEEDACCESSORS(types), private, access),             \
+            name, chooser, BOOST_PP_CAT(name, _traits) );                                         \
+    access:                                                                                       \
+        BOOST_PP_SEQ_FOR_EACH_I(SENF_PARSER_VARIANT_ACCESSOR, name, types)                        \
+    public:
+
+#   define SENF_PARSER_VARIANT_MAKETRANSFORM(name, types)                                         \
+        BOOST_PP_SEQ_FOR_EACH_I(SENF_PARSER_VARIANT_KEYVALUE, 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<                                                                   \
+                BOOST_PP_SEQ_ENUM(SENF_PARSER_VARIANT_KEYVALUES(name, types))                     \
+            > > BOOST_PP_CAT(name, _transform);
+
+#   define SENF_PARSER_VARIANT_KEYVALUE(r, name, i, elem)                                         \
+        static BOOST_PP_CAT(name, _chooser_value_type)                                            \
+            BOOST_PP_CAT(BOOST_PP_CAT(name, _key_),i)()                                           \
+                { return SENF_PARSER_VARIANT_GETKEY(elem, i); }
+
+#   define SENF_PARSER_VARIANT_NOTRANSFORM(name, types)                                           \
+        typedef void BOOST_PP_CAT(name, _transform);
+
+#   define SENF_PARSER_VARIANT_KEYVALUES(name, types)                                             \
+        BOOST_PP_SEQ_FOR_EACH_I(SENF_PARSER_VARIANT_KEYVALUES_, name, types)
+
+#   define SENF_PARSER_VARIANT_KEYVALUES_(r, name, i, elem)                                       \
+        (BOOST_PP_CAT(name,_key_value_template)<                                                  \
+             & BOOST_PP_CAT(BOOST_PP_CAT(name, _key_), i) >)
 
-#   define SENF_PARSER_VARIANT_(r, data, elem) ,elem
+#   define SENF_PARSER_VARIANT_ACCESSOR(r, name, i, elem)                                         \
+        BOOST_PP_IF( SENF_PARSER_VARIANT_HASID(elem),                                             \
+                     SENF_PARSER_VARIANT_MAKEACCESSOR,                                            \
+                     SENF_PARSER_VARIANT_NOACCESSOR )(name, i, elem)
 
-#   define SENF_PARSER_VARIANT_I(field, name, chooser, translator, types)                         \
-        typedef senf::DirectVariantParser<                                                       \
-            BOOST_PP_CAT(chooser, _t),                                                            \
-            SENF_PARSER_CURRENT_FIXED_OFFSET() - SENF_PARSER_FIXED_OFFSET(chooser),               \
-            translator                                                                            \
-            BOOST_PP_SEQ_FOR_EACH( SENF_PARSER_VARIANT_, _, types )                               \
-            >::parser BOOST_PP_CAT(name, _variant_t);                                             \
-        field( name, BOOST_PP_CAT(name, _variant_t) )
+#   define SENF_PARSER_VARIANT_NOACCESSOR(name, i, elem)
+#   define SENF_PARSER_VARIANT_MAKEACCESSOR(name, i, elem)                                        \
+        SENF_PARSER_VARIANT_MAKEACCESSOR_VALUE(name, i, elem, SENF_PARSER_VARIANT_GETID(elem))    \
+        SENF_PARSER_VARIANT_MAKEACCESSOR_HAS(name, i, elem, SENF_PARSER_VARIANT_GETHASID(elem))   \
+        SENF_PARSER_VARIANT_MAKEACCESSOR_INIT(name, i, elem, SENF_PARSER_VARIANT_GETINITID(elem))
+
+#   define SENF_PARSER_VARIANT_IFNOTNA(id, x)                                                     \
+        BOOST_PP_EXPR_IIF( BOOST_PP_NOT( SENF_PARSER_VARIANT_NA(id) ), x )
+    
+#   define SENF_PARSER_VARIANT_MAKEACCESSOR_VALUE(name, i, elem, id)                              \
+        SENF_PARSER_VARIANT_IFNOTNA( id,                                                          \
+            typedef SENF_PARSER_VARIANT_GETTYPE(elem)                                             \
+                BOOST_PP_CAT(id, _t);                                                             \
+            BOOST_PP_CAT(id, _t) id() const                                                       \
+                { return name().get<i>(); }                                                       \
+        )
+                                     
+#   define SENF_PARSER_VARIANT_MAKEACCESSOR_HAS(name, i, elem, id)                                \
+        SENF_PARSER_VARIANT_IFNOTNA( id,                                                          \
+            bool id() const                                                                       \
+                { return name().variant() == i; }                                                 \
+        )
+
+#   define SENF_PARSER_VARIANT_MAKEACCESSOR_INIT(name, i, elem, id)                               \
+        SENF_PARSER_VARIANT_IFNOTNA( id,                                                          \
+            void id() const                                                                       \
+            { name().init<i>(); }                                                                 \
+        )
+
+#   define SENF_PARSER_VARIANT_KEY_GOBBLE__key(key, type)
+#   define SENF_PARSER_VARIANT_KEY_GETKEY__key(key, type) key
+#   define SENF_PARSER_VARIANT_KEY_GETTYPE__key(key, type) type
+
+#   define SENF_PARSER_VARIANT_ID_GOBBLE__id(id, value)
+#   define SENF_PARSER_VARIANT_ID_GETID__id(id, value) id
+#   define SENF_PARSER_VARIANT_ID_GETVALUE__id(id, value) value
+#   define SENF_PARSER_VARIANT_ID_GETHASID__id(id, value) SENF_CAT_RECURS3(has_, id)
+#   define SENF_PARSER_VARIANT_ID_GETINITID__id(id, value) SENF_CAT_RECURS3(init_, id)
+
+#   define SENF_PARSER_VARIANT_ID_GOBBLE__novalue(id, value)
+#   define SENF_PARSER_VARIANT_ID_GETID__novalue(id, value) na
+#   define SENF_PARSER_VARIANT_ID_GETVALUE__novalue(id, value) value
+#   define SENF_PARSER_VARIANT_ID_GETHASID__novalue(id, value) na
+#   define SENF_PARSER_VARIANT_ID_GETINITID__novalue(id, value) id
+
+#   define SENF_PARSER_VARIANT_ID_GOBBLE__ids(id, hasid, initid, value)
+#   define SENF_PARSER_VARIANT_ID_GETID__ids(id, hasid, initid, value) id
+#   define SENF_PARSER_VARIANT_ID_GETVALUE__ids(id, hasid, initid, value) value
+#   define SENF_PARSER_VARIANT_ID_GETHASID__ids(id, hasid, initid, value) hasid
+#   define SENF_PARSER_VARIANT_ID_GETINITID__ids(id, hasid, initid, value) initid
+
+#   define SENF_PARSER_VARIANT_NA_GOBBLE__na
+
+#   define SENF_PARSER_VARIANT_NA(x)                                                              \
+        BOOST_PP_IS_EMPTY( SENF_CAT_RECURS1(SENF_PARSER_VARIANT_NA_GOBBLE__, x) )
+
+#   define SENF_PARSER_VARIANT_HASKEY(x)                                                          \
+        SENF_PARSER_VARIANT_HASKEY_( SENF_PARSER_VARIANT_GETVALUE(x) )
+
+#   define SENF_PARSER_VARIANT_HASKEY_(x)                                                         \
+        BOOST_PP_IS_EMPTY( SENF_CAT_RECURS1(SENF_PARSER_VARIANT_KEY_GOBBLE__, x) )
+
+#   define SENF_PARSER_VARIANT_GETKEY(x, default)                                                 \
+        SENF_PARSER_VARIANT_GETKEY_( SENF_PARSER_VARIANT_GETVALUE(x), default )
+
+#   define SENF_PARSER_VARIANT_GETKEY_(x, default)                                                \
+        BOOST_PP_IF( SENF_PARSER_VARIANT_HASKEY_(x),                                              \
+                     BOOST_PP_CAT(SENF_PARSER_VARIANT_KEY_GETKEY__, x),                           \
+                     default )
+
+#   define SENF_PARSER_VARIANT_HASID(x)                                                           \
+        BOOST_PP_IS_EMPTY( SENF_CAT_RECURS2(SENF_PARSER_VARIANT_ID_GOBBLE__, x) )
+
+#   define SENF_PARSER_VARIANT_GETID(x)                                                           \
+        BOOST_PP_CAT(SENF_PARSER_VARIANT_ID_GETID__, x)
+
+#   define SENF_PARSER_VARIANT_GETHASID(x)                                                        \
+        BOOST_PP_CAT(SENF_PARSER_VARIANT_ID_GETHASID__, x)
+
+#   define SENF_PARSER_VARIANT_GETINITID(x)                                                       \
+        BOOST_PP_CAT(SENF_PARSER_VARIANT_ID_GETINITID__, x)
+
+#   define SENF_PARSER_VARIANT_GETVALUE(x)                                                        \
+        BOOST_PP_IF( SENF_PARSER_VARIANT_HASID(x),                                                \
+                     BOOST_PP_CAT(SENF_PARSER_VARIANT_ID_GETVALUE__, x),                          \
+                     x )
+
+#   define SENF_PARSER_VARIANT_GETTYPE(x)                                                         \
+        SENF_PARSER_VARIANT_GETTYPE_( SENF_PARSER_VARIANT_GETVALUE(x) )
+
+#   define SENF_PARSER_VARIANT_GETTYPE_(x)                                                        \
+        BOOST_PP_IF( SENF_PARSER_VARIANT_HASKEY_(x),                                              \
+                     BOOST_PP_CAT(SENF_PARSER_VARIANT_KEY_GETTYPE__, x),                          \
+                     x )
+
+#   define SENF_PARSER_VARIANT_NEEDTRANSFORM(types)                                               \
+        BOOST_PP_SEQ_FOLD_LEFT(SENF_PARSER_VARIANT_NEEDTRANSFORM_, 0, types)
+
+#   define SENF_PARSER_VARIANT_NEEDTRANSFORM_(s, state, elem)                                     \
+        BOOST_PP_OR(state, SENF_PARSER_VARIANT_HASKEY(elem))
+
+#   define SENF_PARSER_VARIANT_NEEDACCESSORS(types)                                               \
+        BOOST_PP_SEQ_FOLD_LEFT(SENF_PARSER_VARIANT_NEEDACCESSORS_, 0, types)
+
+#   define SENF_PARSER_VARIANT_NEEDACCESSORS_(s, state, elem)                                     \
+        BOOST_PP_OR(state, SENF_PARSER_VARIANT_HASID(elem))
+
+#   define SENF_PARSER_VARIANT_TYPES(types)                                                       \
+        BOOST_PP_SEQ_FOR_EACH(SENF_PARSER_VARIANT_TYPES_, _, types)
+
+#   define SENF_PARSER_VARIANT_TYPES_(r, _, elem)                                                 \
+        (SENF_PARSER_VARIANT_GETTYPE(elem))
+
+#endif
 
 }}