bbd13b8f2a8cb91fcef7a9ad3b53d4428d1a8d3a
[folly.git] / folly / test / PolyTest.cpp
1 /*
2  * Copyright 2017 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <folly/Poly.h>
18
19 #include <folly/Conv.h>
20 #include <folly/poly/Nullable.h>
21 #include <folly/poly/Regular.h>
22 #include <folly/portability/GTest.h>
23
24 #include <array>
25
26 using namespace folly;
27 using namespace folly::poly;
28
29 namespace {
30 struct Big {
31  private:
32   std::array<char, sizeof(Poly<ISemiRegular>) + 1> data_;
33   int i_;
34
35  public:
36   Big() : data_{}, i_(0) {
37     ++s_count;
38   }
39   explicit Big(int i) : data_{}, i_(i) {
40     ++s_count;
41   }
42   Big(Big const& that) : data_(that.data_), i_(that.i_) {
43     ++s_count;
44   }
45   ~Big() {
46     --s_count;
47   }
48   Big& operator=(Big const&) = default;
49   int value() const {
50     return i_;
51   }
52   friend bool operator==(Big const& a, Big const& b) {
53     return a.value() == b.value();
54   }
55   friend bool operator!=(Big const& a, Big const& b) {
56     return !(a == b);
57   }
58   static std::ptrdiff_t s_count;
59 };
60 std::ptrdiff_t Big::s_count = 0;
61 } // namespace
62
63 TEST(Poly, SemiRegular) {
64   {
65     // A small object, storable in-situ:
66     Poly<ISemiRegular> p = 42;
67     EXPECT_EQ(typeid(int), poly_type(p));
68     EXPECT_EQ(42, poly_cast<int>(p));
69     EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
70     Poly<ISemiRegular> p2 = p;
71     EXPECT_EQ(typeid(int), poly_type(p2));
72     EXPECT_EQ(42, poly_cast<int>(p2));
73     EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
74   }
75
76   EXPECT_EQ(0, Big::s_count);
77   {
78     // A big object, stored on the heap:
79     Poly<ISemiRegular> p = Big(42);
80     EXPECT_EQ(1, Big::s_count);
81     EXPECT_EQ(typeid(Big), poly_type(p));
82     EXPECT_EQ(42, poly_cast<Big>(p).value());
83     EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
84     Poly<ISemiRegular> p2 = p;
85     EXPECT_EQ(2, Big::s_count);
86     EXPECT_EQ(typeid(Big), poly_type(p2));
87     EXPECT_EQ(42, poly_cast<Big>(p2).value());
88     EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
89   }
90   EXPECT_EQ(0, Big::s_count);
91 }
92
93 TEST(Poly, SemiRegularReference) {
94   int i = 42;
95   Poly<ISemiRegular&> p = i;
96   EXPECT_EQ(42, i);
97   EXPECT_EQ(typeid(int), poly_type(p));
98   EXPECT_EQ(42, poly_cast<int>(p));
99   EXPECT_EQ(&i, &poly_cast<int>(p));
100   EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
101   // Can't default-initialize reference-like Poly's:
102   static_assert(!std::is_default_constructible<Poly<ISemiRegular&>>::value, "");
103 }
104
105 TEST(Poly, Conversions) {
106   int i = 42;
107   Poly<ISemiRegular> p1 = i;
108   Poly<ISemiRegular&> p2 = p1;
109   EXPECT_EQ(&poly_cast<int>(p1), &poly_cast<int>(p2));
110   Poly<ISemiRegular const&> p3 = p1;
111   Poly<ISemiRegular const&> p4 = p2;
112   EXPECT_EQ(&poly_cast<int>(p3), &poly_cast<int>(p1));
113   EXPECT_EQ(&poly_cast<int>(p4), &poly_cast<int>(p1));
114   static_assert(
115       !std::is_constructible<Poly<ISemiRegular&>, Poly<ISemiRegular const&>&>::
116           value,
117       "");
118   static_assert(
119       !std::is_constructible<Poly<ISemiRegular>, Poly<ISemiRegular const&>&>::
120           value,
121       "");
122 }
123
124 TEST(Poly, EqualityComparableReference) {
125   int i = 42;
126   int j = 42;
127   Poly<IEqualityComparable&> p1 = i;
128   Poly<IEqualityComparable&> p2 = j;
129   EXPECT_EQ(&i, &poly_cast<int>(p1));
130   EXPECT_EQ(&j, &poly_cast<int>(p2));
131   EXPECT_TRUE(p1 == p2);
132   EXPECT_FALSE(p1 != p2);
133   j = 43;
134   EXPECT_FALSE(p1 == p2);
135   EXPECT_TRUE(p1 != p2);
136   EXPECT_EQ(42, poly_cast<int>(p1));
137   EXPECT_EQ(43, poly_cast<int>(p2));
138 }
139
140 namespace {
141 struct Foo {
142   template <class Base>
143   struct Interface : Base {
144     void foo(int& i) {
145       folly::poly_call<0>(*this, i);
146     }
147   };
148
149   template <class T>
150   using Members = FOLLY_POLY_MEMBERS(&T::foo);
151 };
152
153 struct foo_ {
154   foo_() = default;
155   explicit foo_(int i) : j_(i) {}
156   void foo(int& i) {
157     i += j_;
158   }
159
160  private:
161   int j_ = 0;
162 };
163 } // namespace
164
165 TEST(Poly, Singular) {
166   Poly<Foo> p = foo_{42};
167   int i = 1;
168   p.foo(i);
169   EXPECT_EQ(43, i);
170   EXPECT_EQ(typeid(foo_), poly_type(p));
171 }
172
173 namespace {
174 struct FooBar : PolyExtends<Foo> {
175   template <class Base>
176   struct Interface : Base {
177     std::string bar(int i) const {
178       return folly::poly_call<0>(*this, i);
179     }
180   };
181
182   template <class T>
183   using Members = FOLLY_POLY_MEMBERS(&T::bar);
184 };
185
186 struct foo_bar {
187   foo_bar() = default;
188   explicit foo_bar(int i) : j_(i) {}
189   void foo(int& i) {
190     i += j_;
191   }
192   std::string bar(int i) const {
193     i += j_;
194     return folly::to<std::string>(i);
195   }
196
197  private:
198   int j_ = 0;
199 };
200 } // namespace
201
202 TEST(Poly, SingleInheritance) {
203   Poly<FooBar> p = foo_bar{42};
204   int i = 1;
205   p.foo(i);
206   EXPECT_EQ(43, i);
207   EXPECT_EQ("43", p.bar(1));
208   EXPECT_EQ(typeid(foo_bar), poly_type(p));
209
210   Poly<Foo> q = p; // OK, conversion works.
211   q.foo(i);
212   EXPECT_EQ(85, i);
213
214   Poly<Foo&> r = p;
215   r->foo(i);
216   EXPECT_EQ(127, i);
217   const_cast<Poly<Foo&> const&>(r)->foo(i);
218   EXPECT_EQ(169, i);
219
220   Poly<FooBar const&> cr = p;
221   // cr->foo(i); // ERROR: calls a non-const member through a const reference
222   cr->bar(i); // OK
223 }
224
225 namespace {
226 struct Baz {
227   template <class Base>
228   struct Interface : Base {
229     std::string baz(int i, int j) const {
230       return folly::poly_call<0>(*this, i, j);
231     }
232   };
233
234   template <class T>
235   using Members = FOLLY_POLY_MEMBERS(&T::baz);
236 };
237
238 struct FooBarBazFizz : PolyExtends<FooBar, Baz> {
239   template <class Base>
240   struct Interface : Base {
241     std::string fizz() const {
242       return folly::poly_call<0>(*this);
243     }
244   };
245
246   template <class T>
247   using Members = FOLLY_POLY_MEMBERS(&T::fizz);
248 };
249
250 struct foo_bar_baz_fizz {
251   foo_bar_baz_fizz() = default;
252   explicit foo_bar_baz_fizz(int i) : j_(i) {}
253   void foo(int& i) {
254     i += j_;
255   }
256   std::string bar(int i) const {
257     return folly::to<std::string>(i + j_);
258   }
259   std::string baz(int i, int j) const {
260     return folly::to<std::string>(i + j);
261   }
262   std::string fizz() const {
263     return "fizz";
264   }
265
266  private:
267   int j_ = 0;
268 };
269 } // namespace
270
271 TEST(Poly, MultipleInheritance) {
272   Poly<FooBarBazFizz> p = foo_bar_baz_fizz{42};
273   int i = 1;
274   p.foo(i);
275   EXPECT_EQ(43, i);
276   EXPECT_EQ("43", p.bar(1));
277   EXPECT_EQ("3", p.baz(1, 2));
278   EXPECT_EQ("fizz", p.fizz());
279   EXPECT_EQ(typeid(foo_bar_baz_fizz), poly_type(p));
280 }
281
282 namespace {
283 struct Property {
284   template <class Base>
285   struct Interface : Base {
286     int prop() const {
287       return folly::poly_call<0>(*this);
288     }
289     void prop(int i) {
290       folly::poly_call<1>(*this, i);
291     }
292   };
293
294   template <class T>
295   using Members = FOLLY_POLY_MEMBERS(
296       FOLLY_POLY_MEMBER(int() const, &T::prop),
297       FOLLY_POLY_MEMBER(void(int), &T::prop));
298 };
299
300 struct property {
301   property() = default;
302   explicit property(int i) : j(i) {}
303   int prop() const {
304     return j;
305   }
306   void prop(int i) {
307     j = i;
308   }
309
310  private:
311   int j = 0;
312 };
313 } // namespace
314
315 TEST(Poly, OverloadedMembers) {
316   Poly<Property> p = property{42};
317   EXPECT_EQ(typeid(property), poly_type(p));
318   EXPECT_EQ(42, p.prop());
319   p.prop(68);
320   EXPECT_EQ(68, p.prop());
321 }
322
323 TEST(Poly, NullablePointer) {
324   Poly<INullablePointer> p = nullptr;
325   Poly<INullablePointer> q{};
326   EXPECT_EQ(typeid(void), poly_type(p));
327   EXPECT_TRUE(poly_empty(p));
328   EXPECT_TRUE(p == q);
329   EXPECT_FALSE(p != q);
330   EXPECT_TRUE(p == nullptr);
331   EXPECT_TRUE(nullptr == p);
332   EXPECT_FALSE(p != nullptr);
333   EXPECT_FALSE(nullptr != p);
334
335   // No null references ever.
336   Poly<INullablePointer> r = 42;
337   Poly<INullablePointer&> s = r;
338   static_assert(!poly_empty(s), "");
339   EXPECT_THROW(Poly<INullablePointer&> r(q), BadPolyAccess);
340 }
341
342 namespace {
343 struct MoveOnly_ {
344   MoveOnly_() = default;
345   MoveOnly_(MoveOnly_&&) = default;
346   MoveOnly_(MoveOnly_ const&) = delete;
347   MoveOnly_& operator=(MoveOnly_&&) = default;
348   MoveOnly_& operator=(MoveOnly_ const&) = delete;
349 };
350 } // namespace
351
352 TEST(Poly, Move) {
353   {
354     int i = 42;
355     Poly<IMoveOnly&> p = i;
356     static_assert(
357         !std::is_convertible<Poly<IMoveOnly&>, Poly<IMoveOnly&&>>::value, "");
358     auto q = poly_move(p);
359     static_assert(std::is_same<decltype(q), Poly<IMoveOnly&&>>::value, "");
360     EXPECT_EQ(&poly_cast<int>(p), &poly_cast<int>(q));
361   }
362   {
363     int i = 42;
364     Poly<ISemiRegular const&> p = i;
365     auto q = poly_move(p);
366     static_assert(
367         std::is_same<decltype(q), Poly<ISemiRegular const&>>::value, "");
368     EXPECT_EQ(&poly_cast<int>(p), &poly_cast<int>(q));
369   }
370   {
371     Poly<IMoveOnly> p = MoveOnly_{};
372     static_assert(!std::is_copy_constructible<Poly<IMoveOnly>>::value, "");
373     auto q = poly_move(p);
374     static_assert(std::is_same<decltype(q), Poly<IMoveOnly>>::value, "");
375   }
376 }
377
378 TEST(Poly, RValueRef) {
379   int i = 42;
380   Poly<ISemiRegular&&> p = std::move(i);
381   static_assert(std::is_same<decltype(poly_cast<int>(p)), int&>::value, "");
382   EXPECT_EQ(&i, &poly_cast<int>(p));
383 }
384
385 namespace {
386 template <class Fun>
387 struct IFunction;
388
389 template <class R, class... As>
390 struct IFunction<R(As...)> {
391   template <class Base>
392   struct Interface : Base {
393     R operator()(As... as) const {
394       return static_cast<R>(
395           folly::poly_call<0>(*this, std::forward<As>(as)...));
396     }
397   };
398
399   template <class T>
400   using Members =
401       FOLLY_POLY_MEMBERS(FOLLY_POLY_MEMBER(R(As...) const, &T::operator()));
402 };
403
404 template <class Fun>
405 using Function = Poly<IFunction<Fun>>;
406 } // namespace
407
408 TEST(Poly, Function) {
409   Function<int(int, int)> fun = std::plus<int>{};
410   EXPECT_EQ(42, fun(22, 20));
411   fun = std::multiplies<int>{};
412   EXPECT_EQ(22 * 20, fun(22, 20));
413 }
414
415 namespace {
416 // This multiply extends IEqualityComparable
417 struct IDiamond : PolyExtends<IRegular, INullablePointer> {};
418 } // namespace
419
420 TEST(Poly, DiamondInheritance) {
421   {
422     // A small object, storable in-situ:
423     Poly<IDiamond> p = 42;
424     EXPECT_EQ(typeid(int), poly_type(p));
425     EXPECT_EQ(42, poly_cast<int>(p));
426     EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
427     Poly<IDiamond> p2 = p;
428     EXPECT_EQ(typeid(int), poly_type(p2));
429     EXPECT_EQ(42, poly_cast<int>(p2));
430     EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
431     Poly<IEqualityComparable&> eq = p;
432     EXPECT_EQ(&poly_cast<int>(p), &poly_cast<int>(eq));
433   }
434
435   EXPECT_EQ(0, Big::s_count);
436   {
437     // A big object, stored on the heap:
438     Poly<IDiamond> p = Big(42);
439     EXPECT_EQ(1, Big::s_count);
440     EXPECT_EQ(typeid(Big), poly_type(p));
441     EXPECT_EQ(42, poly_cast<Big>(p).value());
442     EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
443     Poly<IDiamond> p2 = p;
444     EXPECT_EQ(2, Big::s_count);
445     EXPECT_EQ(typeid(Big), poly_type(p2));
446     EXPECT_EQ(42, poly_cast<Big>(p2).value());
447     EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
448     Poly<IEqualityComparable&> eq = p;
449     EXPECT_EQ(&poly_cast<Big>(p), &poly_cast<Big>(eq));
450   }
451   EXPECT_EQ(0, Big::s_count);
452 }
453
454 namespace {
455 struct Struct {
456   int property() const {
457     return 42;
458   }
459   void property(int) {}
460 };
461 struct Struct2 : Struct {
462   int meow() {
463     return 42;
464   }
465
466   int purr() {
467     return 1;
468   }
469   int purr() const {
470     return 2;
471   }
472 };
473
474 int property(Struct const&) {
475   return 42;
476 }
477 void property(Struct&, int) {}
478
479 int meow(Struct2&) {
480   return 42;
481 }
482
483 int purr(Struct2&) {
484   return 1;
485 }
486 int purr(Struct2 const&) {
487   return 2;
488 }
489 } // namespace
490
491 TEST(Poly, Sig) {
492   {
493     auto m0 = folly::sig<int() const>(&Struct::property);
494     EXPECT_EQ(static_cast<int (Struct::*)() const>(&Struct::property), m0);
495     auto m1 = folly::sig<int()>(&Struct::property);
496     EXPECT_EQ(static_cast<int (Struct::*)() const>(&Struct::property), m1);
497
498     auto m2 = folly::sig<int() const>(&Struct2::property);
499     EXPECT_EQ(static_cast<int (Struct2::*)() const>(&Struct2::property), m2);
500     auto m3 = folly::sig<int()>(&Struct2::property);
501     EXPECT_EQ(static_cast<int (Struct2::*)() const>(&Struct2::property), m3);
502
503     auto m4 = folly::sig<long()>(&Struct2::meow);
504     EXPECT_EQ(&Struct2::meow, m4);
505
506     auto m5 = folly::sig<int()>(&Struct2::purr);
507     EXPECT_EQ(static_cast<int (Struct2::*)()>(&Struct2::purr), m5);
508     auto m6 = folly::sig<int() const>(&Struct2::purr);
509     EXPECT_EQ(static_cast<int (Struct2::*)() const>(&Struct2::purr), m6);
510   }
511   {
512     auto m0 = folly::sig<int(Struct const&)>(&::property);
513     EXPECT_EQ(static_cast<int (*)(Struct const&)>(&::property), m0);
514     auto m1 = folly::sig<int(Struct&)>(&::property);
515     EXPECT_EQ(static_cast<int (*)(Struct const&)>(&::property), m1);
516
517     auto m2 = folly::sig<long(Struct2&)>(&::meow);
518     EXPECT_EQ(&::meow, m2);
519
520     auto m3 = folly::sig<int(Struct2&)>(&::purr);
521     EXPECT_EQ(static_cast<int (*)(Struct2&)>(&::purr), m3);
522     auto m4 = folly::sig<int(Struct2 const&)>(&::purr);
523     EXPECT_EQ(static_cast<int (*)(Struct2 const&)>(&::purr), m4);
524   }
525 }
526
527 namespace {
528 struct IAddable {
529   template <class Base>
530   struct Interface : Base {
531     friend PolySelf<Base, PolyDecay> operator+(
532         PolySelf<Base> const& a,
533         PolySelf<Base> const& b) {
534       return folly::poly_call<0, IAddable>(a, b);
535     }
536   };
537   template <class T>
538   static auto plus_(T const& a, T const& b) -> decltype(a + b) {
539     return a + b;
540   }
541
542   template <class T>
543   using Members = FOLLY_POLY_MEMBERS(&plus_<std::decay_t<T>>);
544 };
545 } // namespace
546
547 TEST(Poly, Addable) {
548   Poly<IAddable> a = 2, b = 3;
549   Poly<IAddable> c = a + b;
550   EXPECT_EQ(typeid(int), poly_type(c));
551   EXPECT_EQ(5, poly_cast<int>(c));
552
553   Poly<IAddable const&> aref = a, bref = b;
554   auto cc = aref + bref;
555   static_assert(std::is_same<decltype(cc), Poly<IAddable>>::value, "");
556   EXPECT_EQ(typeid(int), poly_type(cc));
557   EXPECT_EQ(5, poly_cast<int>(cc));
558   b = 4;
559   EXPECT_EQ(5, poly_cast<int>(cc));
560   cc = aref + bref;
561   EXPECT_EQ(6, poly_cast<int>(cc));
562 }