Dev for variant
[profile/ivi/common-api-dbus-runtime.git] / src / test / DBusVariantTest.cpp
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 #include <iostream>
5 #include <string>
6 #include <tuple>
7 #include <type_traits>
8 #include <cassert>
9
10 template<class Visitor, class Variant, typename ... Ts>
11 struct apply_void_visitor;
12
13 template<class Visitor, class Variant>
14 struct apply_void_visitor<Visitor, Variant> {
15         static const unsigned int index = 0;
16
17         static
18         void visit(Visitor&, Variant&) {
19                 //won't be called
20                 assert(false);
21                 throw "";
22         }
23 };
24
25 template<class Visitor, class Variant, typename T, typename ... Ts>
26 struct apply_void_visitor<Visitor, Variant, T, Ts...> {
27         static const unsigned int index = apply_void_visitor<Visitor, Variant,
28                         Ts...>::index + 1;
29
30         static
31         void visit(Visitor& visitor, Variant& var) {
32                 if (var.getValueType() == index) {
33                         bool b;
34                         visitor(var.template get<T>(b));
35                 } else {
36                         apply_void_visitor<Visitor, Variant, Ts...>::visit(visitor,     var);
37                 }
38         }
39 };
40
41 /*template<typename ... Ts>
42 struct assign_visitor {
43 public:
44         assign_visitor(Variant<Ts...>& lhs, const bool clear = true) :
45                         lhs_(lhs), clear_(clear) {
46         }
47
48         template<typename T>
49         void operator()(const T& value) const {
50                 lhs_.template set<T>(value, clear_);
51         }
52
53         template<typename T>
54         void operator()(T& value) const {
55                 lhs_.template set<T>(value, clear_);
56         }
57
58 private:
59         Variant<Ts...>& lhs_;
60         const bool clear_;
61 };*/
62
63 template<unsigned int size>
64 struct clear_visitor {
65 public:
66         clear_visitor(typename std::aligned_storage<size>::type& storage) :
67                         storage_(storage) {
68         }
69
70         template<typename _Type>
71         void operator()(const _Type&) const {
72                 (reinterpret_cast<const _Type *>(&storage_))->~_Type();
73         }
74
75         private:
76         typename std::aligned_storage<size>::type& storage_;
77 };
78
79 template<typename U, typename ... Ts>
80 struct select_type;
81
82 template<typename U>
83 struct select_type<U> {
84 };
85
86 //U == T
87 template<typename T, typename ... Ts>
88 struct select_type<T, T, Ts...> {
89         typedef T type;
90 };
91
92 //U& == T
93 template<typename T, typename ... Ts>
94 struct select_type<T, T&, Ts...> {
95         typedef T& type;
96 };
97
98 //U == T&
99 template<typename T, typename ... Ts>
100 struct select_type<T&, T, Ts...> {
101         typedef T type;
102 };
103
104 //const U& == T
105 template<typename T, typename ... Ts>
106 struct select_type<T, const T&, Ts...> {
107         typedef const T& type;
108 };
109
110 //U == const T&
111 template<typename T, typename ... Ts>
112 struct select_type<const T&, T, Ts...> {
113         typedef T type;
114 };
115
116 //U == X*
117 //T == const X*
118 template<typename T, typename ... Ts>
119 struct select_type<T*, const T*, Ts...> {
120         typedef const T* type;
121 };
122
123 //U == X&
124 //T == const X&
125 template<typename T, typename ... Ts>
126 struct select_type<T&, const T&, Ts...> {
127         typedef const T& type;
128 };
129
130 //U != T, let's try to find U among Ts
131 template<typename U, typename T, typename ... Ts>
132 struct select_type<U, T, Ts...> {
133         typedef typename select_type<U, Ts...>::type type;
134 };
135
136 template<typename ... Ts>
137 struct type_index_getter;
138
139 template<>
140 struct type_index_getter<> {
141         static const unsigned int index = 0;
142
143         template<typename U>
144         static
145         unsigned int get() {
146                 return 0;
147         }
148 };
149
150 template<typename T, typename ... Ts>
151 struct type_index_getter<T, Ts...> {
152         static const unsigned int index = type_index_getter<Ts...>::index + 1;
153
154         template<typename U>
155         static
156         unsigned int get(
157                         typename std::enable_if<std::is_same<T, U>::value >::type* = 0) {
158                 return index;
159         }
160
161         template<typename U>
162         static
163         unsigned int get(typename std::enable_if<!std::is_same<T, U>::value >::type* = 0) {
164                 return type_index_getter<Ts...>::template get<U>();
165         }
166 };
167
168 template<typename ... Ts>
169 struct max_size;
170
171 template<>
172 struct max_size<> {
173         static const unsigned int value = 0;
174 };
175
176 template<typename T, typename ... Ts>
177 struct max_size<T, Ts...> {
178         static const unsigned int current_type_size = sizeof(T);
179         static const unsigned int next_type_size = max_size<Ts...>::value;
180         static const unsigned int value =
181                         current_type_size > next_type_size ?
182                                         current_type_size : next_type_size;
183 };
184
185 template<typename _SearchType, typename _CurrentType, typename ... _RestTypes>
186 struct VariantTypeSelector: VariantTypeSelector<_SearchType, _RestTypes...> {
187 };
188
189 template <typename _SearchType, typename... _RestTypes>
190 struct VariantTypeSelector<_SearchType, _SearchType, _RestTypes...> {
191     typedef _SearchType type;
192 };
193
194 template <typename... _Types>
195 class Variant {
196  private:
197     typedef std::tuple_size<std::tuple<_Types...>> TypesTupleSize;
198
199  public:
200
201     static const unsigned int maxSize = max_size<_Types...>::value;
202
203
204     Variant(): valueType_(TypesTupleSize::value) {
205     }
206
207     Variant(const Variant& fromVariant):
208         valueType_(fromVariant.valueType_),
209         valueStorage_(fromVariant.valueStorage_) {
210     }
211
212     Variant(Variant&& fromVariant):
213         valueType_(std::move(fromVariant.valueType_)),
214         valueStorage_(std::move(fromVariant.valueStorage_)) {
215         fromVariant.valueType_ = TypesTupleSize::value;
216     }
217
218     ~Variant() {
219         if (hasValue()) {
220             clear_visitor<maxSize> visitor(valueStorage_);
221             apply_void_visitor<clear_visitor<maxSize>, Variant<_Types...>, _Types...>::visit(visitor, *this);
222         }
223     }
224
225     Variant& operator=(const Variant& fromVariant) {
226         // TODO
227         return *this;
228     }
229
230     Variant& operator=(Variant&& fromVariant) {
231         // TODO
232         return *this;
233     }
234
235     template <typename _Type>
236         const bool& isType() const {
237                 typedef typename select_type<_Type, _Types...>::type selected_type_t;
238                 unsigned int cType = type_index_getter<_Types...>::template get<selected_type_t>();
239                 if(cType == valueType_) {
240                         return true;
241                 } else {
242                         return false;
243                 }
244         }
245
246     // TODO use std::enable_if
247     template <typename _Type>
248     Variant(const _Type& value) {
249         typedef typename select_type<_Type, _Types...>::type selected_type_t;
250         valueType_ = type_index_getter<_Types...>::template get<selected_type_t>();
251         new (&valueStorage_) _Type(value);
252     }
253
254     // TODO use std::enable_if
255     template <typename _Type>
256     Variant(_Type && value) {
257         typedef typename select_type<_Type, _Types...>::type selected_type_t;
258         valueType_ = type_index_getter<_Types...>::template get<selected_type_t>();
259         new (&valueStorage_) typename std::remove_reference<_Type>::type(std::move(value));
260     }
261
262         template <typename _Type>
263         const typename VariantTypeSelector<_Type, _Types...>::type & get(bool& success) const {
264                 typedef typename select_type<_Type, _Types...>::type selected_type_t;
265                 unsigned int cType = type_index_getter<_Types...>::template get<selected_type_t>();
266                 if(cType == valueType_) {
267                         success = true;
268                         return *(reinterpret_cast<const _Type *>(&valueStorage_));
269                 } else {
270                         success = false;
271                         //TODO: Fix return temporary
272                         return _Type();
273                 }
274         }
275
276         inline size_t getValueType() {
277                 return valueType_;
278         }
279
280         template<typename U>
281         void set( const U& value, const bool clear)     {
282                 typedef typename select_type<U, _Types...>::type selected_type_t;
283
284                 const selected_type_t& type_value = value;
285                 if(hasValue()) {
286                         clear_visitor<maxSize> visitor(valueStorage_);
287                         apply_void_visitor<clear_visitor<maxSize>, Variant<_Types...>, _Types...>::visit(visitor, *this);
288                 }
289                 new (&valueStorage_) selected_type_t(std::move(value));
290                 valueType_ = type_index_getter<_Types...>::template get<selected_type_t>();
291         }
292
293  private:
294     inline bool hasValue() const {
295         return valueType_ < TypesTupleSize::value;
296     }
297
298     size_t valueType_;
299     typename std::aligned_storage<maxSize>::type valueStorage_;
300
301 };
302
303
304
305 int main(int argc, char** argv) {
306     int fromInt = 5;
307     double fromDouble = 12.344d;
308     std::string fromString = "123abc!";
309     Variant<int, double, double, std::string> myVariant(fromInt);
310     Variant<int, double, double, std::string> myVariantf(fromDouble);
311
312     Variant<int, double, double, std::string>* myVariants = new Variant<int, double, double, std::string>(fromString);
313     bool success;
314
315     const int& myInt = myVariant.get<int>(success);
316     std::cout << "myInt = " << myInt << " (" << std::boolalpha << success << ")\n";
317
318     const int& myFake = myVariant.get<double>(success);
319     std::cout << "myFake = " << myFake << " (" << std::boolalpha << success << ")\n";
320
321     std::cout << "myInt is int = " << " (" << std::boolalpha << myVariant.isType<int>() << ")\n";
322     std::cout << "myInt is std::string = " << " (" << std::boolalpha << myVariant.isType<std::string>() << ")\n";
323
324     const int& myDouble = myVariantf.get<double>(success);
325     std::cout << "myDouble = " << myDouble << " (" << std::boolalpha << success << ")\n";
326
327     const std::string& myString = myVariants->get<std::string>(success);
328     std::cout << "myString = " << myString << " (" << std::boolalpha << success << ")\n";
329
330     delete myVariants;
331
332     return 0;
333 }