Added possibility to declare union in config file
[archive/platform/core/system/libConfig.git] / src / config / fields-union.hpp
1 /*
2  *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Contact: Mateusz Malicki (m.malicki2@samsung.com)
5  *
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License
17  */
18
19 /**
20  * @file
21  * @author  Mateusz Malicki (m.malicki2@samsung.com)
22  * @brief   Macros for declare configuration fields
23  */
24
25 #ifndef CONFIG_FIELDS_UNION_HPP
26 #define CONFIG_FIELDS_UNION_HPP
27
28 #include "config/fields.hpp"
29 #include <memory>
30 #include <cassert>
31
32 /**
33  * Use this macro to declare and register config fields
34  *
35  * Example:
36  *  struct Foo {
37  *      std::string bar;
38  *
39  *      CONFIG_REGISTER
40  *      (
41  *          bar,
42  *      )
43  *  };
44  *
45  *  struct Config
46  *  {
47  *      CONFIG_DECLARE_UNION
48  *      (
49  *          Foo,
50  *          int
51  *      )
52  *  };
53  *
54  *  Example of valid configuration:
55  *   1. {
56  *        "type": "Foo",
57  *        "value": { "bar": "some string" }
58  *      }
59  *   2. {
60  *        "type": "int",
61  *        "value": 1
62  *      }
63  *
64  *
65  *  Usage:
66  *   Config config;
67  *   if (config.is<Foo>()) {
68  *       Foo& foo = config.as<Foo>();
69  *       // ...
70  *   }
71  *   if (config.is<int>())) {
72  *       int field = config.as<int>();
73  *       // ...
74  *   }
75  */
76
77
78 #define CONFIG_DECLARE_UNION(...)                                                               \
79     struct TypeWrapperBase                                                                      \
80     {                                                                                           \
81         virtual ~TypeWrapperBase() {}                                                           \
82     };                                                                                          \
83                                                                                                 \
84     template<typename Class>                                                                    \
85     struct TypeWrapper : TypeWrapperBase                                                        \
86     {                                                                                           \
87         Class value;                                                                            \
88         ~TypeWrapper() {}                                                                       \
89     };                                                                                          \
90                                                                                                 \
91     std::unique_ptr<TypeWrapperBase> mConfigDeclareField__;                                     \
92                                                                                                 \
93     template<typename Visitor>                                                                  \
94     void accept(Visitor v) {                                                                    \
95         std::string name;                                                                       \
96         v.visit("type", name);                                                                  \
97         visitOption(v, name);                                                                   \
98     }                                                                                           \
99                                                                                                 \
100     template<typename Visitor>                                                                  \
101     void accept(Visitor v) const {                                                              \
102         const std::string name = getOptionName();                                               \
103         if (!name.empty()) {                                                                    \
104             v.visit("type", name);                                                              \
105             visitOption(v, name);                                                               \
106         } else {                                                                                \
107            /* Unsupported type in config file */                                                \
108         }                                                                                       \
109     }                                                                                           \
110                                                                                                 \
111     template<typename Visitor>                                                                  \
112     void visitOption(Visitor& v, const std::string& name) {                                     \
113         GENERATE_CODE(GENERATE_UNION_VISIT__, __VA_ARGS__)                                      \
114     }                                                                                           \
115     template<typename Visitor>                                                                  \
116     void visitOption(Visitor& v, const std::string& name) const {                               \
117         GENERATE_CODE(GENERATE_UNION_VISIT_CONST__, __VA_ARGS__)                                \
118     }                                                                                           \
119     std::string getOptionName() const {                                                         \
120         GENERATE_CODE(GENERATE_UNION_NAME__, __VA_ARGS__)                                       \
121         return std::string();                                                                   \
122     }                                                                                           \
123                                                                                                 \
124     template<typename Type>                                                                     \
125     bool is() const {                                                                           \
126         return dynamic_cast<TypeWrapper<Type>*>(mConfigDeclareField__.get()) != NULL;           \
127     }                                                                                           \
128     template<typename Type>                                                                     \
129     Type& as() {                                                                                \
130         assert(mConfigDeclareField__.get());                                                    \
131         return dynamic_cast<TypeWrapper<Type>&>(*mConfigDeclareField__.get()).value;            \
132     }                                                                                           \
133     template<typename Type>                                                                     \
134     const Type& as() const {                                                                    \
135         assert(mConfigDeclareField__.get());                                                    \
136         return dynamic_cast<const TypeWrapper<Type>&>(*mConfigDeclareField__.get()).value;      \
137     }
138
139 #define GENERATE_CODE(MACRO, ...)                                                               \
140     BOOST_PP_LIST_FOR_EACH(MACRO, _, BOOST_PP_VARIADIC_TO_LIST(__VA_ARGS__))
141
142 #define GENERATE_UNION_VISIT__(r, _, TYPE_)                                                     \
143     if (#TYPE_ == name) {                                                                       \
144         mConfigDeclareField__.reset(new TypeWrapper<TYPE_>());                                  \
145         v.visit("value", as<TYPE_>());                                                          \
146     }
147
148 #define GENERATE_UNION_VISIT_CONST__(r, _, TYPE_)                                               \
149     if (#TYPE_ == name) {                                                                       \
150         v.visit("value", as<TYPE_>());                                                          \
151     }
152
153 #define GENERATE_UNION_NAME__(r, _, TYPE_)                                                      \
154     if (is<TYPE_>()) {                                                                          \
155         return #TYPE_;                                                                          \
156     }
157
158 #endif /* CONFIG_FIELDS_UNION_HPP */