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/. */
10 template<class Visitor, class Variant, typename ... Ts>
11 struct apply_void_visitor;
13 template<class Visitor, class Variant>
14 struct apply_void_visitor<Visitor, Variant> {
15 static const unsigned int index = 0;
18 void visit(Visitor&, Variant&) {
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,
31 void visit(Visitor& visitor, Variant& var) {
32 if (var.getValueType() == index) {
34 visitor(var.template get<T>(b));
36 apply_void_visitor<Visitor, Variant, Ts...>::visit(visitor, var);
41 /*template<typename ... Ts>
42 struct assign_visitor {
44 assign_visitor(Variant<Ts...>& lhs, const bool clear = true) :
45 lhs_(lhs), clear_(clear) {
49 void operator()(const T& value) const {
50 lhs_.template set<T>(value, clear_);
54 void operator()(T& value) const {
55 lhs_.template set<T>(value, clear_);
63 template<unsigned int size>
64 struct clear_visitor {
66 clear_visitor(typename std::aligned_storage<size>::type& storage) :
70 template<typename _Type>
71 void operator()(const _Type&) const {
72 (reinterpret_cast<const _Type *>(&storage_))->~_Type();
76 typename std::aligned_storage<size>::type& storage_;
79 template<typename U, typename ... Ts>
83 struct select_type<U> {
87 template<typename T, typename ... Ts>
88 struct select_type<T, T, Ts...> {
93 template<typename T, typename ... Ts>
94 struct select_type<T, T&, Ts...> {
99 template<typename T, typename ... Ts>
100 struct select_type<T&, T, Ts...> {
105 template<typename T, typename ... Ts>
106 struct select_type<T, const T&, Ts...> {
107 typedef const T& type;
111 template<typename T, typename ... Ts>
112 struct select_type<const T&, T, Ts...> {
118 template<typename T, typename ... Ts>
119 struct select_type<T*, const T*, Ts...> {
120 typedef const T* type;
125 template<typename T, typename ... Ts>
126 struct select_type<T&, const T&, Ts...> {
127 typedef const T& type;
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;
136 template<typename ... Ts>
137 struct type_index_getter;
140 struct type_index_getter<> {
141 static const unsigned int index = 0;
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;
157 typename std::enable_if<std::is_same<T, U>::value >::type* = 0) {
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>();
168 template<typename ... Ts>
173 static const unsigned int value = 0;
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;
185 template<typename _SearchType, typename _CurrentType, typename ... _RestTypes>
186 struct VariantTypeSelector: VariantTypeSelector<_SearchType, _RestTypes...> {
189 template <typename _SearchType, typename... _RestTypes>
190 struct VariantTypeSelector<_SearchType, _SearchType, _RestTypes...> {
191 typedef _SearchType type;
194 template <typename... _Types>
197 typedef std::tuple_size<std::tuple<_Types...>> TypesTupleSize;
201 static const unsigned int maxSize = max_size<_Types...>::value;
204 Variant(): valueType_(TypesTupleSize::value) {
207 Variant(const Variant& fromVariant):
208 valueType_(fromVariant.valueType_),
209 valueStorage_(fromVariant.valueStorage_) {
212 Variant(Variant&& fromVariant):
213 valueType_(std::move(fromVariant.valueType_)),
214 valueStorage_(std::move(fromVariant.valueStorage_)) {
215 fromVariant.valueType_ = TypesTupleSize::value;
220 clear_visitor<maxSize> visitor(valueStorage_);
221 apply_void_visitor<clear_visitor<maxSize>, Variant<_Types...>, _Types...>::visit(visitor, *this);
225 Variant& operator=(const Variant& fromVariant) {
230 Variant& operator=(Variant&& fromVariant) {
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_) {
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);
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));
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_) {
268 return *(reinterpret_cast<const _Type *>(&valueStorage_));
271 //TODO: Fix return temporary
276 inline size_t getValueType() {
281 void set( const U& value, const bool clear) {
282 typedef typename select_type<U, _Types...>::type selected_type_t;
284 const selected_type_t& type_value = value;
286 clear_visitor<maxSize> visitor(valueStorage_);
287 apply_void_visitor<clear_visitor<maxSize>, Variant<_Types...>, _Types...>::visit(visitor, *this);
289 new (&valueStorage_) selected_type_t(std::move(value));
290 valueType_ = type_index_getter<_Types...>::template get<selected_type_t>();
294 inline bool hasValue() const {
295 return valueType_ < TypesTupleSize::value;
299 typename std::aligned_storage<maxSize>::type valueStorage_;
305 int main(int argc, char** argv) {
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);
312 Variant<int, double, double, std::string>* myVariants = new Variant<int, double, double, std::string>(fromString);
315 const int& myInt = myVariant.get<int>(success);
316 std::cout << "myInt = " << myInt << " (" << std::boolalpha << success << ")\n";
318 const int& myFake = myVariant.get<double>(success);
319 std::cout << "myFake = " << myFake << " (" << std::boolalpha << success << ")\n";
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";
324 const int& myDouble = myVariantf.get<double>(success);
325 std::cout << "myDouble = " << myDouble << " (" << std::boolalpha << success << ")\n";
327 const std::string& myString = myVariants->get<std::string>(success);
328 std::cout << "myString = " << myString << " (" << std::boolalpha << success << ")\n";