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 #include <folly/Poly.h>
19 #include <folly/Conv.h>
20 #include <folly/poly/Nullable.h>
21 #include <folly/poly/Regular.h>
22 #include <folly/portability/GTest.h>
26 using namespace folly;
27 using namespace folly::poly;
32 std::array<char, sizeof(Poly<ISemiRegular>) + 1> data_;
36 Big() : data_{}, i_(0) {
39 explicit Big(int i) : data_{}, i_(i) {
42 Big(Big const& that) : data_(that.data_), i_(that.i_) {
48 Big& operator=(Big const&) = default;
52 friend bool operator==(Big const& a, Big const& b) {
53 return a.value() == b.value();
55 friend bool operator!=(Big const& a, Big const& b) {
58 static std::ptrdiff_t s_count;
60 std::ptrdiff_t Big::s_count = 0;
63 TEST(Poly, SemiRegular) {
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);
76 EXPECT_EQ(0, Big::s_count);
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);
90 EXPECT_EQ(0, Big::s_count);
93 TEST(Poly, SemiRegularReference) {
95 Poly<ISemiRegular&> p = 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, "");
105 TEST(Poly, Conversions) {
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));
115 !std::is_constructible<Poly<ISemiRegular&>, Poly<ISemiRegular const&>&>::
119 !std::is_constructible<Poly<ISemiRegular>, Poly<ISemiRegular const&>&>::
124 TEST(Poly, EqualityComparableReference) {
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);
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));
142 template <class Base>
143 struct Interface : Base {
145 folly::poly_call<0>(*this, i);
150 using Members = FOLLY_POLY_MEMBERS(&T::foo);
155 explicit foo_(int i) : j_(i) {}
165 TEST(Poly, Singular) {
166 Poly<Foo> p = foo_{42};
170 EXPECT_EQ(typeid(foo_), poly_type(p));
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);
183 using Members = FOLLY_POLY_MEMBERS(&T::bar);
188 explicit foo_bar(int i) : j_(i) {}
192 std::string bar(int i) const {
194 return folly::to<std::string>(i);
202 TEST(Poly, SingleInheritance) {
203 Poly<FooBar> p = foo_bar{42};
207 EXPECT_EQ("43", p.bar(1));
208 EXPECT_EQ(typeid(foo_bar), poly_type(p));
210 Poly<Foo> q = p; // OK, conversion works.
217 const_cast<Poly<Foo&> const&>(r)->foo(i);
220 Poly<FooBar const&> cr = p;
221 // cr->foo(i); // ERROR: calls a non-const member through a const reference
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);
235 using Members = FOLLY_POLY_MEMBERS(&T::baz);
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);
247 using Members = FOLLY_POLY_MEMBERS(&T::fizz);
250 struct foo_bar_baz_fizz {
251 foo_bar_baz_fizz() = default;
252 explicit foo_bar_baz_fizz(int i) : j_(i) {}
256 std::string bar(int i) const {
257 return folly::to<std::string>(i + j_);
259 std::string baz(int i, int j) const {
260 return folly::to<std::string>(i + j);
262 std::string fizz() const {
271 TEST(Poly, MultipleInheritance) {
272 Poly<FooBarBazFizz> p = foo_bar_baz_fizz{42};
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));
284 template <class Base>
285 struct Interface : Base {
287 return folly::poly_call<0>(*this);
290 folly::poly_call<1>(*this, i);
295 using Members = FOLLY_POLY_MEMBERS(
296 FOLLY_POLY_MEMBER(int() const, &T::prop),
297 FOLLY_POLY_MEMBER(void(int), &T::prop));
301 property() = default;
302 explicit property(int i) : j(i) {}
315 TEST(Poly, OverloadedMembers) {
316 Poly<Property> p = property{42};
317 EXPECT_EQ(typeid(property), poly_type(p));
318 EXPECT_EQ(42, p.prop());
320 EXPECT_EQ(68, p.prop());
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));
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);
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);
344 MoveOnly_() = default;
345 MoveOnly_(MoveOnly_&&) = default;
346 MoveOnly_(MoveOnly_ const&) = delete;
347 MoveOnly_& operator=(MoveOnly_&&) = default;
348 MoveOnly_& operator=(MoveOnly_ const&) = delete;
355 Poly<IMoveOnly&> p = i;
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));
364 Poly<ISemiRegular const&> p = i;
365 auto q = poly_move(p);
367 std::is_same<decltype(q), Poly<ISemiRegular const&>>::value, "");
368 EXPECT_EQ(&poly_cast<int>(p), &poly_cast<int>(q));
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, "");
378 TEST(Poly, RValueRef) {
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));
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)...));
401 FOLLY_POLY_MEMBERS(FOLLY_POLY_MEMBER(R(As...) const, &T::operator()));
405 using Function = Poly<IFunction<Fun>>;
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));
416 // This multiply extends IEqualityComparable
417 struct IDiamond : PolyExtends<IRegular, INullablePointer> {};
420 TEST(Poly, DiamondInheritance) {
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));
435 EXPECT_EQ(0, Big::s_count);
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));
451 EXPECT_EQ(0, Big::s_count);
456 int property() const {
459 void property(int) {}
461 struct Struct2 : Struct {
474 int property(Struct const&) {
477 void property(Struct&, int) {}
486 int purr(Struct2 const&) {
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);
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);
503 auto m4 = folly::sig<long()>(&Struct2::meow);
504 EXPECT_EQ(&Struct2::meow, m4);
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);
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);
517 auto m2 = folly::sig<long(Struct2&)>(&::meow);
518 EXPECT_EQ(&::meow, m2);
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);
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);
538 static auto plus_(T const& a, T const& b) -> decltype(a + b) {
543 using Members = FOLLY_POLY_MEMBERS(&plus_<std::decay_t<T>>);
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));
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));
559 EXPECT_EQ(5, poly_cast<int>(cc));
561 EXPECT_EQ(6, poly_cast<int>(cc));