@@ -30,55 +30,55 @@ namespace chip {
30
30
31
31
namespace VariantInternal {
32
32
33
- template <typename ... Ts>
33
+ template <std:: size_t Index, typename ... Ts>
34
34
struct VariantCurry ;
35
35
36
- template <typename T, typename ... Ts>
37
- struct VariantCurry <T, Ts...>
36
+ template <std:: size_t Index, typename T, typename ... Ts>
37
+ struct VariantCurry <Index, T, Ts...>
38
38
{
39
39
inline static void Destroy (std::size_t id, void * data)
40
40
{
41
- if (id == T::VariantId )
41
+ if (id == Index )
42
42
reinterpret_cast <T *>(data)->~T ();
43
43
else
44
- VariantCurry<Ts...>::Destroy (id, data);
44
+ VariantCurry<Index + 1 , Ts...>::Destroy (id, data);
45
45
}
46
46
47
47
inline static void Move (std::size_t that_t , void * that_v, void * this_v)
48
48
{
49
- if (that_t == T::VariantId )
49
+ if (that_t == Index )
50
50
new (this_v) T (std::move (*reinterpret_cast <T *>(that_v)));
51
51
else
52
- VariantCurry<Ts...>::Move (that_t , that_v, this_v);
52
+ VariantCurry<Index + 1 , Ts...>::Move (that_t , that_v, this_v);
53
53
}
54
54
55
55
inline static void Copy (std::size_t that_t , const void * that_v, void * this_v)
56
56
{
57
- if (that_t == T::VariantId )
57
+ if (that_t == Index )
58
58
{
59
59
new (this_v) T (*reinterpret_cast <const T *>(that_v));
60
60
}
61
61
else
62
62
{
63
- VariantCurry<Ts...>::Copy (that_t , that_v, this_v);
63
+ VariantCurry<Index + 1 , Ts...>::Copy (that_t , that_v, this_v);
64
64
}
65
65
}
66
66
67
67
inline static bool Equal (std::size_t type_t , const void * that_v, const void * this_v)
68
68
{
69
- if (type_t == T::VariantId )
69
+ if (type_t == Index )
70
70
{
71
71
return *reinterpret_cast <const T *>(this_v) == *reinterpret_cast <const T *>(that_v);
72
72
}
73
73
else
74
74
{
75
- return VariantCurry<Ts...>::Equal (type_t , that_v, this_v);
75
+ return VariantCurry<Index + 1 , Ts...>::Equal (type_t , that_v, this_v);
76
76
}
77
77
}
78
78
};
79
79
80
- template <>
81
- struct VariantCurry <>
80
+ template <std:: size_t Index >
81
+ struct VariantCurry <Index >
82
82
{
83
83
inline static void Destroy (std::size_t id, void * data) {}
84
84
inline static void Move (std::size_t that_t , void * that_v, void * this_v) {}
@@ -90,23 +90,41 @@ struct VariantCurry<>
90
90
}
91
91
};
92
92
93
+ template <typename T, typename TupleType>
94
+ class TupleIndexOfType
95
+ {
96
+ private:
97
+ template <std::size_t Index>
98
+ static constexpr
99
+ typename std::enable_if<std::is_same<T, typename std::tuple_element<Index, TupleType>::type>::value, std::size_t >::type
100
+ calculate ()
101
+ {
102
+ return Index;
103
+ }
104
+
105
+ template <std::size_t Index>
106
+ static constexpr
107
+ typename std::enable_if<!std::is_same<T, typename std::tuple_element<Index, TupleType>::type>::value, std::size_t >::type
108
+ calculate ()
109
+ {
110
+ return calculate<Index + 1 >();
111
+ }
112
+
113
+ public:
114
+ static constexpr std::size_t value = calculate<0 >();
115
+ };
116
+
93
117
} // namespace VariantInternal
94
118
95
119
/* *
96
120
* @brief
97
121
* Represents a type-safe union. An instance of Variant at any given time either holds a value of one of its
98
- * alternative types, or no value. Each type must define a unique value of a static field named VariantId.
122
+ * alternative types, or no value.
99
123
*
100
124
* Example:
101
- * struct Type1
102
- * {
103
- * static constexpr const std::size_t VariantId = 1;
104
- * };
125
+ * struct Type1 {};
105
126
*
106
- * struct Type2
107
- * {
108
- * static constexpr const std::size_t VariantId = 2;
109
- * };
127
+ * struct Type2 {};
110
128
*
111
129
* Variant<Type1, Type2> v;
112
130
* v.Set<Type1>(); // v contains Type1
@@ -121,7 +139,7 @@ struct Variant
121
139
static constexpr std::size_t kInvalidType = SIZE_MAX;
122
140
123
141
using Data = typename std::aligned_storage<kDataSize , kDataAlign >::type;
124
- using Curry = VariantInternal::VariantCurry<Ts...>;
142
+ using Curry = VariantInternal::VariantCurry<0 , Ts...>;
125
143
126
144
std::size_t mTypeId ;
127
145
Data mData ;
@@ -158,13 +176,13 @@ struct Variant
158
176
159
177
bool operator ==(const Variant & other) const
160
178
{
161
- return GetType () == other.GetType () && Curry::Equal (mTypeId , &other.mData , &mData );
179
+ return GetType () == other.GetType () && (! Valid () || Curry::Equal (mTypeId , &other.mData , &mData ) );
162
180
}
163
181
164
182
template <typename T>
165
183
bool Is () const
166
184
{
167
- return (mTypeId == T::VariantId );
185
+ return (mTypeId == VariantInternal::TupleIndexOfType<T, std::tuple<Ts...>>::value );
168
186
}
169
187
170
188
std::size_t GetType () const { return mTypeId ; }
@@ -176,20 +194,20 @@ struct Variant
176
194
{
177
195
Curry::Destroy (mTypeId , &mData );
178
196
new (&mData ) T (std::forward<Args>(args)...);
179
- mTypeId = T::VariantId ;
197
+ mTypeId = VariantInternal::TupleIndexOfType<T, std::tuple<Ts...>>::value ;
180
198
}
181
199
182
200
template <typename T>
183
201
T & Get ()
184
202
{
185
- VerifyOrDie (mTypeId == T::VariantId );
203
+ VerifyOrDie (( mTypeId == VariantInternal::TupleIndexOfType<T, std::tuple<Ts...>>::value) );
186
204
return *reinterpret_cast <T *>(&mData );
187
205
}
188
206
189
207
template <typename T>
190
208
const T & Get () const
191
209
{
192
- VerifyOrDie (mTypeId == T::VariantId );
210
+ VerifyOrDie (( mTypeId == VariantInternal::TupleIndexOfType<T, std::tuple<Ts...>>::value) );
193
211
return *reinterpret_cast <const T *>(&mData );
194
212
}
195
213
0 commit comments