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