1 /*
2 * Copyright (c) 2016, Facebook, Inc.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree. An additional grant
7 * of patent rights can be found in the PATENTS file in the same directory.
8 */
9
10 #include <fatal/type/variant_traits.h>
11
12 #include <fatal/type/call_traits.h>
13
14 #include <fatal/test/driver.h>
15
16 #include <memory>
17 #include <type_traits>
18 #include <utility>
19
20 namespace fatal {
21
22 class poor_mans_variant {
23 union storage {
24 int i;
25 double d;
26 bool b;
27 };
28
29 public:
30 enum class id { empty, i, d, b };
get_id() const31 id get_id() const { return id_; }
32
get_i() const33 int get_i() const & { return storage_.i; }
get_d() const34 double get_d() const & { return storage_.d; }
get_b() const35 bool get_b() const & { return storage_.b; }
36
get_i()37 int &get_i() & { return storage_.i; }
get_d()38 double &get_d() & { return storage_.d; }
get_b()39 bool &get_b() & { return storage_.b; }
40
get_i()41 int &&get_i() && { return std::move(storage_.i); }
get_d()42 double &&get_d() && { return std::move(storage_.d); }
get_b()43 bool &&get_b() && { return std::move(storage_.b); }
44
set_i(int i)45 void set_i(int i) {
46 id_ = id::i;
47 storage_.i = i;
48 }
49
set_d(double d)50 void set_d(double d) {
51 id_ = id::d;
52 storage_.d = d;
53 }
54
set_b(bool b)55 void set_b(bool b) {
56 id_ = id::b;
57 storage_.b = b;
58 }
59
empty() const60 bool empty() const { return id_ == id::empty; }
clear()61 void clear() { id_ = id::empty; }
62
operator ->() const63 storage const *operator ->() const { return std::addressof(storage_); }
64
65 private:
66 id id_ = id::empty;
67 storage storage_;
68 };
69
70 FATAL_S(poor_mans_variant_name, "poor_mans_variant");
71
72 class poor_mans_variant_traits {
73 struct get {
74 FATAL_CALL_TRAITS(i, get_i);
75 FATAL_CALL_TRAITS(d, get_d);
76 FATAL_CALL_TRAITS(b, get_b);
77 };
78
79 struct set {
80 FATAL_CALL_TRAITS(i, set_i);
81 FATAL_CALL_TRAITS(d, set_d);
82 FATAL_CALL_TRAITS(b, set_b);
83 };
84
85 public:
86 using type = poor_mans_variant;
87 using id = type::id;
88 using name = poor_mans_variant_name;
89
90 struct ids {
91 using i = std::integral_constant<id, id::i>;
92 using d = std::integral_constant<id, id::d>;
93 using b = std::integral_constant<id, id::b>;
94 };
95
96 using descriptors = list<
97 variant_member_descriptor<
98 int,
99 ids::i,
100 get::i::member_function,
101 set::i::member_function
102 >,
103 variant_member_descriptor<
104 double,
105 ids::d,
106 get::d::member_function,
107 set::d::member_function
108 >,
109 variant_member_descriptor<
110 bool,
111 ids::b,
112 get::b::member_function,
113 set::b::member_function
114 >
115 >;
116
get_id(type const & variant)117 static id get_id(type const &variant) { return variant.get_id(); }
empty(type const & variant)118 static bool empty(type const &variant) { return variant.empty(); }
clear(type & variant)119 static void clear(type &variant) { variant.clear(); }
120 };
121
122 struct poor_mans_variant_metadata {};
123
124 FATAL_REGISTER_VARIANT_TRAITS(
125 poor_mans_variant_traits,
126 poor_mans_variant_metadata
127 );
128
FATAL_TEST(variant_traits,has_variant_traits)129 FATAL_TEST(variant_traits, has_variant_traits) {
130 FATAL_EXPECT_SAME<std::true_type, has_variant_traits<poor_mans_variant>>();
131 FATAL_EXPECT_SAME<std::false_type, has_variant_traits<void>>();
132 }
133
FATAL_TEST(poor_mans_variant,types)134 FATAL_TEST(poor_mans_variant, types) {
135 using type = poor_mans_variant;
136 using ids = poor_mans_variant_traits::ids;
137 using traits = variant_traits<type>;
138
139 FATAL_EXPECT_SAME<type, traits::type>();
140 FATAL_EXPECT_SAME<poor_mans_variant_name, traits::name>();
141 FATAL_EXPECT_SAME<type::id, traits::id>();
142 FATAL_EXPECT_SAME<poor_mans_variant_metadata, traits::metadata>();
143
144 FATAL_EXPECT_SAME<ids::i, traits::ids::i>();
145 FATAL_EXPECT_SAME<ids::d, traits::ids::d>();
146 FATAL_EXPECT_SAME<ids::b, traits::ids::b>();
147
148 FATAL_EXPECT_SAME<
149 poor_mans_variant_traits::descriptors,
150 traits::descriptors
151 >();
152 }
153
FATAL_TEST(poor_mans_variant,functions)154 FATAL_TEST(poor_mans_variant, functions) {
155 using type = poor_mans_variant;
156 using id = poor_mans_variant::id;
157 using traits = variant_traits<type>;
158
159 type v;
160 type const &c = v;
161 type &&r = std::move(v);
162
163 FATAL_EXPECT_TRUE(traits::empty(v));
164 FATAL_EXPECT_TRUE(traits::empty(c));
165 FATAL_EXPECT_TRUE(traits::empty(r));
166 FATAL_EXPECT_EQ(id::empty, traits::get_id(v));
167 FATAL_EXPECT_EQ(id::empty, traits::get_id(c));
168 FATAL_EXPECT_EQ(id::empty, traits::get_id(r));
169
170 v.set_i(10);
171 FATAL_EXPECT_FALSE(traits::empty(v));
172 FATAL_EXPECT_FALSE(traits::empty(c));
173 FATAL_EXPECT_FALSE(traits::empty(r));
174 FATAL_EXPECT_EQ(id::i, traits::get_id(v));
175 FATAL_EXPECT_EQ(id::i, traits::get_id(c));
176 FATAL_EXPECT_EQ(id::i, traits::get_id(r));
177
178 v.set_d(5.6);
179 FATAL_EXPECT_FALSE(traits::empty(v));
180 FATAL_EXPECT_FALSE(traits::empty(c));
181 FATAL_EXPECT_FALSE(traits::empty(r));
182 FATAL_EXPECT_EQ(id::d, traits::get_id(v));
183 FATAL_EXPECT_EQ(id::d, traits::get_id(c));
184 FATAL_EXPECT_EQ(id::d, traits::get_id(r));
185
186 v.set_b(true);
187 FATAL_EXPECT_FALSE(traits::empty(v));
188 FATAL_EXPECT_FALSE(traits::empty(c));
189 FATAL_EXPECT_FALSE(traits::empty(r));
190 FATAL_EXPECT_EQ(id::b, traits::get_id(v));
191 FATAL_EXPECT_EQ(id::b, traits::get_id(c));
192 FATAL_EXPECT_EQ(id::b, traits::get_id(r));
193
194 traits::clear(v);
195 FATAL_EXPECT_TRUE(traits::empty(v));
196 FATAL_EXPECT_TRUE(traits::empty(c));
197 FATAL_EXPECT_TRUE(traits::empty(r));
198 FATAL_EXPECT_EQ(id::empty, traits::get_id(v));
199 FATAL_EXPECT_EQ(id::empty, traits::get_id(c));
200 FATAL_EXPECT_EQ(id::empty, traits::get_id(r));
201 }
202
FATAL_TEST(poor_mans_variant,by_id)203 FATAL_TEST(poor_mans_variant, by_id) {
204 using type = poor_mans_variant;
205 using ids = poor_mans_variant_traits::ids;
206 using traits = variant_traits<type>::by_id;
207
208 FATAL_EXPECT_SAME<ids::i, traits::id<ids::i>>();
209 FATAL_EXPECT_SAME<ids::d, traits::id<ids::d>>();
210 FATAL_EXPECT_SAME<ids::b, traits::id<ids::b>>();
211
212 FATAL_EXPECT_SAME<int, traits::type<ids::i>>();
213 FATAL_EXPECT_SAME<double, traits::type<ids::d>>();
214 FATAL_EXPECT_SAME<bool, traits::type<ids::b>>();
215
216 type v;
217 type const &c = v;
218 type &&r = std::move(v);
219
220 v.set_i(10);
221 FATAL_EXPECT_EQ(10, traits::get<ids::i>(v));
222 FATAL_EXPECT_EQ(10, traits::get<ids::i>(c));
223 FATAL_EXPECT_EQ(10, traits::get<ids::i>(r));
224
225 v.set_d(5.6);
226 FATAL_EXPECT_EQ(5.6, traits::get<ids::d>(v));
227 FATAL_EXPECT_EQ(5.6, traits::get<ids::d>(c));
228 FATAL_EXPECT_EQ(5.6, traits::get<ids::d>(r));
229
230 v.set_b(true);
231 FATAL_EXPECT_EQ(true, traits::get<ids::b>(v));
232 FATAL_EXPECT_EQ(true, traits::get<ids::b>(c));
233 FATAL_EXPECT_EQ(true, traits::get<ids::b>(r));
234
235 traits::set<ids::i>(v, 97);
236 FATAL_EXPECT_EQ(97, v->i);
237 FATAL_EXPECT_EQ(97, c->i);
238 FATAL_EXPECT_EQ(97, r->i);
239
240 traits::set<ids::d>(v, 7.2);
241 FATAL_EXPECT_EQ(7.2, v->d);
242 FATAL_EXPECT_EQ(7.2, c->d);
243 FATAL_EXPECT_EQ(7.2, r->d);
244
245 traits::set<ids::b>(v, false);
246 FATAL_EXPECT_EQ(false, v->b);
247 FATAL_EXPECT_EQ(false, c->b);
248 FATAL_EXPECT_EQ(false, r->b);
249 }
250
FATAL_TEST(poor_mans_variant,by_type)251 FATAL_TEST(poor_mans_variant, by_type) {
252 using type = poor_mans_variant;
253 using ids = poor_mans_variant_traits::ids;
254 using traits = variant_traits<type>::by_type;
255
256 FATAL_EXPECT_SAME<ids::i, traits::id<int>>();
257 FATAL_EXPECT_SAME<ids::d, traits::id<double>>();
258 FATAL_EXPECT_SAME<ids::b, traits::id<bool>>();
259
260 FATAL_EXPECT_SAME<int, traits::type<int>>();
261 FATAL_EXPECT_SAME<double, traits::type<double>>();
262 FATAL_EXPECT_SAME<bool, traits::type<bool>>();
263
264 type v;
265 type const &c = v;
266 type &&r = std::move(v);
267
268 v.set_i(10);
269 FATAL_EXPECT_EQ(10, traits::get<int>(v));
270 FATAL_EXPECT_EQ(10, traits::get<int>(c));
271 FATAL_EXPECT_EQ(10, traits::get<int>(r));
272
273 v.set_d(5.6);
274 FATAL_EXPECT_EQ(5.6, traits::get<double>(v));
275 FATAL_EXPECT_EQ(5.6, traits::get<double>(c));
276 FATAL_EXPECT_EQ(5.6, traits::get<double>(r));
277
278 v.set_b(true);
279 FATAL_EXPECT_EQ(true, traits::get<bool>(v));
280 FATAL_EXPECT_EQ(true, traits::get<bool>(c));
281 FATAL_EXPECT_EQ(true, traits::get<bool>(r));
282
283 traits::set<int>(v, 97);
284 FATAL_EXPECT_EQ(97, v->i);
285 FATAL_EXPECT_EQ(97, c->i);
286 FATAL_EXPECT_EQ(97, r->i);
287
288 traits::set<double>(v, 7.2);
289 FATAL_EXPECT_EQ(7.2, v->d);
290 FATAL_EXPECT_EQ(7.2, c->d);
291 FATAL_EXPECT_EQ(7.2, r->d);
292
293 traits::set<bool>(v, false);
294 FATAL_EXPECT_EQ(false, v->b);
295 FATAL_EXPECT_EQ(false, c->b);
296 FATAL_EXPECT_EQ(false, r->b);
297 }
298
299 // TODO: empty
300 // TODO: clear
301
302 } // namespace fatal {
303