]> git.tdb.fi Git - libs/core.git/blob - source/core/variant.h
Fix a shadowed variable warning
[libs/core.git] / source / core / variant.h
1 #ifndef MSP_CORE_VARIANT_H_
2 #define MSP_CORE_VARIANT_H_
3
4 #include <stdexcept>
5 #include <type_traits>
6 #include <typeinfo>
7 #include "meta.h"
8
9 namespace Msp {
10
11 class type_mismatch: public std::runtime_error
12 {
13 public:
14         type_mismatch(const std::type_info &, const std::type_info &);
15 };
16
17
18 class Variant
19 {
20 public:
21         static constexpr unsigned INTERNAL_SIZE = 2*sizeof(void *);
22
23         struct Functions
24         {
25                 const std::type_info &(*get_type)();
26                 bool (*compare)(const char *, const char *);
27                 void (*clone)(char *, const char *);
28                 void (*destroy)(char *);
29         };
30
31 private:
32         const Functions *funcs = nullptr;
33         alignas(void *) char storage[INTERNAL_SIZE];
34
35 public:
36         Variant() = default;
37         template<typename T>
38         Variant(const T &v) { assign(v); }
39         Variant(const Variant &v) { copy_from(v); }
40         ~Variant() { if(funcs) funcs->destroy(storage); }
41
42         template<typename T>
43         Variant &operator=(const T &v) { assign(v); return *this; }
44
45         Variant &operator=(const Variant &v) { if(&v!=this) copy_from(v); return *this; }
46
47 private:
48         template<typename T>
49         void assign(const T &);
50
51         void copy_from(const Variant &);
52
53         template<typename T>
54         T &get();
55
56 public:
57         template<typename T>
58         T &value() { return get<T>(); }
59
60         template<typename T>
61         const T &value() const { return const_cast<Variant *>(this)->get<T>(); }
62
63         template<typename T>
64         bool has_type() const { return funcs==get_functions<typename std::remove_cv<T>::type>(); }
65
66         bool has_same_type(const Variant &v) const { return (funcs && funcs==v.funcs); }
67
68         template<typename T>
69         DEPRECATED bool check_type() const { return has_type<T>(); }
70
71         DEPRECATED bool check_same_type(const Variant &v) const { return has_same_type(v); }
72
73         bool operator==(const Variant &v) const { return (has_same_type(v) && funcs->compare(storage, v.storage)); }
74         bool operator!=(const Variant &v) const { return !(operator==(v)); }
75
76         template<typename T>
77         operator T() const { return value<T>(); }
78
79 private:
80         template<typename T>
81         static constexpr bool is_small() { return (sizeof(T)<=INTERNAL_SIZE && alignof(T)<=alignof(void *)); }
82
83         template<typename T, typename U>
84         using EnableSmall = typename std::enable_if<is_small<T>(), U>::type;
85
86         template<typename T, typename U>
87         using EnableLarge = typename std::enable_if<!is_small<T>(), U>::type;
88
89         template<typename T>
90         static const Functions *get_functions();
91
92         template<typename T>
93         static const std::type_info &get_type() { return typeid(T); }
94
95         template<typename T>
96         static EnableSmall<T, void> create(char *s, const T &v)
97         { new(s) T(v); }
98
99         template<typename T>
100         static EnableLarge<T, void> create(char *s, const T &v)
101         { *reinterpret_cast<T **>(s) = new T(v); }
102
103         template<typename T>
104         static typename std::enable_if<!IsEqualityComparable<T>::value, bool>::type compare(const char *, const char *)
105         { return false; }
106
107         template<typename T>
108         static typename std::enable_if<IsEqualityComparable<T>::value, EnableSmall<T, bool>>::type compare(const char *s1, const char *s2)
109         { return *reinterpret_cast<const T *>(s1)==*reinterpret_cast<const T *>(s2); }
110
111         template<typename T>
112         static typename std::enable_if<IsEqualityComparable<T>::value, EnableLarge<T, bool>>::type compare(const char *s1, const char *s2)
113         { return **reinterpret_cast<const T *const *>(s1)==**reinterpret_cast<const T *const *>(s2); }
114
115         template<typename T>
116         static EnableSmall<T, void> clone(char *s, const char *v)
117         { new(s) T(*reinterpret_cast<const T *>(v)); }
118
119         template<typename T>
120         static EnableLarge<T, void> clone(char *s, const char *v)
121         { *reinterpret_cast<T **>(s) = new T(**reinterpret_cast<const T *const *>(v)); }
122
123         template<typename T>
124         static EnableSmall<T, void> destroy(char *s)
125         { reinterpret_cast<T *>(s)->~T(); }
126
127         template<typename T>
128         static EnableLarge<T, void> destroy(char *s)
129         { delete *reinterpret_cast<T **>(s); }
130 };
131
132
133 template<typename T>
134 inline void Variant::assign(const T &v)
135 {
136         if(funcs)
137                 funcs->destroy(storage);
138
139         funcs = get_functions<typename std::remove_cv<T>::type>();
140         create(storage, v);
141 }
142
143 inline void Variant::copy_from(const Variant &v)
144 {
145         if(funcs)
146                 funcs->destroy(storage);
147
148         funcs = v.funcs;
149         if(funcs)
150                 funcs->clone(storage, v.storage);
151 }
152
153 template<typename T>
154 inline T &Variant::get()
155 {
156         if(!has_type<T>())
157                 throw type_mismatch(typeid(T), (funcs ? funcs->get_type() : typeid(void)));
158
159         if(sizeof(T)<=INTERNAL_SIZE)
160                 return *reinterpret_cast<T *>(storage);
161         else
162                 return **reinterpret_cast<T **>(storage);
163 }
164
165 template<typename T>
166 inline const Variant::Functions *Variant::get_functions()
167 {
168         static Functions funcs =
169         {
170                 &get_type<T>,
171                 &compare<T>,
172                 &clone<T>,
173                 &destroy<T>
174         };
175         return &funcs;
176 }
177
178 } // namespace Msp
179
180 #endif