Added possibility to declare union in config file 86/30886/9
authorMateusz Malicki <m.malicki2@samsung.com>
Wed, 26 Nov 2014 14:11:51 +0000 (15:11 +0100)
committerMateusz Malicki <m.malicki2@samsung.com>
Thu, 27 Nov 2014 16:33:04 +0000 (17:33 +0100)
[Bug/Feature]   Possibility to declare something like union in config file
[Cause]         Necessity to create vector with element of more than one type
[Solution]      Added macro CONFIG_DECLARE_OPTIONS
[Verification]  Build, install, run scs tests

Change-Id: I094eb63f5cda6435836b3d76674d3cad5f89fe14

src/config/fields-union.hpp [new file with mode: 0644]

diff --git a/src/config/fields-union.hpp b/src/config/fields-union.hpp
new file mode 100644 (file)
index 0000000..8f4d997
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Mateusz Malicki (m.malicki2@samsung.com)
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Mateusz Malicki (m.malicki2@samsung.com)
+ * @brief   Macros for declare configuration fields
+ */
+
+#ifndef CONFIG_FIELDS_UNION_HPP
+#define CONFIG_FIELDS_UNION_HPP
+
+#include "config/fields.hpp"
+#include <memory>
+#include <cassert>
+
+/**
+ * Use this macro to declare and register config fields
+ *
+ * Example:
+ *  struct Foo {
+ *      std::string bar;
+ *
+ *      CONFIG_REGISTER
+ *      (
+ *          bar,
+ *      )
+ *  };
+ *
+ *  struct Config
+ *  {
+ *      CONFIG_DECLARE_UNION
+ *      (
+ *          Foo,
+ *          int
+ *      )
+ *  };
+ *
+ *  Example of valid configuration:
+ *   1. {
+ *        "type": "Foo",
+ *        "value": { "bar": "some string" }
+ *      }
+ *   2. {
+ *        "type": "int",
+ *        "value": 1
+ *      }
+ *
+ *
+ *  Usage:
+ *   Config config;
+ *   if (config.is<Foo>()) {
+ *       Foo& foo = config.as<Foo>();
+ *       // ...
+ *   }
+ *   if (config.is<int>())) {
+ *       int field = config.as<int>();
+ *       // ...
+ *   }
+ */
+
+
+#define CONFIG_DECLARE_UNION(...)                                                               \
+    struct TypeWrapperBase                                                                      \
+    {                                                                                           \
+        virtual ~TypeWrapperBase() {}                                                           \
+    };                                                                                          \
+                                                                                                \
+    template<typename Class>                                                                    \
+    struct TypeWrapper : TypeWrapperBase                                                        \
+    {                                                                                           \
+        Class value;                                                                            \
+        ~TypeWrapper() {}                                                                       \
+    };                                                                                          \
+                                                                                                \
+    std::unique_ptr<TypeWrapperBase> mConfigDeclareField__;                                     \
+                                                                                                \
+    template<typename Visitor>                                                                  \
+    void accept(Visitor v) {                                                                    \
+        std::string name;                                                                       \
+        v.visit("type", name);                                                                  \
+        visitOption(v, name);                                                                   \
+    }                                                                                           \
+                                                                                                \
+    template<typename Visitor>                                                                  \
+    void accept(Visitor v) const {                                                              \
+        const std::string name = getOptionName();                                               \
+        if (!name.empty()) {                                                                    \
+            v.visit("type", name);                                                              \
+            visitOption(v, name);                                                               \
+        } else {                                                                                \
+           /* Unsupported type in config file */                                                \
+        }                                                                                       \
+    }                                                                                           \
+                                                                                                \
+    template<typename Visitor>                                                                  \
+    void visitOption(Visitor& v, const std::string& name) {                                     \
+        GENERATE_CODE(GENERATE_UNION_VISIT__, __VA_ARGS__)                                      \
+    }                                                                                           \
+    template<typename Visitor>                                                                  \
+    void visitOption(Visitor& v, const std::string& name) const {                               \
+        GENERATE_CODE(GENERATE_UNION_VISIT_CONST__, __VA_ARGS__)                                \
+    }                                                                                           \
+    std::string getOptionName() const {                                                         \
+        GENERATE_CODE(GENERATE_UNION_NAME__, __VA_ARGS__)                                       \
+        return std::string();                                                                   \
+    }                                                                                           \
+                                                                                                \
+    template<typename Type>                                                                     \
+    bool is() const {                                                                           \
+        return dynamic_cast<TypeWrapper<Type>*>(mConfigDeclareField__.get()) != NULL;           \
+    }                                                                                           \
+    template<typename Type>                                                                     \
+    Type& as() {                                                                                \
+        assert(mConfigDeclareField__.get());                                                    \
+        return dynamic_cast<TypeWrapper<Type>&>(*mConfigDeclareField__.get()).value;            \
+    }                                                                                           \
+    template<typename Type>                                                                     \
+    const Type& as() const {                                                                    \
+        assert(mConfigDeclareField__.get());                                                    \
+        return dynamic_cast<const TypeWrapper<Type>&>(*mConfigDeclareField__.get()).value;      \
+    }
+
+#define GENERATE_CODE(MACRO, ...)                                                               \
+    BOOST_PP_LIST_FOR_EACH(MACRO, _, BOOST_PP_VARIADIC_TO_LIST(__VA_ARGS__))
+
+#define GENERATE_UNION_VISIT__(r, _, TYPE_)                                                     \
+    if (#TYPE_ == name) {                                                                       \
+        mConfigDeclareField__.reset(new TypeWrapper<TYPE_>());                                  \
+        v.visit("value", as<TYPE_>());                                                          \
+    }
+
+#define GENERATE_UNION_VISIT_CONST__(r, _, TYPE_)                                               \
+    if (#TYPE_ == name) {                                                                       \
+        v.visit("value", as<TYPE_>());                                                          \
+    }
+
+#define GENERATE_UNION_NAME__(r, _, TYPE_)                                                      \
+    if (is<TYPE_>()) {                                                                          \
+        return #TYPE_;                                                                          \
+    }
+
+#endif /* CONFIG_FIELDS_UNION_HPP */