proxygen
PolyTest.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2017-present 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 #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 5
17 #pragma message "Folly.Poly requires gcc-5 or greater"
18 #else
19 #include <folly/Poly.h>
20 
21 #include <folly/Conv.h>
22 #include <folly/poly/Nullable.h>
23 #include <folly/poly/Regular.h>
25 
26 #include <array>
27 
28 using namespace folly;
29 using namespace folly::poly;
30 
31 namespace {
32 template <class T>
33 struct Big_t {
34  private:
35  std::array<char, sizeof(Poly<ISemiRegular>) + 1> data_;
36  T t_;
37 
38  public:
39  Big_t() : data_{}, t_() {
40  ++s_count;
41  }
42  explicit Big_t(T t) : data_{}, t_(t) {
43  ++s_count;
44  }
45  Big_t(Big_t const& that) : data_(that.data_), t_(that.t_) {
46  ++s_count;
47  }
48  ~Big_t() {
49  --s_count;
50  }
51  Big_t& operator=(Big_t const&) = default;
52  T value() const {
53  return t_;
54  }
55  friend bool operator==(Big_t const& a, Big_t const& b) {
56  return a.value() == b.value();
57  }
58  friend bool operator!=(Big_t const& a, Big_t const& b) {
59  return !(a == b);
60  }
61  friend bool operator<(Big_t const& a, Big_t const& b) {
62  return a.value() < b.value();
63  }
64  static std::ptrdiff_t s_count;
65 };
66 template <class T>
67 std::ptrdiff_t Big_t<T>::s_count = 0;
68 
69 using Big = Big_t<int>;
70 using BigDouble = Big_t<double>;
71 } // namespace
72 
73 TEST(Poly, SemiRegular) {
74  {
75  // A small object, storable in-situ:
76  Poly<ISemiRegular> p = 42;
77  EXPECT_EQ(typeid(int), poly_type(p));
78  EXPECT_EQ(42, poly_cast<int>(p));
79  EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
80  Poly<ISemiRegular> p2 = p;
81  EXPECT_EQ(typeid(int), poly_type(p2));
82  EXPECT_EQ(42, poly_cast<int>(p2));
83  EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
84  }
85 
86  EXPECT_EQ(0, Big::s_count);
87  {
88  // A big object, stored on the heap:
89  Poly<ISemiRegular> p = Big(42);
90  EXPECT_EQ(1, Big::s_count);
91  EXPECT_EQ(typeid(Big), poly_type(p));
92  EXPECT_EQ(42, poly_cast<Big>(p).value());
93  EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
94  Poly<ISemiRegular> p2 = p;
95  EXPECT_EQ(2, Big::s_count);
96  EXPECT_EQ(typeid(Big), poly_type(p2));
97  EXPECT_EQ(42, poly_cast<Big>(p2).value());
98  EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
99  }
100  EXPECT_EQ(0, Big::s_count);
101 
102  // four swap cases
103  //
104 
105  {
106  // A small object, storable in-situ:
107  Poly<ISemiRegular> p = 42;
108  EXPECT_EQ(typeid(int), poly_type(p));
109  EXPECT_EQ(42, poly_cast<int>(p));
110  EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
111  // A small object, storable in-situ:
112  Poly<ISemiRegular> p2 = 4.2;
113  EXPECT_EQ(typeid(double), poly_type(p2));
114  EXPECT_EQ(4.2, poly_cast<double>(p2));
115  EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
116  std::swap(p, p2);
117  EXPECT_EQ(typeid(double), poly_type(p));
118  EXPECT_EQ(4.2, poly_cast<double>(p));
119  EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
120  EXPECT_EQ(typeid(int), poly_type(p2));
121  EXPECT_EQ(42, poly_cast<int>(p2));
122  EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
123  using std::swap;
124  swap(p, p2);
125  EXPECT_EQ(typeid(int), poly_type(p));
126  EXPECT_EQ(42, poly_cast<int>(p));
127  EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
128  EXPECT_EQ(typeid(double), poly_type(p2));
129  EXPECT_EQ(4.2, poly_cast<double>(p2));
130  EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
131  }
132 
133  EXPECT_EQ(0, Big::s_count);
134  EXPECT_EQ(0, BigDouble::s_count);
135  {
136  // A big object, stored on the heap:
137  Poly<ISemiRegular> p = Big(42);
138  EXPECT_EQ(1, Big::s_count);
139  EXPECT_EQ(typeid(Big), poly_type(p));
140  EXPECT_EQ(42, poly_cast<Big>(p).value());
141  EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
142  // A big object, stored on the heap:
143  Poly<ISemiRegular> p2 = BigDouble(4.2);
144  EXPECT_EQ(1, BigDouble::s_count);
145  EXPECT_EQ(typeid(BigDouble), poly_type(p2));
146  EXPECT_EQ(4.2, poly_cast<BigDouble>(p2).value());
147  EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
148  std::swap(p, p2);
149  EXPECT_EQ(1, Big::s_count);
150  EXPECT_EQ(1, BigDouble::s_count);
151  EXPECT_EQ(typeid(BigDouble), poly_type(p));
152  EXPECT_EQ(4.2, poly_cast<BigDouble>(p).value());
153  EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
154  EXPECT_EQ(typeid(Big), poly_type(p2));
155  EXPECT_EQ(42, poly_cast<Big>(p2).value());
156  EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
157  using std::swap;
158  swap(p, p2);
159  EXPECT_EQ(1, Big::s_count);
160  EXPECT_EQ(1, BigDouble::s_count);
161  EXPECT_EQ(typeid(Big), poly_type(p));
162  EXPECT_EQ(42, poly_cast<Big>(p).value());
163  EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
164  EXPECT_EQ(typeid(BigDouble), poly_type(p2));
165  EXPECT_EQ(4.2, poly_cast<BigDouble>(p2).value());
166  EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
167  }
168  EXPECT_EQ(0, BigDouble::s_count);
169  EXPECT_EQ(0, Big::s_count);
170 
171  EXPECT_EQ(0, Big::s_count);
172  {
173  // A big object, stored on the heap:
174  Poly<ISemiRegular> p = Big(42);
175  EXPECT_EQ(1, Big::s_count);
176  EXPECT_EQ(typeid(Big), poly_type(p));
177  EXPECT_EQ(42, poly_cast<Big>(p).value());
178  EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
179  // A small object, storable in-situ:
180  Poly<ISemiRegular> p2 = 4.2;
181  EXPECT_EQ(typeid(double), poly_type(p2));
182  EXPECT_EQ(4.2, poly_cast<double>(p2));
183  EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
184  std::swap(p, p2);
185  EXPECT_EQ(1, Big::s_count);
186  EXPECT_EQ(typeid(double), poly_type(p));
187  EXPECT_EQ(4.2, poly_cast<double>(p));
188  EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
189  EXPECT_EQ(typeid(Big), poly_type(p2));
190  EXPECT_EQ(42, poly_cast<Big>(p2).value());
191  EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
192  using std::swap;
193  swap(p, p2);
194  EXPECT_EQ(1, Big::s_count);
195  EXPECT_EQ(typeid(Big), poly_type(p));
196  EXPECT_EQ(42, poly_cast<Big>(p).value());
197  EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
198  EXPECT_EQ(typeid(double), poly_type(p2));
199  EXPECT_EQ(4.2, poly_cast<double>(p2));
200  EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
201  }
202  EXPECT_EQ(0, Big::s_count);
203 
204  EXPECT_EQ(0, BigDouble::s_count);
205  {
206  // A small object, storable in-situ:
207  Poly<ISemiRegular> p = 42;
208  EXPECT_EQ(typeid(int), poly_type(p));
209  EXPECT_EQ(42, poly_cast<int>(p));
210  EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
211  // A big object, stored on the heap:
212  Poly<ISemiRegular> p2 = BigDouble(4.2);
213  EXPECT_EQ(1, BigDouble::s_count);
214  EXPECT_EQ(typeid(BigDouble), poly_type(p2));
215  EXPECT_EQ(4.2, poly_cast<BigDouble>(p2).value());
216  EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
217  std::swap(p, p2);
218  EXPECT_EQ(1, BigDouble::s_count);
219  EXPECT_EQ(typeid(BigDouble), poly_type(p));
220  EXPECT_EQ(4.2, poly_cast<BigDouble>(p).value());
221  EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
222  EXPECT_EQ(typeid(int), poly_type(p2));
223  EXPECT_EQ(42, poly_cast<int>(p2));
224  EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
225  using std::swap;
226  swap(p, p2);
227  EXPECT_EQ(1, BigDouble::s_count);
228  EXPECT_EQ(typeid(int), poly_type(p));
229  EXPECT_EQ(42, poly_cast<int>(p));
230  EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
231  EXPECT_EQ(typeid(BigDouble), poly_type(p2));
232  EXPECT_EQ(4.2, poly_cast<BigDouble>(p2).value());
233  EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
234  }
235  EXPECT_EQ(0, BigDouble::s_count);
236 }
237 
238 TEST(Poly, EqualityComparable) {
239  {
242  EXPECT_TRUE(p == q);
243  EXPECT_TRUE(q == p);
244  EXPECT_FALSE(p != q);
245  EXPECT_FALSE(q != p);
246  p = 43;
247  EXPECT_FALSE(p == q);
248  EXPECT_FALSE(q == p);
249  EXPECT_TRUE(p != q);
250  EXPECT_TRUE(q != p);
251  }
252  {
253  // empty not equal
256  EXPECT_FALSE(p == q);
257  EXPECT_FALSE(q == p);
258  }
259  {
260  // empty equal
263  EXPECT_TRUE(p == q);
264  EXPECT_TRUE(q == p);
265  }
266  {
267  // mismatched types throws
270  EXPECT_THROW((void)(q == p), BadPolyCast);
271  }
272 }
273 
274 TEST(Poly, StrictlyOrderable) {
275  {
276  // A small object, storable in-situ:
279  EXPECT_TRUE(p < q);
280  EXPECT_TRUE(p <= q);
281  EXPECT_FALSE(p > q);
282  EXPECT_FALSE(p >= q);
283  EXPECT_TRUE(q > p);
284  EXPECT_TRUE(q >= p);
285  EXPECT_FALSE(q < p);
286  EXPECT_FALSE(q <= p);
287  }
288  {
289  // A big object, stored on the heap:
290  Poly<IStrictlyOrderable> p = Big(42);
291  Poly<IStrictlyOrderable> q = Big(43);
292  EXPECT_TRUE(p < q);
293  }
294  {
295  // if equal, no one is bigger
298  EXPECT_FALSE(p < q);
299  EXPECT_TRUE(p <= q);
300  EXPECT_FALSE(p > q);
301  EXPECT_TRUE(p >= q);
302  EXPECT_FALSE(q < p);
303  EXPECT_TRUE(q <= p);
304  EXPECT_FALSE(q > p);
305  EXPECT_TRUE(q >= p);
306  }
307  {
308  // empty is always smaller
311  EXPECT_TRUE(p < q);
312  EXPECT_FALSE(q < p);
313  }
314  {
315  // mismatched types throws
316  Poly<IStrictlyOrderable> p = 4.2;
318  EXPECT_THROW((void)(p < q), BadPolyCast);
319  EXPECT_THROW((void)(q < p), BadPolyCast);
320  }
321 }
322 
323 TEST(Poly, SemiRegularReference) {
324  int i = 42;
326  EXPECT_EQ(42, i);
327  EXPECT_EQ(typeid(int), poly_type(p));
328  EXPECT_EQ(42, poly_cast<int>(p));
329  EXPECT_EQ(&i, &poly_cast<int>(p));
330  EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
331  Poly<ISemiRegular&> p2 = p;
332  EXPECT_EQ(typeid(int), poly_type(p2));
333  EXPECT_EQ(42, poly_cast<int>(p2));
334  EXPECT_EQ(&i, &poly_cast<int>(p2));
335  EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
336  std::swap(p, p2);
337  EXPECT_EQ(typeid(int), poly_type(p2));
338  EXPECT_EQ(42, poly_cast<int>(p2));
339  EXPECT_EQ(&i, &poly_cast<int>(p2));
340  EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
341  using std::swap;
342  swap(p, p2);
343  EXPECT_EQ(typeid(int), poly_type(p2));
344  EXPECT_EQ(42, poly_cast<int>(p2));
345  EXPECT_EQ(&i, &poly_cast<int>(p2));
346  EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
347  // Can't default-initialize reference-like Poly's:
348  static_assert(!std::is_default_constructible<Poly<ISemiRegular&>>::value, "");
349 }
350 
351 TEST(Poly, Conversions) {
352  int i = 42;
353  Poly<ISemiRegular> p1 = i;
354  Poly<ISemiRegular&> p2 = p1;
355  EXPECT_EQ(&poly_cast<int>(p1), &poly_cast<int>(p2));
358  EXPECT_EQ(&poly_cast<int>(p3), &poly_cast<int>(p1));
359  EXPECT_EQ(&poly_cast<int>(p4), &poly_cast<int>(p1));
360  static_assert(
361  !std::is_constructible<Poly<ISemiRegular&>, Poly<ISemiRegular const&>&>::
362  value,
363  "");
364  static_assert(
365  !std::is_constructible<Poly<ISemiRegular>, Poly<ISemiRegular const&>&>::
366  value,
367  "");
368 }
369 
370 TEST(Poly, EqualityComparableReference) {
371  int i = 42;
372  int j = 42;
375  EXPECT_EQ(&i, &poly_cast<int>(p1));
376  EXPECT_EQ(&j, &poly_cast<int>(p2));
377  EXPECT_TRUE(p1 == p2);
378  EXPECT_FALSE(p1 != p2);
379  j = 43;
380  EXPECT_FALSE(p1 == p2);
381  EXPECT_TRUE(p1 != p2);
382  EXPECT_EQ(42, poly_cast<int>(p1));
383  EXPECT_EQ(43, poly_cast<int>(p2));
384 }
385 
386 namespace {
387 struct Foo {
388  template <class Base>
389  struct Interface : Base {
390  void foo(int& i) {
391  folly::poly_call<0>(*this, i);
392  }
393  };
394 
395  template <class T>
396  using Members = FOLLY_POLY_MEMBERS(&T::foo);
397 };
398 
399 struct foo_ {
400  foo_() = default;
401  explicit foo_(int i) : j_(i) {}
402  void foo(int& i) {
403  i += j_;
404  }
405 
406  private:
407  int j_ = 0;
408 };
409 } // namespace
410 
411 TEST(Poly, Singular) {
412  Poly<Foo> p = foo_{42};
413  int i = 1;
414  p.foo(i);
415  EXPECT_EQ(43, i);
416  EXPECT_EQ(typeid(foo_), poly_type(p));
417 }
418 
419 namespace {
420 struct FooBar : PolyExtends<Foo> {
421  template <class Base>
422  struct Interface : Base {
423  std::string bar(int i) const {
424  return folly::poly_call<0>(*this, i);
425  }
426  };
427 
428  template <class T>
429  using Members = FOLLY_POLY_MEMBERS(&T::bar);
430 };
431 
432 struct foo_bar {
433  foo_bar() = default;
434  explicit foo_bar(int i) : j_(i) {}
435  void foo(int& i) {
436  i += j_;
437  }
438  std::string bar(int i) const {
439  i += j_;
440  return folly::to<std::string>(i);
441  }
442 
443  private:
444  int j_ = 0;
445 };
446 } // namespace
447 
448 TEST(Poly, SingleInheritance) {
449  Poly<FooBar> p = foo_bar{42};
450  int i = 1;
451  p.foo(i);
452  EXPECT_EQ(43, i);
453  EXPECT_EQ("43", p.bar(1));
454  EXPECT_EQ(typeid(foo_bar), poly_type(p));
455 
456  Poly<Foo> q = p; // OK, conversion works.
457  q.foo(i);
458  EXPECT_EQ(85, i);
459 
460  Poly<Foo&> r = p;
461  r->foo(i);
462  EXPECT_EQ(127, i);
463  const_cast<Poly<Foo&> const&>(r)->foo(i);
464  EXPECT_EQ(169, i);
465 
466  Poly<FooBar const&> cr = p;
467  // cr->foo(i); // ERROR: calls a non-const member through a const reference
468  cr->bar(i); // OK
469 }
470 
471 namespace {
472 struct Baz {
473  template <class Base>
474  struct Interface : Base {
475  std::string baz(int i, int j) const {
476  return folly::poly_call<0>(*this, i, j);
477  }
478  };
479 
480  template <class T>
481  using Members = FOLLY_POLY_MEMBERS(&T::baz);
482 };
483 
484 struct FooBarBazFizz : PolyExtends<FooBar, Baz> {
485  template <class Base>
486  struct Interface : Base {
487  std::string fizz() const {
488  return folly::poly_call<0>(*this);
489  }
490  };
491 
492  template <class T>
493  using Members = FOLLY_POLY_MEMBERS(&T::fizz);
494 };
495 
496 struct foo_bar_baz_fizz {
497  foo_bar_baz_fizz() = default;
498  explicit foo_bar_baz_fizz(int i) : j_(i) {}
499  void foo(int& i) {
500  i += j_;
501  }
502  std::string bar(int i) const {
503  return folly::to<std::string>(i + j_);
504  }
505  std::string baz(int i, int j) const {
506  return folly::to<std::string>(i + j);
507  }
508  std::string fizz() const {
509  return "fizz";
510  }
511 
512  private:
513  int j_ = 0;
514 };
515 } // namespace
516 
517 TEST(Poly, MultipleInheritance) {
518  Poly<FooBarBazFizz> p = foo_bar_baz_fizz{42};
519  int i = 1;
520  p.foo(i);
521  EXPECT_EQ(43, i);
522  EXPECT_EQ("43", p.bar(1));
523  EXPECT_EQ("3", p.baz(1, 2));
524  EXPECT_EQ("fizz", p.fizz());
525  EXPECT_EQ(typeid(foo_bar_baz_fizz), poly_type(p));
526 }
527 
528 namespace {
529 struct Property {
530  template <class Base>
531  struct Interface : Base {
532  int prop() const {
533  return folly::poly_call<0>(*this);
534  }
535  void prop(int i) {
536  folly::poly_call<1>(*this, i);
537  }
538  };
539 
540  template <class T>
541  using Members = FOLLY_POLY_MEMBERS(
542  FOLLY_POLY_MEMBER(int() const, &T::prop),
543  FOLLY_POLY_MEMBER(void(int), &T::prop));
544 };
545 
546 struct has_property {
547  has_property() = default;
548  explicit has_property(int i) : j(i) {}
549  int prop() const {
550  return j;
551  }
552  void prop(int i) {
553  j = i;
554  }
555 
556  private:
557  int j = 0;
558 };
559 } // namespace
560 
561 TEST(Poly, OverloadedMembers) {
562  Poly<Property> p = has_property{42};
563  EXPECT_EQ(typeid(has_property), poly_type(p));
564  EXPECT_EQ(42, p.prop());
565  p.prop(68);
566  EXPECT_EQ(68, p.prop());
567 }
568 
569 TEST(Poly, NullablePointer) {
570  Poly<INullablePointer> p = nullptr;
572  EXPECT_EQ(typeid(void), poly_type(p));
574  EXPECT_TRUE(p == q);
575  EXPECT_FALSE(p != q);
576  EXPECT_TRUE(p == nullptr);
577  EXPECT_TRUE(nullptr == p);
578  EXPECT_FALSE(p != nullptr);
579  EXPECT_FALSE(nullptr != p);
580 
581  // No null references ever.
582  Poly<INullablePointer> r = 42;
584  static_assert(!poly_empty(s), "");
586 }
587 
588 namespace {
589 struct MoveOnly_ {
590  MoveOnly_() = default;
591  MoveOnly_(MoveOnly_&&) = default;
592  MoveOnly_(MoveOnly_ const&) = delete;
593  MoveOnly_& operator=(MoveOnly_&&) = default;
594  MoveOnly_& operator=(MoveOnly_ const&) = delete;
595 };
596 } // namespace
597 
598 TEST(Poly, Move) {
599  {
600  int i = 42;
601  Poly<IMoveOnly&> p = i;
602  static_assert(
603  !std::is_convertible<Poly<IMoveOnly&>, Poly<IMoveOnly&&>>::value, "");
604  auto q = poly_move(p);
605  static_assert(std::is_same<decltype(q), Poly<IMoveOnly&&>>::value, "");
606  EXPECT_EQ(&poly_cast<int>(p), &poly_cast<int>(q));
607  }
608  {
609  int i = 42;
611  auto q = poly_move(p);
612  static_assert(
613  std::is_same<decltype(q), Poly<ISemiRegular const&>>::value, "");
614  EXPECT_EQ(&poly_cast<int>(p), &poly_cast<int>(q));
615  }
616  {
617  Poly<IMoveOnly> p = MoveOnly_{};
618  static_assert(!std::is_copy_constructible<Poly<IMoveOnly>>::value, "");
619  auto q = poly_move(p);
620  static_assert(std::is_same<decltype(q), Poly<IMoveOnly>>::value, "");
621  }
622 }
623 
624 TEST(Poly, RValueRef) {
625  int i = 42;
627  static_assert(std::is_same<decltype(poly_cast<int>(p)), int&>::value, "");
628  EXPECT_EQ(&i, &poly_cast<int>(p));
629 }
630 
631 namespace {
632 template <class Fun>
633 struct IFunction;
634 
635 template <class R, class... As>
636 struct IFunction<R(As...)> {
637  template <class Base>
638  struct Interface : Base {
639  R operator()(As... as) const {
640  return static_cast<R>(
641  folly::poly_call<0>(*this, std::forward<As>(as)...));
642  }
643  };
644 
645  template <class T>
646  using Members =
647  FOLLY_POLY_MEMBERS(FOLLY_POLY_MEMBER(R(As...) const, &T::operator()));
648 };
649 
650 template <class Fun>
652 } // namespace
653 
655  Function<int(int, int)> fun = std::plus<int>{};
656  EXPECT_EQ(42, fun(22, 20));
657  fun = std::multiplies<int>{};
658  EXPECT_EQ(22 * 20, fun(22, 20));
659 }
660 
661 namespace {
662 // This multiply extends IEqualityComparable
663 struct IDiamond : PolyExtends<IRegular, INullablePointer> {};
664 } // namespace
665 
666 TEST(Poly, DiamondInheritance) {
667  {
668  // A small object, storable in-situ:
669  Poly<IDiamond> p = 42;
670  EXPECT_EQ(typeid(int), poly_type(p));
671  EXPECT_EQ(42, poly_cast<int>(p));
672  EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
673  Poly<IDiamond> p2 = p;
674  EXPECT_EQ(typeid(int), poly_type(p2));
675  EXPECT_EQ(42, poly_cast<int>(p2));
676  EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
678  EXPECT_EQ(&poly_cast<int>(p), &poly_cast<int>(eq));
679  }
680 
681  EXPECT_EQ(0, Big::s_count);
682  {
683  // A big object, stored on the heap:
684  Poly<IDiamond> p = Big(42);
685  EXPECT_EQ(1, Big::s_count);
686  EXPECT_EQ(typeid(Big), poly_type(p));
687  EXPECT_EQ(42, poly_cast<Big>(p).value());
688  EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
689  Poly<IDiamond> p2 = p;
690  EXPECT_EQ(2, Big::s_count);
691  EXPECT_EQ(typeid(Big), poly_type(p2));
692  EXPECT_EQ(42, poly_cast<Big>(p2).value());
693  EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
695  EXPECT_EQ(&poly_cast<Big>(p), &poly_cast<Big>(eq));
696  }
697  EXPECT_EQ(0, Big::s_count);
698 }
699 
700 namespace {
701 struct Struct {
702  int property() const {
703  return 42;
704  }
705  void property(int) {}
706 };
707 struct Struct2 : Struct {
708  int meow() {
709  return 42;
710  }
711 
712  int purr() {
713  return 1;
714  }
715  int purr() const {
716  return 2;
717  }
718 };
719 
720 int property(Struct const&) {
721  return 42;
722 }
723 void property(Struct&, int) {}
724 
725 int meow(Struct2&) {
726  return 42;
727 }
728 
729 int purr(Struct2&) {
730  return 1;
731 }
732 int purr(Struct2 const&) {
733  return 2;
734 }
735 } // namespace
736 
737 TEST(Poly, Sig) {
738  {
739  auto m0 = folly::sig<int() const>(&Struct::property);
740  EXPECT_EQ(static_cast<int (Struct::*)() const>(&Struct::property), m0);
741  auto m1 = folly::sig<int()>(&Struct::property);
742  EXPECT_EQ(static_cast<int (Struct::*)() const>(&Struct::property), m1);
743 
744  auto m2 = folly::sig<int() const>(&Struct2::property);
745  EXPECT_EQ(static_cast<int (Struct2::*)() const>(&Struct2::property), m2);
746  auto m3 = folly::sig<int()>(&Struct2::property);
747  EXPECT_EQ(static_cast<int (Struct2::*)() const>(&Struct2::property), m3);
748 
749  auto m4 = folly::sig<long()>(&Struct2::meow);
750  EXPECT_EQ(&Struct2::meow, m4);
751 
752  auto m5 = folly::sig<int()>(&Struct2::purr);
753  EXPECT_EQ(static_cast<int (Struct2::*)()>(&Struct2::purr), m5);
754  auto m6 = folly::sig<int() const>(&Struct2::purr);
755  EXPECT_EQ(static_cast<int (Struct2::*)() const>(&Struct2::purr), m6);
756  }
757  {
758  auto m0 = folly::sig<int(Struct const&)>(&::property);
759  EXPECT_EQ(static_cast<int (*)(Struct const&)>(&::property), m0);
760  auto m1 = folly::sig<int(Struct&)>(&::property);
761  EXPECT_EQ(static_cast<int (*)(Struct const&)>(&::property), m1);
762 
763  auto m2 = folly::sig<long(Struct2&)>(&::meow);
764  EXPECT_EQ(&::meow, m2);
765 
766  auto m3 = folly::sig<int(Struct2&)>(&::purr);
767  EXPECT_EQ(static_cast<int (*)(Struct2&)>(&::purr), m3);
768  auto m4 = folly::sig<int(Struct2 const&)>(&::purr);
769  EXPECT_EQ(static_cast<int (*)(Struct2 const&)>(&::purr), m4);
770  }
771 }
772 
773 namespace {
774 struct IAddable {
775  template <class Base>
776  struct Interface : Base {
778  PolySelf<Base> const& a,
779  PolySelf<Base> const& b) {
780  return folly::poly_call<0, IAddable>(a, b);
781  }
782  };
783  template <class T>
784  static auto plus_(T const& a, T const& b) -> decltype(a + b) {
785  return a + b;
786  }
787 
788  template <class T>
789  using Members = FOLLY_POLY_MEMBERS(&plus_<std::decay_t<T>>);
790 };
791 } // namespace
792 
793 TEST(Poly, Addable) {
794  Poly<IAddable> a = 2, b = 3;
795  Poly<IAddable> c = a + b;
796  EXPECT_EQ(typeid(int), poly_type(c));
797  EXPECT_EQ(5, poly_cast<int>(c));
798 
799  Poly<IAddable const&> aref = a, bref = b;
800  auto cc = aref + bref;
801  static_assert(std::is_same<decltype(cc), Poly<IAddable>>::value, "");
802  EXPECT_EQ(typeid(int), poly_type(cc));
803  EXPECT_EQ(5, poly_cast<int>(cc));
804  b = 4;
805  EXPECT_EQ(5, poly_cast<int>(cc));
806  cc = aref + bref;
807  EXPECT_EQ(6, poly_cast<int>(cc));
808 }
809 
810 namespace {
811 struct IFrobnicator {
812  template <class Base>
813  struct Interface : Base {
814  void frobnicate(folly::Poly<folly::poly::IRegular&> x) {
815  folly::poly_call<0>(*this, x);
816  }
817  };
818  template <class T>
819  using Members = FOLLY_POLY_MEMBERS(&T::frobnicate);
820 };
821 using Frobnicator = folly::Poly<IFrobnicator>;
822 
823 struct my_frobnicator {
824  void frobnicate(folly::Poly<folly::poly::IRegular&>) {
825  // no-op
826  }
827 };
828 } // namespace
829 
830 TEST(Poly, PolyRefAsArg) {
832  Frobnicator frob = my_frobnicator{};
833  // should not throw:
834  frob.frobnicate(x);
835  // should not throw:
836  frob.frobnicate(folly::Poly<folly::poly::IRegular&>(x));
837 }
838 #endif
Definition: InvokeTest.cpp:58
std::type_info const & poly_type(detail::PolyRoot< I > const &that) noexcept
Definition: Poly.h:358
#define EXPECT_THROW(statement, expected_exception)
Definition: gtest.h:1843
char b
#define FOLLY_POLY_MEMBERS(...)
Definition: Poly.h:136
void baz()
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
const int x
folly::std T
The non test part of the code is expected to have failures gtest_output_test_ cc
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
bool operator!=(const Unexpected< Error > &lhs, const Unexpected< Error > &rhs)
Definition: Expected.h:766
auto const foo
Definition: LazyTest.cpp:49
AtomicCounter< T, DeterministicAtomic > Base
char a
bool poly_empty(detail::PolyRoot< I > const &that) noexcept
Definition: Poly.h:383
folly::Singleton< int > bar
PolymorphicMatcher< internal::PropertyMatcher< Class, PropertyType > > Property(PropertyType(Class::*property)() const, const PropertyMatcher &matcher)
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
void swap(exception_wrapper &a, exception_wrapper &b) noexcept
constexpr Poly< I > && poly_move(detail::PolyRoot< I > &that) noexcept
Definition: Poly.h:426
fizz
Definition: CMakeCache.txt:313
bool operator==(const Unexpected< Error > &lhs, const Unexpected< Error > &rhs)
Definition: Expected.h:758
void fun()
const char * string
Definition: Conv.cpp:212
static set< string > s
const
Definition: upload.py:398
basic_fbstring< E, T, A, S > operator+(const basic_fbstring< E, T, A, S > &lhs, const basic_fbstring< E, T, A, S > &rhs)
Definition: FBString.h:2447
uint64_t value(const typename LockFreeRingBuffer< T, Atom >::Cursor &rbcursor)
void swap(SwapTrackingAlloc< T > &, SwapTrackingAlloc< T > &)
Definition: F14TestUtil.h:414
#define EXPECT_FALSE(condition)
Definition: gtest.h:1862
Collect as()
Definition: Base.h:811
char c
TEST(SequencedExecutor, CPUThreadPoolExecutor)
StringPiece data_
decltype(Access::template self_< Node, Tfx >()) PolySelf
Definition: Poly.h:108
std::enable_if< IsLessThanComparable< Value >::value, bool >::type operator<(const Expected< Value, Error > &lhs, const Expected< Value, Error > &rhs)
Definition: Expected.h:1321
#define FOLLY_POLY_MEMBER(SIG, MEM)
Definition: Poly.h:158