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