proxygen
ApplyTupleTest.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2012-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 
17 #include <iostream>
18 
19 #include <folly/Overload.h>
22 
23 #include <array>
24 #include <memory>
25 
26 namespace {
27 
28 void func(int a, int b, double c) {
29  EXPECT_EQ(a, 1);
30  EXPECT_EQ(b, 2);
31  EXPECT_EQ(c, 3.0);
32 }
33 
34 struct Wat {
35  void func(int a, int b, double c) {
36  ::func(a, b, c);
37  }
38 
39  double retVal(int a, double b) {
40  return a + b;
41  }
42 
43  Wat() {}
44  Wat(Wat const&) = delete;
45 
46  int foo;
47 };
48 
49 struct Overloaded {
50  int func(int) {
51  return 0;
52  }
53  bool func(bool) {
54  return true;
55  }
56 };
57 
58 struct Func {
59  int operator()() const {
60  return 1;
61  }
62 };
63 
64 struct CopyCount {
65  CopyCount() {}
66  CopyCount(CopyCount const&) {
67  std::cout << "copy count copy ctor\n";
68  }
69 };
70 
71 void anotherFunc(CopyCount const&) {}
72 
73 std::function<void(int, int, double)> makeFunc() {
74  return &func;
75 }
76 
77 struct GuardObjBase {
78  GuardObjBase(GuardObjBase&&) noexcept {}
79  GuardObjBase() {}
80  GuardObjBase(GuardObjBase const&) = delete;
81  GuardObjBase& operator=(GuardObjBase const&) = delete;
82 };
83 typedef GuardObjBase const& Guard;
84 
85 template <class F, class Tuple>
86 struct GuardObj : GuardObjBase {
87  explicit GuardObj(F&& f, Tuple&& args)
88  : f_(std::forward<F>(f)), args_(std::forward<Tuple>(args)) {}
89  GuardObj(GuardObj&& g) noexcept
90  : GuardObjBase(std::move(g)),
91  f_(std::move(g.f_)),
92  args_(std::move(g.args_)) {}
93 
94  ~GuardObj() {
95  folly::apply(f_, args_);
96  }
97 
98  GuardObj(const GuardObj&) = delete;
99  GuardObj& operator=(const GuardObj&) = delete;
100 
101  private:
102  F f_;
103  Tuple args_;
104 };
105 
106 template <class F, class... Args>
108  F&& f,
109  Args&&... args) {
110  return GuardObj<typename std::decay<F>::type, std::tuple<Args...>>(
111  std::forward<F>(f), std::tuple<Args...>(std::forward<Args>(args)...));
112 }
113 
114 struct Mover {
115  Mover() {}
116  Mover(Mover&&) noexcept {}
117  Mover(const Mover&) = delete;
118  Mover& operator=(const Mover&) = delete;
119 };
120 
121 void move_only_func(Mover&&) {}
122 
123 } // namespace
124 
125 TEST(ApplyTuple, Test) {
126  auto argsTuple = std::make_tuple(1, 2, 3.0);
127  auto func2 = func;
128  folly::apply(func2, argsTuple);
129  folly::apply(func, argsTuple);
130  folly::apply(func, std::make_tuple(1, 2, 3.0));
131  folly::apply(makeFunc(), std::make_tuple(1, 2, 3.0));
132  folly::apply(makeFunc(), argsTuple);
133 
134  std::unique_ptr<Wat> wat(new Wat);
135  folly::apply(&Wat::func, std::make_tuple(wat.get(), 1, 2, 3.0));
136  auto argsTuple2 = std::make_tuple(wat.get(), 1, 2, 3.0);
137  folly::apply(&Wat::func, argsTuple2);
138 
139  EXPECT_EQ(
140  10.0, folly::apply(&Wat::retVal, std::make_tuple(wat.get(), 1, 9.0)));
141 
142  auto test = guard(func, 1, 2, 3.0);
143  CopyCount cpy;
144  auto test2 = guard(anotherFunc, cpy);
145  auto test3 = guard(anotherFunc, std::cref(cpy));
146 
147  Overloaded ovl;
148  EXPECT_EQ(
149  0,
150  folly::apply(
151  static_cast<int (Overloaded::*)(int)>(&Overloaded::func),
152  std::make_tuple(&ovl, 12)));
153  EXPECT_EQ(
154  /* do not code-mode to EXPECT_TRUE */ true,
155  folly::apply(
156  static_cast<bool (Overloaded::*)(bool)>(&Overloaded::func),
157  std::make_tuple(&ovl, false)));
158 
159  int x = folly::apply(std::plus<int>(), std::make_tuple(12, 12));
160  EXPECT_EQ(24, x);
161 
162  Mover m;
163  folly::apply(
164  move_only_func, std::forward_as_tuple(std::forward<Mover>(Mover())));
165  const auto tuple3 = std::make_tuple(1, 2, 3.0);
166  folly::apply(func, tuple3);
167 }
168 
169 TEST(ApplyTuple, Mutable) {
170  auto argsTuple = std::make_tuple(1, 2, 3.0);
171 
172  folly::apply(
173  [](int a, int b, double c) mutable { func(a, b, c); }, argsTuple);
174 }
175 
176 TEST(ApplyTuple, ConstOverloads) {
177  struct ConstOverloaded {
178  ConstOverloaded() {}
179  int operator()() {
180  return 101;
181  }
182  int operator()() const {
183  return 102;
184  }
185  };
186 
187  ConstOverloaded covl;
188 
189  // call operator()()
190  EXPECT_EQ(folly::apply(covl, std::make_tuple()), 101);
191  EXPECT_EQ(folly::apply(std::ref(covl), std::make_tuple()), 101);
193 
194  // call operator()() const
195  EXPECT_EQ(
196  folly::apply(const_cast<ConstOverloaded const&>(covl), std::make_tuple()),
197  102);
198  EXPECT_EQ(folly::apply(std::cref(covl), std::make_tuple()), 102);
199 }
200 
201 TEST(ApplyTuple, RefOverloads) {
202  struct RefOverloaded {
203  RefOverloaded() {}
204  int operator()() & {
205  return 201;
206  }
207  int operator()() const& {
208  return 202;
209  }
210  int operator()() && {
211  return 203;
212  }
213  };
214 
215  RefOverloaded rovl;
216 
217  // call operator()() &
218  EXPECT_EQ(folly::apply(rovl, std::make_tuple()), 201);
219  EXPECT_EQ(folly::apply(std::ref(rovl), std::make_tuple()), 201);
220 
221  // call operator()() const &
222  EXPECT_EQ(
223  folly::apply(const_cast<RefOverloaded const&>(rovl), std::make_tuple()),
224  202);
225  EXPECT_EQ(folly::apply(std::cref(rovl), std::make_tuple()), 202);
226 
227  // call operator()() &&
229 }
230 
231 struct MemberFunc {
232  int x;
233  int getX() const {
234  return x;
235  }
236  void setX(int xx) {
237  x = xx;
238  }
239 };
240 
241 TEST(ApplyTuple, MemberFunction) {
242  MemberFunc mf;
243  mf.x = 123;
244 
245  // call getter
247 
248  // call setter
250  EXPECT_EQ(mf.x, 234);
252 }
253 
254 TEST(ApplyTuple, MemberFunctionWithRefWrapper) {
255  MemberFunc mf;
256  mf.x = 234;
257 
258  EXPECT_EQ(
259  folly::apply(&MemberFunc::getX, std::make_tuple(std::ref(mf))), 234);
260 }
261 
262 TEST(ApplyTuple, MemberFunctionWithConstPointer) {
263  MemberFunc mf;
264  mf.x = 234;
265 
266  EXPECT_EQ(
267  folly::apply(
269  std::make_tuple(const_cast<MemberFunc const*>(&mf))),
270  234);
271 }
272 
273 TEST(ApplyTuple, MemberFunctionWithSharedPtr) {
274  MemberFunc mf;
275  mf.x = 234;
276 
277  EXPECT_EQ(
278  folly::apply(
279  &MemberFunc::getX, std::make_tuple(std::make_shared<MemberFunc>(mf))),
280  234);
281 }
282 
283 TEST(ApplyTuple, MemberFunctionWithUniquePtr) {
284  MemberFunc mf;
285  mf.x = 234;
286 
287  EXPECT_EQ(
288  folly::apply(
289  &MemberFunc::getX, std::make_tuple(std::make_unique<MemberFunc>(mf))),
290  234);
291 }
292 
293 TEST(ApplyTuple, Array) {
294  folly::apply(func, std::array<int, 3>{{1, 2, 3}});
295  folly::apply(func, std::array<double, 3>{{1, 2, 3}});
296 }
297 
298 TEST(ApplyTuple, Pair) {
299  auto add = [](int x, int y) { return x + y; };
300 
301  EXPECT_EQ(folly::apply(add, std::pair<int, int>{1200, 34}), 1234);
302 }
303 
304 TEST(ApplyTuple, MultipleTuples) {
305  auto add = [](int x, int y, int z) { return x * 100 + y * 10 + z; };
306 
307  EXPECT_EQ(123, folly::apply(add, std::make_tuple(1, 2, 3)));
308  EXPECT_EQ(
309  123,
310  folly::apply(
311  add, std::tuple_cat(std::make_tuple(1, 2, 3), std::make_tuple())));
312  EXPECT_EQ(
313  123,
314  folly::apply(
315  add, std::tuple_cat(std::make_tuple(1, 2), std::make_tuple(3))));
316  EXPECT_EQ(
317  123,
318  folly::apply(
319  add, std::tuple_cat(std::make_tuple(1), std::make_tuple(2, 3))));
320  EXPECT_EQ(
321  123,
322  folly::apply(
323  add, std::tuple_cat(std::make_tuple(), std::make_tuple(1, 2, 3))));
324 
325  EXPECT_EQ(
326  123,
327  folly::apply(
328  add,
329  std::tuple_cat(
331  EXPECT_EQ(
332  123,
333  folly::apply(
334  add,
335  std::tuple_cat(
337  EXPECT_EQ(
338  123,
339  folly::apply(
340  add,
341  std::tuple_cat(
343 }
344 
345 TEST(ApplyTuple, UncurryCopyMove) {
346  std::string separator = "================================\n";
347  auto formatRow = folly::uncurry([=](std::string a, std::string b) {
348  // capture separator by copy
349  return separator + a + "\n" + b + "\n" + separator;
350  });
351  auto row = std::make_tuple("hello", "world");
352  auto expected = separator + "hello\nworld\n" + separator;
353  EXPECT_EQ(expected, formatRow(row));
354  auto formatRowCopy = formatRow;
355  EXPECT_EQ(expected, formatRowCopy(row));
356  auto formatRowMove = std::move(formatRow);
357  EXPECT_EQ(expected, formatRowMove(row));
358 
359  // capture value moved out from formatRow
360  EXPECT_NE(expected, formatRow(row));
361 }
362 
363 TEST(ApplyTuple, Uncurry) {
364  EXPECT_EQ(42, folly::uncurry([](int x, int y) {
365  return x * y;
366  })(std::pair<int, int>(6, 7)));
367  EXPECT_EQ(42, folly::uncurry([](int&& x, int&& y) {
368  return x * y;
369  })(std::pair<int&&, int&&>(6, 7)));
370  EXPECT_EQ(42, folly::uncurry([](int&& x, int&& y) {
371  return x * y;
372  })(std::pair<int&&, int&&>(6, 7)));
373 
374  std::string long1 = "a long string exceeding small string size";
375  std::string long2 = "and here is another one!";
376  std::string expected = long1 + long2;
377 
378  auto cat = folly::uncurry(
379  [](std::string a, std::string b) { return std::move(a) + std::move(b); });
380 
381  EXPECT_EQ(expected, cat(std::make_pair(long1, long2)));
382  EXPECT_FALSE(long1.empty());
383  EXPECT_FALSE(long2.empty());
384  EXPECT_EQ(expected, cat(std::tie(long1, long2)));
385  EXPECT_FALSE(long1.empty());
386  EXPECT_FALSE(long2.empty());
387  EXPECT_EQ(
388  expected, cat(std::forward_as_tuple(std::move(long1), std::move(long2))));
389  EXPECT_TRUE(long1.empty());
390  EXPECT_TRUE(long2.empty());
391 }
392 
393 TEST(ApplyTuple, UncurryStdFind) {
394  std::vector<std::pair<int, int>> v{{1, 9}, {2, 8}, {3, 7}, {4, 6}, {5, 5}};
395  EXPECT_EQ(
396  3, std::count_if(v.begin(), v.end(), folly::uncurry([](int a, int b) {
397  return b % a == 0;
398  })));
399 }
400 
401 namespace {
402 struct S {
403  template <typename... Args>
404  explicit S(Args&&... args) : tuple_(std::forward<Args>(args)...) {}
405 
406  std::tuple<int, double, std::string> tuple_;
407 };
408 } // namespace
409 
410 TEST(MakeFromTupleTest, make_from_tuple) {
411  S expected{42, 1.0, "foobar"};
412 
413  // const lvalue ref
414  auto s1 = folly::make_from_tuple<S>(expected.tuple_);
415  EXPECT_EQ(expected.tuple_, s1.tuple_);
416 
417  // rvalue ref
418  S sCopy{expected.tuple_};
419  auto s2 = folly::make_from_tuple<S>(std::move(sCopy.tuple_));
420  EXPECT_EQ(expected.tuple_, s2.tuple_);
421  EXPECT_TRUE(std::get<2>(sCopy.tuple_).empty());
422 
423  // forward
424  std::string str{"foobar"};
425  auto s3 =
426  folly::make_from_tuple<S>(std::forward_as_tuple(42, 1.0, std::move(str)));
427  EXPECT_EQ(expected.tuple_, s3.tuple_);
428  EXPECT_TRUE(str.empty());
429 }
430 
431 TEST(MakeIndexSequenceFromTuple, Basic) {
432  using folly::index_sequence;
434  using OneElementTuple = std::tuple<int>;
435  using TwoElementTuple = std::tuple<int>;
436 
437  EXPECT_TRUE((std::is_same<
438  index_sequence_for_tuple<OneElementTuple>,
439  index_sequence<0>>::value));
440  EXPECT_TRUE((std::is_same<
441  index_sequence_for_tuple<const OneElementTuple>,
442  index_sequence<0>>::value));
443 
444  EXPECT_TRUE((std::is_same<
445  index_sequence_for_tuple<TwoElementTuple>,
446  index_sequence<0>>::value));
447  EXPECT_TRUE((std::is_same<
448  index_sequence_for_tuple<const TwoElementTuple>,
449  index_sequence<0>>::value));
450 }
451 
452 TEST(ApplyResult, Basic) {
453  {
454  auto f = [](auto) -> int { return {}; };
455  EXPECT_TRUE((std::is_same<
456  folly::apply_result_t<decltype(f), std::tuple<int>>,
457  int>{}));
458  }
459 
460  {
461  auto f = folly::overload(
462  [](int) {},
463  [](double) -> double { return {}; },
464  [](int, int) -> int { return {}; });
465 
466  EXPECT_TRUE((std::is_same<
467  folly::apply_result_t<decltype(f), std::tuple<int>>,
468  void>::value));
469  EXPECT_TRUE((std::is_same<
470  folly::apply_result_t<decltype(f), std::tuple<double>>,
471  double>::value));
472  EXPECT_TRUE((std::is_same<
473  folly::apply_result_t<decltype(f), std::tuple<int, int>>,
474  int>::value));
475  }
476 }
477 
478 TEST(IsApplicable, Basic) {
479  {
480  auto f = [] {};
481  EXPECT_TRUE((folly::is_applicable<decltype(f), std::tuple<>>::value));
482  EXPECT_FALSE((folly::is_applicable<decltype(f), std::tuple<int>>::value));
483  }
484  {
485  auto f = folly::overload([](int) {}, [](double) -> double { return {}; });
486  EXPECT_TRUE((folly::is_applicable<decltype(f), std::tuple<double>>::value));
487  EXPECT_TRUE((folly::is_applicable<decltype(f), std::tuple<int>>::value));
488  EXPECT_FALSE((folly::is_applicable<decltype(f), std::tuple<>>::value));
489  EXPECT_FALSE(
490  (folly::is_applicable<decltype(f), std::tuple<int, double>>::value));
491  }
492 }
493 
494 TEST(IsNothrowApplicable, Basic) {
495  {
496  auto f = []() noexcept {};
497  EXPECT_TRUE((folly::is_nothrow_applicable<decltype(f), std::tuple<>>{}));
498  EXPECT_FALSE(
499  (folly::is_nothrow_applicable<decltype(f), std::tuple<int>>{}));
500  }
501  {
502  auto f = folly::overload(
503  [](int) noexcept {}, [](double) -> double { return {}; });
504  EXPECT_FALSE(
505  (folly::is_nothrow_applicable<decltype(f), std::tuple<double>>{}));
506  EXPECT_TRUE((folly::is_nothrow_applicable<decltype(f), std::tuple<int>>{}));
507  EXPECT_FALSE((folly::is_nothrow_applicable<decltype(f), std::tuple<>>{}));
508  EXPECT_FALSE(
509  (folly::is_nothrow_applicable<decltype(f), std::tuple<int, double>>::
510  value));
511  }
512 }
513 
514 TEST(IsApplicableR, Basic) {
515  {
516  auto f = []() -> int { return {}; };
517  EXPECT_TRUE((folly::is_applicable_r<double, decltype(f), std::tuple<>>{}));
518  EXPECT_FALSE(
519  (folly::is_applicable_r<double, decltype(f), std::tuple<int>>{}));
520  }
521  {
522  auto f = folly::overload(
523  [](int) noexcept {}, [](double) -> double { return {}; });
524  EXPECT_TRUE(
525  (folly::is_applicable_r<float, decltype(f), std::tuple<double>>{}));
526  EXPECT_TRUE((folly::is_applicable_r<void, decltype(f), std::tuple<int>>{}));
527  EXPECT_FALSE((folly::is_applicable_r<void, decltype(f), std::tuple<>>{}));
528  EXPECT_FALSE(
529  (folly::is_applicable_r<double, decltype(f), std::tuple<int, double>>::
530  value));
531  }
532 }
533 
534 TEST(IsNothrowApplicableR, Basic) {
535  {
536  auto f = []() noexcept->int {
537  return {};
538  };
539  EXPECT_TRUE(
540  (folly::is_nothrow_applicable_r<double, decltype(f), std::tuple<>>{}));
541  EXPECT_FALSE(
542  (folly::
543  is_nothrow_applicable_r<double, decltype(f), std::tuple<int>>{}));
544  }
545  {
546  auto f = folly::overload(
547  [](int) noexcept {}, [](double) -> double { return {}; });
548  EXPECT_FALSE((
549  folly::
550  is_nothrow_applicable_r<float, decltype(f), std::tuple<double>>{}));
551  EXPECT_TRUE(
552  (folly::is_nothrow_applicable_r<void, decltype(f), std::tuple<int>>{}));
553  EXPECT_FALSE(
554  (folly::is_nothrow_applicable_r<void, decltype(f), std::tuple<>>{}));
556  double,
557  decltype(f),
558  std::tuple<int, double>>::value));
559  }
560 }
561 
562 TEST(ForwardTuple, Basic) {
563  auto tuple = std::make_tuple(1, 2.0);
564 
565  EXPECT_TRUE((std::is_same<
566  decltype(folly::forward_tuple(tuple)),
567  std::tuple<int&, double&>>::value));
568  EXPECT_EQ(folly::forward_tuple(tuple), tuple);
569  EXPECT_TRUE((std::is_same<
570  decltype(folly::forward_tuple(folly::as_const(tuple))),
571  std::tuple<const int&, const double&>>::value));
573 
574  EXPECT_TRUE((std::is_same<
575  decltype(folly::forward_tuple(std::move(tuple))),
576  std::tuple<int&&, double&&>>::value));
577  EXPECT_EQ(folly::forward_tuple(std::move(tuple)), tuple);
578  EXPECT_TRUE(
579  (std::is_same<
581  std::tuple<const int&, const double&>>::value));
583 
584  auto integer = 1;
585  auto floating_point = 2.0;
586  auto ref_tuple = std::forward_as_tuple(integer, std::move(floating_point));
587 
588  EXPECT_TRUE((std::is_same<
589  decltype(folly::forward_tuple(ref_tuple)),
590  std::tuple<int&, double&>>::value));
591 
592  EXPECT_TRUE((std::is_same<
593  decltype(folly::forward_tuple(std::move(ref_tuple))),
594  std::tuple<int&, double&&>>::value));
595 
596  EXPECT_TRUE((std::is_same<
597  decltype(std::tuple_cat(
598  folly::forward_tuple(tuple),
600  std::tuple<int&, double&, int&&, double&&>>::value));
601 }
Definition: InvokeTest.cpp:58
make_index_sequence< std::tuple_size< Tuple >::value > index_sequence_for_tuple
Definition: ApplyTuple.h:36
auto forward_tuple(Tuple &&tuple) noexcept-> decltype(detail::apply_tuple::adl::forward_tuple(std::declval< Tuple >(), std::declval< index_sequence_for_tuple< std::remove_reference_t< Tuple >>>()))
Definition: ApplyTuple.h:110
auto f
auto cat
char b
auto add
Definition: BaseTest.cpp:70
auto uncurry(F &&f) -> detail::apply_tuple::Uncurry< typename std::decay< F >::type >
Definition: ApplyTuple.h:178
PskType type
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
const int x
STL namespace.
internal::ArgsMatcher< InnerMatcher > Args(const InnerMatcher &matcher)
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
requires E e noexcept(noexcept(s.error(std::move(e))))
tuple make_tuple()
Definition: gtest-tuple.h:675
constexpr T const & as_const(T &t) noexcept
Definition: Utility.h:96
Function< void()> Func
Definition: Executor.h:27
int getX() const
internal::PairMatcher< FirstMatcher, SecondMatcher > Pair(FirstMatcher first_matcher, SecondMatcher second_matcher)
GuardImpl guard(ErrorHandler &&handler)
Definition: Base.h:840
integer_sequence< std::size_t, Ints... > index_sequence
Definition: Utility.h:191
static map< string, int > m
Definition: InvokeTest.cpp:72
char a
static const char *const value
Definition: Conv.cpp:50
invoke_result_t< ApplyInvoke, F, Tuple > apply_result_t
Definition: ApplyTuple.h:126
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
const char * string
Definition: Conv.cpp:212
g_t g(f_t)
#define EXPECT_NE(val1, val2)
Definition: gtest.h:1926
Definition: InvokeTest.cpp:65
decltype(auto) overload(Cases &&...cases)
Definition: Overload.h:62
#define EXPECT_FALSE(condition)
Definition: gtest.h:1862
char c
constexpr T make_from_tuple(Tuple &&t)
Definition: ApplyTuple.h:204
decltype(auto) constexpr apply(F &&func, Tuple &&tuple)
Definition: ApplyTuple.h:87
TEST(ApplyTuple, Test)
void setX(int xx)