1 /*
2 * Copyright (c) Facebook, Inc. and its affiliates.
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 <array>
20
21 #include <folly/Conv.h>
22 #include <folly/CppAttributes.h>
23 #include <folly/poly/Nullable.h>
24 #include <folly/poly/Regular.h>
25 #include <folly/portability/GTest.h>
26
27 using namespace folly;
28 using namespace folly::poly;
29
30 namespace {
31 template <class T>
32 struct Big_t {
33 private:
34 std::array<char, sizeof(Poly<ISemiRegular>) + 1> data_;
35 T t_;
36
37 public:
Big_t__anonfdb577f40111::Big_t38 Big_t() : data_{}, t_() { ++s_count; }
Big_t__anonfdb577f40111::Big_t39 explicit Big_t(T t) : data_{}, t_(t) { ++s_count; }
Big_t__anonfdb577f40111::Big_t40 Big_t(Big_t const& that) : data_(that.data_), t_(that.t_) { ++s_count; }
~Big_t__anonfdb577f40111::Big_t41 ~Big_t() { --s_count; }
42 Big_t& operator=(Big_t const&) = default;
value__anonfdb577f40111::Big_t43 T value() const { return t_; }
operator ==(Big_t const & a,Big_t const & b)44 friend bool operator==(Big_t const& a, Big_t const& b) {
45 return a.value() == b.value();
46 }
operator !=(Big_t const & a,Big_t const & b)47 friend bool operator!=(Big_t const& a, Big_t const& b) { return !(a == b); }
operator <(Big_t const & a,Big_t const & b)48 friend bool operator<(Big_t const& a, Big_t const& b) {
49 return a.value() < b.value();
50 }
51 static std::ptrdiff_t s_count;
52 };
53 template <class T>
54 std::ptrdiff_t Big_t<T>::s_count = 0;
55
56 using Big = Big_t<int>;
57 using BigDouble = Big_t<double>;
58 } // namespace
59
TEST(Poly,SemiRegular)60 TEST(Poly, SemiRegular) {
61 {
62 // A small object, storable in-situ:
63 Poly<ISemiRegular> p = 42;
64 EXPECT_EQ(typeid(int), poly_type(p));
65 EXPECT_EQ(42, poly_cast<int>(p));
66 EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
67 Poly<ISemiRegular> p2 = p;
68 EXPECT_EQ(typeid(int), poly_type(p2));
69 EXPECT_EQ(42, poly_cast<int>(p2));
70 EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
71 }
72
73 EXPECT_EQ(0, Big::s_count);
74 {
75 // A big object, stored on the heap:
76 Poly<ISemiRegular> p = Big(42);
77 EXPECT_EQ(1, Big::s_count);
78 EXPECT_EQ(typeid(Big), poly_type(p));
79 EXPECT_EQ(42, poly_cast<Big>(p).value());
80 EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
81 Poly<ISemiRegular> p2 = p;
82 EXPECT_EQ(2, Big::s_count);
83 EXPECT_EQ(typeid(Big), poly_type(p2));
84 EXPECT_EQ(42, poly_cast<Big>(p2).value());
85 EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
86 }
87 EXPECT_EQ(0, Big::s_count);
88
89 // four swap cases
90 //
91
92 {
93 // A small object, storable in-situ:
94 Poly<ISemiRegular> p = 42;
95 EXPECT_EQ(typeid(int), poly_type(p));
96 EXPECT_EQ(42, poly_cast<int>(p));
97 EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
98 // A small object, storable in-situ:
99 Poly<ISemiRegular> p2 = 4.2;
100 EXPECT_EQ(typeid(double), poly_type(p2));
101 EXPECT_EQ(4.2, poly_cast<double>(p2));
102 EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
103 std::swap(p, p2);
104 EXPECT_EQ(typeid(double), poly_type(p));
105 EXPECT_EQ(4.2, poly_cast<double>(p));
106 EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
107 EXPECT_EQ(typeid(int), poly_type(p2));
108 EXPECT_EQ(42, poly_cast<int>(p2));
109 EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
110 using std::swap;
111 swap(p, p2);
112 EXPECT_EQ(typeid(int), poly_type(p));
113 EXPECT_EQ(42, poly_cast<int>(p));
114 EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
115 EXPECT_EQ(typeid(double), poly_type(p2));
116 EXPECT_EQ(4.2, poly_cast<double>(p2));
117 EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
118 }
119
120 EXPECT_EQ(0, Big::s_count);
121 EXPECT_EQ(0, BigDouble::s_count);
122 {
123 // A big object, stored on the heap:
124 Poly<ISemiRegular> p = Big(42);
125 EXPECT_EQ(1, Big::s_count);
126 EXPECT_EQ(typeid(Big), poly_type(p));
127 EXPECT_EQ(42, poly_cast<Big>(p).value());
128 EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
129 // A big object, stored on the heap:
130 Poly<ISemiRegular> p2 = BigDouble(4.2);
131 EXPECT_EQ(1, BigDouble::s_count);
132 EXPECT_EQ(typeid(BigDouble), poly_type(p2));
133 EXPECT_EQ(4.2, poly_cast<BigDouble>(p2).value());
134 EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
135 std::swap(p, p2);
136 EXPECT_EQ(1, Big::s_count);
137 EXPECT_EQ(1, BigDouble::s_count);
138 EXPECT_EQ(typeid(BigDouble), poly_type(p));
139 EXPECT_EQ(4.2, poly_cast<BigDouble>(p).value());
140 EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
141 EXPECT_EQ(typeid(Big), poly_type(p2));
142 EXPECT_EQ(42, poly_cast<Big>(p2).value());
143 EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
144 using std::swap;
145 swap(p, p2);
146 EXPECT_EQ(1, Big::s_count);
147 EXPECT_EQ(1, BigDouble::s_count);
148 EXPECT_EQ(typeid(Big), poly_type(p));
149 EXPECT_EQ(42, poly_cast<Big>(p).value());
150 EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
151 EXPECT_EQ(typeid(BigDouble), poly_type(p2));
152 EXPECT_EQ(4.2, poly_cast<BigDouble>(p2).value());
153 EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
154 }
155 EXPECT_EQ(0, BigDouble::s_count);
156 EXPECT_EQ(0, Big::s_count);
157
158 EXPECT_EQ(0, Big::s_count);
159 {
160 // A big object, stored on the heap:
161 Poly<ISemiRegular> p = Big(42);
162 EXPECT_EQ(1, Big::s_count);
163 EXPECT_EQ(typeid(Big), poly_type(p));
164 EXPECT_EQ(42, poly_cast<Big>(p).value());
165 EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
166 // A small object, storable in-situ:
167 Poly<ISemiRegular> p2 = 4.2;
168 EXPECT_EQ(typeid(double), poly_type(p2));
169 EXPECT_EQ(4.2, poly_cast<double>(p2));
170 EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
171 std::swap(p, p2);
172 EXPECT_EQ(1, Big::s_count);
173 EXPECT_EQ(typeid(double), poly_type(p));
174 EXPECT_EQ(4.2, poly_cast<double>(p));
175 EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
176 EXPECT_EQ(typeid(Big), poly_type(p2));
177 EXPECT_EQ(42, poly_cast<Big>(p2).value());
178 EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
179 using std::swap;
180 swap(p, p2);
181 EXPECT_EQ(1, Big::s_count);
182 EXPECT_EQ(typeid(Big), poly_type(p));
183 EXPECT_EQ(42, poly_cast<Big>(p).value());
184 EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
185 EXPECT_EQ(typeid(double), poly_type(p2));
186 EXPECT_EQ(4.2, poly_cast<double>(p2));
187 EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
188 }
189 EXPECT_EQ(0, Big::s_count);
190
191 EXPECT_EQ(0, BigDouble::s_count);
192 {
193 // A small object, storable in-situ:
194 Poly<ISemiRegular> p = 42;
195 EXPECT_EQ(typeid(int), poly_type(p));
196 EXPECT_EQ(42, poly_cast<int>(p));
197 EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
198 // A big object, stored on the heap:
199 Poly<ISemiRegular> p2 = BigDouble(4.2);
200 EXPECT_EQ(1, BigDouble::s_count);
201 EXPECT_EQ(typeid(BigDouble), poly_type(p2));
202 EXPECT_EQ(4.2, poly_cast<BigDouble>(p2).value());
203 EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
204 std::swap(p, p2);
205 EXPECT_EQ(1, BigDouble::s_count);
206 EXPECT_EQ(typeid(BigDouble), poly_type(p));
207 EXPECT_EQ(4.2, poly_cast<BigDouble>(p).value());
208 EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
209 EXPECT_EQ(typeid(int), poly_type(p2));
210 EXPECT_EQ(42, poly_cast<int>(p2));
211 EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
212 using std::swap;
213 swap(p, p2);
214 EXPECT_EQ(1, BigDouble::s_count);
215 EXPECT_EQ(typeid(int), poly_type(p));
216 EXPECT_EQ(42, poly_cast<int>(p));
217 EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
218 EXPECT_EQ(typeid(BigDouble), poly_type(p2));
219 EXPECT_EQ(4.2, poly_cast<BigDouble>(p2).value());
220 EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
221 }
222 EXPECT_EQ(0, BigDouble::s_count);
223 }
224
TEST(Poly,EqualityComparable)225 TEST(Poly, EqualityComparable) {
226 {
227 Poly<IEqualityComparable> p = 42;
228 Poly<IEqualityComparable> q = 42;
229 EXPECT_TRUE(p == q);
230 EXPECT_TRUE(q == p);
231 EXPECT_FALSE(p != q);
232 EXPECT_FALSE(q != p);
233 p = 43;
234 EXPECT_FALSE(p == q);
235 EXPECT_FALSE(q == p);
236 EXPECT_TRUE(p != q);
237 EXPECT_TRUE(q != p);
238 }
239 {
240 // empty not equal
241 Poly<IEqualityComparable> p;
242 Poly<IEqualityComparable> q = 42;
243 EXPECT_FALSE(p == q);
244 EXPECT_FALSE(q == p);
245 }
246 {
247 // empty equal
248 Poly<IEqualityComparable> p;
249 Poly<IEqualityComparable> q;
250 EXPECT_TRUE(p == q);
251 EXPECT_TRUE(q == p);
252 }
253 {
254 // mismatched types throws
255 Poly<IEqualityComparable> p = 4.2;
256 Poly<IEqualityComparable> q = 42;
257 EXPECT_THROW((void)(q == p), BadPolyCast);
258 }
259 }
260
TEST(Poly,StrictlyOrderable)261 TEST(Poly, StrictlyOrderable) {
262 {
263 // A small object, storable in-situ:
264 Poly<IStrictlyOrderable> p = 42;
265 Poly<IStrictlyOrderable> q = 43;
266 EXPECT_TRUE(p < q);
267 EXPECT_TRUE(p <= q);
268 EXPECT_FALSE(p > q);
269 EXPECT_FALSE(p >= q);
270 EXPECT_TRUE(q > p);
271 EXPECT_TRUE(q >= p);
272 EXPECT_FALSE(q < p);
273 EXPECT_FALSE(q <= p);
274 }
275 {
276 // A big object, stored on the heap:
277 Poly<IStrictlyOrderable> p = Big(42);
278 Poly<IStrictlyOrderable> q = Big(43);
279 EXPECT_TRUE(p < q);
280 }
281 {
282 // if equal, no one is bigger
283 Poly<IStrictlyOrderable> p = 42;
284 Poly<IStrictlyOrderable> q = 42;
285 EXPECT_FALSE(p < q);
286 EXPECT_TRUE(p <= q);
287 EXPECT_FALSE(p > q);
288 EXPECT_TRUE(p >= q);
289 EXPECT_FALSE(q < p);
290 EXPECT_TRUE(q <= p);
291 EXPECT_FALSE(q > p);
292 EXPECT_TRUE(q >= p);
293 }
294 {
295 // empty is always smaller
296 Poly<IStrictlyOrderable> p;
297 Poly<IStrictlyOrderable> q = 42;
298 EXPECT_TRUE(p < q);
299 EXPECT_FALSE(q < p);
300 }
301 {
302 // mismatched types throws
303 Poly<IStrictlyOrderable> p = 4.2;
304 Poly<IStrictlyOrderable> q = 42;
305 EXPECT_THROW((void)(p < q), BadPolyCast);
306 EXPECT_THROW((void)(q < p), BadPolyCast);
307 }
308 }
309
TEST(Poly,SemiRegularReference)310 TEST(Poly, SemiRegularReference) {
311 int i = 42;
312 Poly<ISemiRegular&> p = i;
313 EXPECT_EQ(42, i);
314 EXPECT_EQ(typeid(int), poly_type(p));
315 EXPECT_EQ(42, poly_cast<int>(p));
316 EXPECT_EQ(&i, &poly_cast<int>(p));
317 EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
318 Poly<ISemiRegular&> p2 = p;
319 EXPECT_EQ(typeid(int), poly_type(p2));
320 EXPECT_EQ(42, poly_cast<int>(p2));
321 EXPECT_EQ(&i, &poly_cast<int>(p2));
322 EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
323 std::swap(p, p2);
324 EXPECT_EQ(typeid(int), poly_type(p2));
325 EXPECT_EQ(42, poly_cast<int>(p2));
326 EXPECT_EQ(&i, &poly_cast<int>(p2));
327 EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
328 using std::swap;
329 swap(p, p2);
330 EXPECT_EQ(typeid(int), poly_type(p2));
331 EXPECT_EQ(42, poly_cast<int>(p2));
332 EXPECT_EQ(&i, &poly_cast<int>(p2));
333 EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
334 // Can't default-initialize reference-like Poly's:
335 static_assert(!std::is_default_constructible<Poly<ISemiRegular&>>::value, "");
336 }
337
TEST(Poly,Conversions)338 TEST(Poly, Conversions) {
339 int i = 42;
340 Poly<ISemiRegular> p1 = i;
341 Poly<ISemiRegular&> p2 = p1;
342 EXPECT_EQ(&poly_cast<int>(p1), &poly_cast<int>(p2));
343 Poly<ISemiRegular const&> p3 = p1;
344 Poly<ISemiRegular const&> p4 = p2;
345 EXPECT_EQ(&poly_cast<int>(p3), &poly_cast<int>(p1));
346 EXPECT_EQ(&poly_cast<int>(p4), &poly_cast<int>(p1));
347 static_assert(
348 !std::is_constructible<Poly<ISemiRegular&>, Poly<ISemiRegular const&>&>::
349 value,
350 "");
351 static_assert(
352 !std::is_constructible<Poly<ISemiRegular>, Poly<ISemiRegular const&>&>::
353 value,
354 "");
355 }
356
TEST(Poly,EqualityComparableReference)357 TEST(Poly, EqualityComparableReference) {
358 int i = 42;
359 int j = 42;
360 Poly<IEqualityComparable&> p1 = i;
361 Poly<IEqualityComparable&> p2 = j;
362 EXPECT_EQ(&i, &poly_cast<int>(p1));
363 EXPECT_EQ(&j, &poly_cast<int>(p2));
364 EXPECT_TRUE(p1 == p2);
365 EXPECT_FALSE(p1 != p2);
366 j = 43;
367 EXPECT_FALSE(p1 == p2);
368 EXPECT_TRUE(p1 != p2);
369 EXPECT_EQ(42, poly_cast<int>(p1));
370 EXPECT_EQ(43, poly_cast<int>(p2));
371 }
372
373 namespace {
374 struct Foo {
375 template <class Base>
376 struct Interface : Base {
foo__anonfdb577f40211::Foo::Interface377 void foo(int& i) { folly::poly_call<0>(*this, i); }
378 };
379
380 template <class T>
381 using Members = FOLLY_POLY_MEMBERS(&T::foo);
382 };
383
384 struct foo_ {
385 foo_() = default;
foo___anonfdb577f40211::foo_386 explicit foo_(int i) : j_(i) {}
foo__anonfdb577f40211::foo_387 void foo(int& i) { i += j_; }
388
389 private:
390 int j_ = 0;
391 };
392 } // namespace
393
TEST(Poly,Singular)394 TEST(Poly, Singular) {
395 Poly<Foo> p = foo_{42};
396 int i = 1;
397 p.foo(i);
398 EXPECT_EQ(43, i);
399 EXPECT_EQ(typeid(foo_), poly_type(p));
400 }
401
402 namespace {
403 struct FooBar : PolyExtends<Foo> {
404 template <class Base>
405 struct Interface : Base {
bar__anonfdb577f40311::FooBar::Interface406 std::string bar(int i) const { return folly::poly_call<0>(*this, i); }
407 };
408
409 template <class T>
410 using Members = FOLLY_POLY_MEMBERS(&T::bar);
411 };
412
413 struct foo_bar {
414 foo_bar() = default;
foo_bar__anonfdb577f40311::foo_bar415 explicit foo_bar(int i) : j_(i) {}
foo__anonfdb577f40311::foo_bar416 void foo(int& i) { i += j_; }
bar__anonfdb577f40311::foo_bar417 std::string bar(int i) const {
418 i += j_;
419 return folly::to<std::string>(i);
420 }
421
422 private:
423 int j_ = 0;
424 };
425 } // namespace
426
TEST(Poly,SingleInheritance)427 TEST(Poly, SingleInheritance) {
428 Poly<FooBar> p = foo_bar{42};
429 int i = 1;
430 p.foo(i);
431 EXPECT_EQ(43, i);
432 EXPECT_EQ("43", p.bar(1));
433 EXPECT_EQ(typeid(foo_bar), poly_type(p));
434
435 Poly<Foo> q = p; // OK, conversion works.
436 q.foo(i);
437 EXPECT_EQ(85, i);
438
439 Poly<Foo&> r = p;
440 r->foo(i);
441 EXPECT_EQ(127, i);
442 const_cast<Poly<Foo&> const&>(r)->foo(i);
443 EXPECT_EQ(169, i);
444
445 Poly<FooBar const&> cr = p;
446 // cr->foo(i); // ERROR: calls a non-const member through a const reference
447 cr->bar(i); // OK
448 }
449
450 namespace {
451 struct Baz {
452 template <class Base>
453 struct Interface : Base {
baz__anonfdb577f40411::Baz::Interface454 std::string baz(int i, int j) const {
455 return folly::poly_call<0>(*this, i, j);
456 }
457 };
458
459 template <class T>
460 using Members = FOLLY_POLY_MEMBERS(&T::baz);
461 };
462
463 struct FooBarBazFizz : PolyExtends<FooBar, Baz> {
464 template <class Base>
465 struct Interface : Base {
fizz__anonfdb577f40411::FooBarBazFizz::Interface466 std::string fizz() const { return folly::poly_call<0>(*this); }
467 };
468
469 template <class T>
470 using Members = FOLLY_POLY_MEMBERS(&T::fizz);
471 };
472
473 struct foo_bar_baz_fizz {
474 foo_bar_baz_fizz() = default;
foo_bar_baz_fizz__anonfdb577f40411::foo_bar_baz_fizz475 explicit foo_bar_baz_fizz(int i) : j_(i) {}
foo__anonfdb577f40411::foo_bar_baz_fizz476 void foo(int& i) { i += j_; }
bar__anonfdb577f40411::foo_bar_baz_fizz477 std::string bar(int i) const { return folly::to<std::string>(i + j_); }
baz__anonfdb577f40411::foo_bar_baz_fizz478 std::string baz(int i, int j) const { return folly::to<std::string>(i + j); }
fizz__anonfdb577f40411::foo_bar_baz_fizz479 std::string fizz() const { return "fizz"; }
480
481 private:
482 int j_ = 0;
483 };
484 } // namespace
485
TEST(Poly,MultipleInheritance)486 TEST(Poly, MultipleInheritance) {
487 Poly<FooBarBazFizz> p = foo_bar_baz_fizz{42};
488 int i = 1;
489 p.foo(i);
490 EXPECT_EQ(43, i);
491 EXPECT_EQ("43", p.bar(1));
492 EXPECT_EQ("3", p.baz(1, 2));
493 EXPECT_EQ("fizz", p.fizz());
494 EXPECT_EQ(typeid(foo_bar_baz_fizz), poly_type(p));
495 }
496
497 namespace {
498 struct Property {
499 template <class Base>
500 struct Interface : Base {
prop__anonfdb577f40511::Property::Interface501 int prop() const { return folly::poly_call<0>(*this); }
prop__anonfdb577f40511::Property::Interface502 void prop(int i) { folly::poly_call<1>(*this, i); }
503 };
504
505 template <class T>
506 using Members = FOLLY_POLY_MEMBERS(
507 FOLLY_POLY_MEMBER(int() const, &T::prop),
508 FOLLY_POLY_MEMBER(void(int), &T::prop));
509 };
510
511 struct has_property {
512 has_property() = default;
has_property__anonfdb577f40511::has_property513 explicit has_property(int i) : j(i) {}
prop__anonfdb577f40511::has_property514 int prop() const { return j; }
prop__anonfdb577f40511::has_property515 void prop(int i) { j = i; }
516
517 private:
518 int j = 0;
519 };
520 } // namespace
521
TEST(Poly,OverloadedMembers)522 TEST(Poly, OverloadedMembers) {
523 Poly<Property> p = has_property{42};
524 EXPECT_EQ(typeid(has_property), poly_type(p));
525 EXPECT_EQ(42, p.prop());
526 p.prop(68);
527 EXPECT_EQ(68, p.prop());
528 }
529
TEST(Poly,NullablePointer)530 TEST(Poly, NullablePointer) {
531 Poly<INullablePointer> p = nullptr;
532 Poly<INullablePointer> q{};
533 EXPECT_EQ(typeid(void), poly_type(p));
534 EXPECT_TRUE(poly_empty(p));
535 EXPECT_TRUE(p == q);
536 EXPECT_FALSE(p != q);
537 EXPECT_TRUE(p == nullptr);
538 EXPECT_TRUE(nullptr == p);
539 EXPECT_FALSE(p != nullptr);
540 EXPECT_FALSE(nullptr != p);
541
542 // No null references ever.
543 Poly<INullablePointer> r = 42;
544 Poly<INullablePointer&> s = r;
545 static_assert(!poly_empty(s), "");
546 EXPECT_THROW(Poly<INullablePointer&> r_(q), BadPolyAccess);
547 }
548
549 namespace {
550 struct MoveOnly_ {
551 MoveOnly_() = default;
552 MoveOnly_(MoveOnly_&&) = default;
553 MoveOnly_(MoveOnly_ const&) = delete;
554 MoveOnly_& operator=(MoveOnly_&&) = default;
555 MoveOnly_& operator=(MoveOnly_ const&) = delete;
556 };
557 } // namespace
558
TEST(Poly,Move)559 TEST(Poly, Move) {
560 {
561 int i = 42;
562 Poly<IMoveOnly&> p = i;
563 static_assert(
564 !std::is_convertible<Poly<IMoveOnly&>, Poly<IMoveOnly&&>>::value, "");
565 auto q = poly_move(p);
566 static_assert(std::is_same<decltype(q), Poly<IMoveOnly&&>>::value, "");
567 EXPECT_EQ(&poly_cast<int>(p), &poly_cast<int>(q));
568 }
569 {
570 int i = 42;
571 Poly<ISemiRegular const&> p = i;
572 auto q = poly_move(p);
573 static_assert(
574 std::is_same<decltype(q), Poly<ISemiRegular const&>>::value, "");
575 EXPECT_EQ(&poly_cast<int>(p), &poly_cast<int>(q));
576 }
577 {
578 Poly<IMoveOnly> p = MoveOnly_{};
579 static_assert(!std::is_copy_constructible<Poly<IMoveOnly>>::value, "");
580 auto q = poly_move(p);
581 static_assert(std::is_same<decltype(q), Poly<IMoveOnly>>::value, "");
582 }
583 }
584
TEST(Poly,RValueRef)585 TEST(Poly, RValueRef) {
586 int i = 42;
587 Poly<ISemiRegular&&> p = std::move(i);
588 static_assert(std::is_same<decltype(poly_cast<int>(p)), int&>::value, "");
589 EXPECT_EQ(&i, &poly_cast<int>(p));
590 }
591
592 namespace {
593 template <class Fun>
594 struct IFunction;
595
596 template <class R, class... As>
597 struct IFunction<R(As...)> {
598 template <class Base>
599 struct Interface : Base {
operator ()__anonfdb577f40711::IFunction::Interface600 R operator()(As... as) const {
601 return static_cast<R>(
602 folly::poly_call<0>(*this, std::forward<As>(as)...));
603 }
604 };
605
606 template <class T>
607 using Members =
608 FOLLY_POLY_MEMBERS(FOLLY_POLY_MEMBER(R(As...) const, &T::operator()));
609 };
610
611 template <class Fun>
612 using Function = Poly<IFunction<Fun>>;
613 } // namespace
614
TEST(Poly,Function)615 TEST(Poly, Function) {
616 Function<int(int, int)> fun = std::plus<int>{};
617 EXPECT_EQ(42, fun(22, 20));
618 fun = std::multiplies<int>{};
619 EXPECT_EQ(22 * 20, fun(22, 20));
620 }
621
622 namespace {
623 // This multiply extends IEqualityComparable
624 struct IDiamond : PolyExtends<IRegular, INullablePointer> {};
625 } // namespace
626
TEST(Poly,DiamondInheritance)627 TEST(Poly, DiamondInheritance) {
628 {
629 // A small object, storable in-situ:
630 Poly<IDiamond> p = 42;
631 EXPECT_EQ(typeid(int), poly_type(p));
632 EXPECT_EQ(42, poly_cast<int>(p));
633 EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
634 Poly<IDiamond> p2 = p;
635 EXPECT_EQ(typeid(int), poly_type(p2));
636 EXPECT_EQ(42, poly_cast<int>(p2));
637 EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
638 Poly<IEqualityComparable&> eq = p;
639 EXPECT_EQ(&poly_cast<int>(p), &poly_cast<int>(eq));
640 }
641
642 EXPECT_EQ(0, Big::s_count);
643 {
644 // A big object, stored on the heap:
645 Poly<IDiamond> p = Big(42);
646 EXPECT_EQ(1, Big::s_count);
647 EXPECT_EQ(typeid(Big), poly_type(p));
648 EXPECT_EQ(42, poly_cast<Big>(p).value());
649 EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
650 Poly<IDiamond> p2 = p;
651 EXPECT_EQ(2, Big::s_count);
652 EXPECT_EQ(typeid(Big), poly_type(p2));
653 EXPECT_EQ(42, poly_cast<Big>(p2).value());
654 EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
655 Poly<IEqualityComparable&> eq = p;
656 EXPECT_EQ(&poly_cast<Big>(p), &poly_cast<Big>(eq));
657 }
658 EXPECT_EQ(0, Big::s_count);
659 }
660
661 namespace {
662 struct Struct {
property__anonfdb577f40911::Struct663 int property() const { return 42; }
property__anonfdb577f40911::Struct664 void property(int) {}
665 };
666 struct Struct2 : Struct {
meow__anonfdb577f40911::Struct2667 int meow() { return 42; }
668
purr__anonfdb577f40911::Struct2669 int purr() { return 1; }
purr__anonfdb577f40911::Struct2670 int purr() const { return 2; }
671 };
672
property(Struct const &)673 int property(Struct const&) {
674 return 42;
675 }
property(Struct &,int)676 FOLLY_MAYBE_UNUSED void property(Struct&, int) {}
677
meow(Struct2 &)678 int meow(Struct2&) {
679 return 42;
680 }
681
purr(Struct2 &)682 int purr(Struct2&) {
683 return 1;
684 }
purr(Struct2 const &)685 int purr(Struct2 const&) {
686 return 2;
687 }
688 } // namespace
689
TEST(Poly,Sig)690 TEST(Poly, Sig) {
691 {
692 auto m0 = folly::sig<int() const>(&Struct::property);
693 EXPECT_EQ(static_cast<int (Struct::*)() const>(&Struct::property), m0);
694 auto m1 = folly::sig<int()>(&Struct::property);
695 EXPECT_EQ(static_cast<int (Struct::*)() const>(&Struct::property), m1);
696
697 auto m2 = folly::sig<int() const>(&Struct2::property);
698 EXPECT_EQ(static_cast<int (Struct2::*)() const>(&Struct2::property), m2);
699 auto m3 = folly::sig<int()>(&Struct2::property);
700 EXPECT_EQ(static_cast<int (Struct2::*)() const>(&Struct2::property), m3);
701
702 auto m4 = folly::sig<long()>(&Struct2::meow);
703 EXPECT_EQ(&Struct2::meow, m4);
704
705 auto m5 = folly::sig<int()>(&Struct2::purr);
706 EXPECT_EQ(static_cast<int (Struct2::*)()>(&Struct2::purr), m5);
707 auto m6 = folly::sig<int() const>(&Struct2::purr);
708 EXPECT_EQ(static_cast<int (Struct2::*)() const>(&Struct2::purr), m6);
709 }
710 {
711 auto m0 = folly::sig<int(Struct const&)>(&::property);
712 EXPECT_EQ(static_cast<int (*)(Struct const&)>(&::property), m0);
713 auto m1 = folly::sig<int(Struct&)>(&::property);
714 EXPECT_EQ(static_cast<int (*)(Struct const&)>(&::property), m1);
715
716 auto m2 = folly::sig<long(Struct2&)>(&::meow);
717 EXPECT_EQ(&::meow, m2);
718
719 auto m3 = folly::sig<int(Struct2&)>(&::purr);
720 EXPECT_EQ(static_cast<int (*)(Struct2&)>(&::purr), m3);
721 auto m4 = folly::sig<int(Struct2 const&)>(&::purr);
722 EXPECT_EQ(static_cast<int (*)(Struct2 const&)>(&::purr), m4);
723 }
724 }
725
726 namespace {
727 struct IAddable {
728 template <class Base>
729 struct Interface : Base {
operator +__anonfdb577f40a11::IAddable730 friend PolySelf<Base, PolyDecay> operator+(
731 PolySelf<Base> const& a, PolySelf<Base> const& b) {
732 return folly::poly_call<0, IAddable>(a, b);
733 }
734 };
735 template <class T>
plus___anonfdb577f40a11::IAddable736 static auto plus_(T const& a, T const& b) -> decltype(a + b) {
737 return a + b;
738 }
739
740 template <class T>
741 using Members = FOLLY_POLY_MEMBERS(&plus_<std::decay_t<T>>);
742 };
743 } // namespace
744
TEST(Poly,Addable)745 TEST(Poly, Addable) {
746 Poly<IAddable> a = 2, b = 3;
747 Poly<IAddable> c = a + b;
748 EXPECT_EQ(typeid(int), poly_type(c));
749 EXPECT_EQ(5, poly_cast<int>(c));
750
751 Poly<IAddable const&> aref = a, bref = b;
752 auto cc = aref + bref;
753 static_assert(std::is_same<decltype(cc), Poly<IAddable>>::value, "");
754 EXPECT_EQ(typeid(int), poly_type(cc));
755 EXPECT_EQ(5, poly_cast<int>(cc));
756 b = 4;
757 EXPECT_EQ(5, poly_cast<int>(cc));
758 cc = aref + bref;
759 EXPECT_EQ(6, poly_cast<int>(cc));
760 }
761
762 namespace {
763 struct IFrobnicator {
764 template <class Base>
765 struct Interface : Base {
frobnicate__anonfdb577f40b11::IFrobnicator::Interface766 void frobnicate(folly::Poly<folly::poly::IRegular&> x) {
767 folly::poly_call<0>(*this, x);
768 }
769 };
770 template <class T>
771 using Members = FOLLY_POLY_MEMBERS(&T::frobnicate);
772 };
773 using Frobnicator = folly::Poly<IFrobnicator>;
774
775 struct my_frobnicator {
frobnicate__anonfdb577f40b11::my_frobnicator776 void frobnicate(folly::Poly<folly::poly::IRegular&>) {
777 // no-op
778 }
779 };
780 } // namespace
781
TEST(Poly,PolyRefAsArg)782 TEST(Poly, PolyRefAsArg) {
783 folly::Poly<folly::poly::IRegular> x = 42;
784 Frobnicator frob = my_frobnicator{};
785 // should not throw:
786 frob.frobnicate(x);
787 // should not throw:
788 frob.frobnicate(folly::Poly<folly::poly::IRegular&>(x));
789 }
790
791 namespace {
792 struct ICat {
793 template <class Base>
794 struct Interface : Base {
pet__anonfdb577f40c11::ICat::Interface795 void pet() { folly::poly_call<0>(*this); }
796
meow__anonfdb577f40c11::ICat::Interface797 int meow() const { return folly::poly_call<1>(*this); }
798 };
799
800 template <class T>
801 using Members = FOLLY_POLY_MEMBERS(&T::pet, &T::meow);
802 };
803
804 struct cat {
pet__anonfdb577f40c11::cat805 void pet() noexcept { ++pet_count; }
meow__anonfdb577f40c11::cat806 int meow() const noexcept { return pet_count; }
807 int pet_count = 0;
808 };
809 } // namespace
810
TEST(Poly,NoexceptMembers)811 TEST(Poly, NoexceptMembers) {
812 cat c{};
813
814 folly::Poly<ICat&> ref = c;
815 ref->pet();
816
817 folly::Poly<ICat const&> cref = ref;
818 EXPECT_EQ(cref->meow(), 1);
819 }
820