2 * Copyright 2017 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 5
18 #pragma message "Folly.Poly requires gcc-5 or greater"
20 #include <folly/Poly.h>
22 #include <folly/Conv.h>
23 #include <folly/poly/Nullable.h>
24 #include <folly/poly/Regular.h>
25 #include <folly/portability/GTest.h>
29 using namespace folly;
30 using namespace folly::poly;
35 std::array<char, sizeof(Poly<ISemiRegular>) + 1> data_;
39 Big() : data_{}, i_(0) {
42 explicit Big(int i) : data_{}, i_(i) {
45 Big(Big const& that) : data_(that.data_), i_(that.i_) {
51 Big& operator=(Big const&) = default;
55 friend bool operator==(Big const& a, Big const& b) {
56 return a.value() == b.value();
58 friend bool operator!=(Big const& a, Big const& b) {
61 static std::ptrdiff_t s_count;
63 std::ptrdiff_t Big::s_count = 0;
66 TEST(Poly, SemiRegular) {
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);
79 EXPECT_EQ(0, Big::s_count);
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);
93 EXPECT_EQ(0, Big::s_count);
96 TEST(Poly, SemiRegularReference) {
98 Poly<ISemiRegular&> p = 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, "");
108 TEST(Poly, Conversions) {
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));
118 !std::is_constructible<Poly<ISemiRegular&>, Poly<ISemiRegular const&>&>::
122 !std::is_constructible<Poly<ISemiRegular>, Poly<ISemiRegular const&>&>::
127 TEST(Poly, EqualityComparableReference) {
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);
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));
145 template <class Base>
146 struct Interface : Base {
148 folly::poly_call<0>(*this, i);
153 using Members = FOLLY_POLY_MEMBERS(&T::foo);
158 explicit foo_(int i) : j_(i) {}
168 TEST(Poly, Singular) {
169 Poly<Foo> p = foo_{42};
173 EXPECT_EQ(typeid(foo_), poly_type(p));
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);
186 using Members = FOLLY_POLY_MEMBERS(&T::bar);
191 explicit foo_bar(int i) : j_(i) {}
195 std::string bar(int i) const {
197 return folly::to<std::string>(i);
205 TEST(Poly, SingleInheritance) {
206 Poly<FooBar> p = foo_bar{42};
210 EXPECT_EQ("43", p.bar(1));
211 EXPECT_EQ(typeid(foo_bar), poly_type(p));
213 Poly<Foo> q = p; // OK, conversion works.
220 const_cast<Poly<Foo&> const&>(r)->foo(i);
223 Poly<FooBar const&> cr = p;
224 // cr->foo(i); // ERROR: calls a non-const member through a const reference
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);
238 using Members = FOLLY_POLY_MEMBERS(&T::baz);
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);
250 using Members = FOLLY_POLY_MEMBERS(&T::fizz);
253 struct foo_bar_baz_fizz {
254 foo_bar_baz_fizz() = default;
255 explicit foo_bar_baz_fizz(int i) : j_(i) {}
259 std::string bar(int i) const {
260 return folly::to<std::string>(i + j_);
262 std::string baz(int i, int j) const {
263 return folly::to<std::string>(i + j);
265 std::string fizz() const {
274 TEST(Poly, MultipleInheritance) {
275 Poly<FooBarBazFizz> p = foo_bar_baz_fizz{42};
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));
287 template <class Base>
288 struct Interface : Base {
290 return folly::poly_call<0>(*this);
293 folly::poly_call<1>(*this, i);
298 using Members = FOLLY_POLY_MEMBERS(
299 FOLLY_POLY_MEMBER(int() const, &T::prop),
300 FOLLY_POLY_MEMBER(void(int), &T::prop));
304 property() = default;
305 explicit property(int i) : j(i) {}
318 TEST(Poly, OverloadedMembers) {
319 Poly<Property> p = property{42};
320 EXPECT_EQ(typeid(property), poly_type(p));
321 EXPECT_EQ(42, p.prop());
323 EXPECT_EQ(68, p.prop());
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));
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);
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);
347 MoveOnly_() = default;
348 MoveOnly_(MoveOnly_&&) = default;
349 MoveOnly_(MoveOnly_ const&) = delete;
350 MoveOnly_& operator=(MoveOnly_&&) = default;
351 MoveOnly_& operator=(MoveOnly_ const&) = delete;
358 Poly<IMoveOnly&> p = i;
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));
367 Poly<ISemiRegular const&> p = i;
368 auto q = poly_move(p);
370 std::is_same<decltype(q), Poly<ISemiRegular const&>>::value, "");
371 EXPECT_EQ(&poly_cast<int>(p), &poly_cast<int>(q));
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, "");
381 TEST(Poly, RValueRef) {
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));
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)...));
404 FOLLY_POLY_MEMBERS(FOLLY_POLY_MEMBER(R(As...) const, &T::operator()));
408 using Function = Poly<IFunction<Fun>>;
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));
419 // This multiply extends IEqualityComparable
420 struct IDiamond : PolyExtends<IRegular, INullablePointer> {};
423 TEST(Poly, DiamondInheritance) {
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));
438 EXPECT_EQ(0, Big::s_count);
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));
454 EXPECT_EQ(0, Big::s_count);
459 int property() const {
462 void property(int) {}
464 struct Struct2 : Struct {
477 int property(Struct const&) {
480 void property(Struct&, int) {}
489 int purr(Struct2 const&) {
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);
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);
506 auto m4 = folly::sig<long()>(&Struct2::meow);
507 EXPECT_EQ(&Struct2::meow, m4);
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);
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);
520 auto m2 = folly::sig<long(Struct2&)>(&::meow);
521 EXPECT_EQ(&::meow, m2);
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);
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);
541 static auto plus_(T const& a, T const& b) -> decltype(a + b) {
546 using Members = FOLLY_POLY_MEMBERS(&plus_<std::decay_t<T>>);
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));
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));
562 EXPECT_EQ(5, poly_cast<int>(cc));
564 EXPECT_EQ(6, poly_cast<int>(cc));