--- /dev/null
+/*
+ * 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 */