2 * Copyright 2016 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.
19 #include <folly/Function.h>
21 #include <folly/Memory.h>
22 #include <gtest/gtest.h>
24 using folly::FunctionMoveCtor;
25 using folly::Function;
28 int func_int_int_add_25(int x) {
31 int func_int_int_add_111(int x) {
34 int func_int_return_987() {
37 float floatMult(float a, float b) {
41 template <class T, size_t S>
43 std::array<T, S> data = {{0}};
45 // Two operator() with different argument types.
46 // The InvokeReference tests use both
47 T const& operator()(size_t index) const {
50 T operator()(size_t index, T const& value) {
51 T oldvalue = data[index];
57 // TEST =====================================================================
63 MoveMayThrow() = default;
64 MoveMayThrow(MoveMayThrow const&) = default;
65 MoveMayThrow& operator=(MoveMayThrow const&) = default;
66 MoveMayThrow(MoveMayThrow&&) noexcept(false) {
68 throw std::runtime_error("MoveMayThrow(MoveMayThrow&&)");
71 MoveMayThrow& operator=(MoveMayThrow&&) noexcept(false) {
73 throw std::runtime_error("MoveMayThrow::operator=(MoveMayThrow&&)");
80 TEST(Function, NoExceptMovable) {
81 // callable_noexcept is noexcept-movable
82 auto callable_noexcept = [](int x) { return x + 1; };
84 std::is_nothrow_move_constructible<decltype(callable_noexcept)>::value);
86 // callable_throw may throw when moved
88 auto callable_throw = [mmt](int x) { return x + 10; };
90 std::is_nothrow_move_constructible<decltype(callable_throw)>::value);
92 // callable_noexcept can be stored in the Function object
93 Function<int(int), FunctionMoveCtor::NO_THROW> func(callable_noexcept);
94 EXPECT_EQ(func(42), 43);
95 EXPECT_FALSE(func.hasAllocatedMemory());
96 EXPECT_TRUE(std::is_nothrow_move_constructible<decltype(func)>::value);
98 // callable_throw cannot be stored in the Function object,
99 // because Function guarantees noexcept-movability, but
100 // callable_throw may throw when moved
101 Function<int(int), FunctionMoveCtor::NO_THROW> func_safe_move(callable_throw);
102 EXPECT_EQ(func_safe_move(42), 52);
103 EXPECT_TRUE(func_safe_move.hasAllocatedMemory());
105 std::is_nothrow_move_constructible<decltype(func_safe_move)>::value);
107 // callable_throw can be stored in the Function object when
108 // the NoExceptMovable template parameter is set to NO
109 Function<int(int), FunctionMoveCtor::MAY_THROW> func_movethrows(
111 EXPECT_EQ(func_movethrows(42), 52);
112 EXPECT_FALSE(func_movethrows.hasAllocatedMemory());
114 std::is_nothrow_move_constructible<decltype(func_movethrows)>::value);
117 // TEST =====================================================================
118 // InvokeFunctor & InvokeReference
120 template <FunctionMoveCtor NEM, size_t S>
121 void invoke_functor_test() {
122 Functor<int, 100> func;
125 // Try Functions with differently sized storage areas
126 // S=0: request storage for functors of size 0. The storage size
127 // will be actually larger, because there is a lower limit which
128 // still allows to store at least pointers to functors on the heap.
129 // S=1: request minimum storage size of 0.5x the sizeof(func)
130 // S=2: request sizeof(func)
131 // S=3: request 1.5*sizeof(func)
132 Function<int(size_t) const, NEM, sizeof(func)* S / 2> getter =
135 // Function will allocate memory on the heap to store
136 // the functor object if the internal storage area is smaller than
138 EXPECT_EQ(getter.hasAllocatedMemory(), S < 2);
140 EXPECT_EQ(getter(5), 123);
142 TEST(Function, InvokeFunctor_T0) {
143 invoke_functor_test<FunctionMoveCtor::MAY_THROW, 0>();
145 TEST(Function, InvokeFunctor_N0) {
146 invoke_functor_test<FunctionMoveCtor::NO_THROW, 0>();
148 TEST(Function, InvokeFunctor_T1) {
149 invoke_functor_test<FunctionMoveCtor::MAY_THROW, 1>();
151 TEST(Function, InvokeFunctor_N1) {
152 invoke_functor_test<FunctionMoveCtor::NO_THROW, 1>();
154 TEST(Function, InvokeFunctor_T2) {
155 invoke_functor_test<FunctionMoveCtor::MAY_THROW, 2>();
157 TEST(Function, InvokeFunctor_N2) {
158 invoke_functor_test<FunctionMoveCtor::NO_THROW, 2>();
160 TEST(Function, InvokeFunctor_T3) {
161 invoke_functor_test<FunctionMoveCtor::MAY_THROW, 3>();
163 TEST(Function, InvokeFunctor_N3) {
164 invoke_functor_test<FunctionMoveCtor::NO_THROW, 3>();
167 template <FunctionMoveCtor NEM>
168 void invoke_reference_test() {
169 Functor<int, 10> func;
172 // Have Functions for getter and setter, both referencing the
174 Function<int(size_t) const, NEM, 0> getter = std::ref(func);
175 Function<int(size_t, int), NEM, 0> setter = std::ref(func);
177 EXPECT_EQ(getter(5), 123);
178 EXPECT_EQ(setter(5, 456), 123);
179 EXPECT_EQ(setter(5, 567), 456);
180 EXPECT_EQ(getter(5), 567);
182 TEST(Function, InvokeReference_T) {
183 invoke_reference_test<FunctionMoveCtor::MAY_THROW>();
185 TEST(Function, InvokeReference_N) {
186 invoke_reference_test<FunctionMoveCtor::NO_THROW>();
189 // TEST =====================================================================
192 template <FunctionMoveCtor NEM>
193 void emptiness_test() {
194 Function<int(int), NEM> f;
195 EXPECT_EQ(f, nullptr);
196 EXPECT_EQ(nullptr, f);
198 EXPECT_THROW(f(98), std::bad_function_call);
200 Function<int(int), NEM> g([](int x) { return x + 1; });
201 EXPECT_NE(g, nullptr);
202 EXPECT_NE(nullptr, g);
204 EXPECT_EQ(g(99), 100);
206 Function<int(int), NEM> h(&func_int_int_add_25);
207 EXPECT_NE(h, nullptr);
208 EXPECT_NE(nullptr, h);
210 EXPECT_EQ(h(100), 125);
213 EXPECT_EQ(h, nullptr);
214 EXPECT_EQ(nullptr, h);
216 EXPECT_THROW(h(101), std::bad_function_call);
219 TEST(Function, Emptiness_T) {
220 emptiness_test<FunctionMoveCtor::MAY_THROW>();
222 TEST(Function, Emptiness_N) {
223 emptiness_test<FunctionMoveCtor::NO_THROW>();
226 // TEST =====================================================================
229 TEST(Function, Types) {
231 !std::is_base_of<std::unary_function<int, int>, Function<int()>>::value));
233 (!std::is_base_of<std::binary_function<int, int, int>, Function<int()>>::
235 EXPECT_TRUE((std::is_same<Function<int()>::ResultType, int>::value));
238 std::is_base_of<std::unary_function<int, double>, Function<double(int)>>::
240 EXPECT_TRUE((!std::is_base_of<
241 std::binary_function<int, int, double>,
242 Function<double(int)>>::value));
243 EXPECT_TRUE((std::is_same<Function<double(int)>::ResultType, double>::value));
245 (std::is_same<Function<double(int)>::result_type, double>::value));
246 EXPECT_TRUE((std::is_same<Function<double(int)>::argument_type, int>::value));
248 EXPECT_TRUE((!std::is_base_of<
249 std::unary_function<int, double>,
250 Function<double(int, char)>>::value));
251 EXPECT_TRUE((std::is_base_of<
252 std::binary_function<int, char, double>,
253 Function<double(int, char)>>::value));
255 (std::is_same<Function<double(int, char)>::ResultType, double>::value));
257 (std::is_same<Function<double(int, char)>::result_type, double>::value));
259 (std::is_same<Function<double(int, char)>::first_argument_type, int>::
262 (std::is_same<Function<double(int, char)>::second_argument_type, char>::
266 // TEST =====================================================================
269 template <FunctionMoveCtor NEM1, FunctionMoveCtor NEM2, bool UseSwapMethod>
271 Function<int(int), NEM1> mf1(func_int_int_add_25);
272 Function<int(int), NEM2> mf2(func_int_int_add_111);
274 EXPECT_EQ(mf1(100), 125);
275 EXPECT_EQ(mf2(100), 211);
283 EXPECT_EQ(mf2(100), 125);
284 EXPECT_EQ(mf1(100), 211);
286 Function<int(int)> mf3(nullptr);
287 EXPECT_EQ(mf3, nullptr);
295 EXPECT_EQ(mf3(100), 211);
296 EXPECT_EQ(mf1, nullptr);
298 Function<int(int)> mf4([](int x) { return x + 222; });
299 EXPECT_EQ(mf4(100), 322);
306 EXPECT_EQ(mf4(100), 211);
307 EXPECT_EQ(mf3(100), 322);
314 EXPECT_EQ(mf3, nullptr);
315 EXPECT_EQ(mf1(100), 322);
317 TEST(Function, SwapMethod_TT) {
318 swap_test<FunctionMoveCtor::MAY_THROW, FunctionMoveCtor::MAY_THROW, true>();
320 TEST(Function, SwapMethod_TN) {
321 swap_test<FunctionMoveCtor::MAY_THROW, FunctionMoveCtor::NO_THROW, true>();
323 TEST(Function, SwapMethod_NT) {
324 swap_test<FunctionMoveCtor::NO_THROW, FunctionMoveCtor::MAY_THROW, true>();
326 TEST(Function, SwapMethod_NN) {
327 swap_test<FunctionMoveCtor::NO_THROW, FunctionMoveCtor::NO_THROW, true>();
329 TEST(Function, SwapFunction_TT) {
330 swap_test<FunctionMoveCtor::MAY_THROW, FunctionMoveCtor::MAY_THROW, false>();
332 TEST(Function, SwapFunction_TN) {
333 swap_test<FunctionMoveCtor::MAY_THROW, FunctionMoveCtor::NO_THROW, false>();
335 TEST(Function, SwapFunction_NT) {
336 swap_test<FunctionMoveCtor::NO_THROW, FunctionMoveCtor::MAY_THROW, false>();
338 TEST(Function, SwapFunction_NN) {
339 swap_test<FunctionMoveCtor::NO_THROW, FunctionMoveCtor::NO_THROW, false>();
342 // TEST =====================================================================
345 template <FunctionMoveCtor NEM>
347 Function<float(float, float), NEM> fnc = floatMult;
348 auto task = std::bind(std::move(fnc), 2.f, 4.f);
349 EXPECT_THROW(fnc(0, 0), std::bad_function_call);
350 EXPECT_EQ(task(), 8);
351 auto task2(std::move(task));
352 EXPECT_THROW(task(), std::bad_function_call);
353 EXPECT_EQ(task2(), 8);
355 TEST(Function, Bind_T) {
356 bind_test<FunctionMoveCtor::MAY_THROW>();
358 TEST(Function, Bind_N) {
359 bind_test<FunctionMoveCtor::NO_THROW>();
362 // TEST =====================================================================
365 template <FunctionMoveCtor NEM, size_t S>
366 void non_copyable_lambda_test() {
367 auto unique_ptr_int = folly::make_unique<int>(900);
368 EXPECT_EQ(*unique_ptr_int, 900);
370 char fooData[64] = {0};
371 EXPECT_EQ(fooData[0], 0); // suppress gcc warning about fooData not being used
373 auto functor = std::bind(
374 [fooData](std::unique_ptr<int>& up) mutable { return ++*up; },
375 std::move(unique_ptr_int));
377 EXPECT_EQ(functor(), 901);
379 Function<int(void), NEM, sizeof(functor)* S / 2> func = std::move(functor);
381 func.hasAllocatedMemory(),
382 S < 2 || (NEM == FunctionMoveCtor::NO_THROW &&
383 !std::is_nothrow_move_constructible<decltype(functor)>::value));
385 EXPECT_EQ(func(), 902);
387 TEST(Function, NonCopyableLambda_T0) {
388 non_copyable_lambda_test<FunctionMoveCtor::MAY_THROW, 0>();
390 TEST(Function, NonCopyableLambda_N0) {
391 non_copyable_lambda_test<FunctionMoveCtor::NO_THROW, 0>();
393 TEST(Function, NonCopyableLambda_T1) {
394 non_copyable_lambda_test<FunctionMoveCtor::MAY_THROW, 1>();
396 TEST(Function, NonCopyableLambda_N1) {
397 non_copyable_lambda_test<FunctionMoveCtor::NO_THROW, 1>();
399 TEST(Function, NonCopyableLambda_T2) {
400 non_copyable_lambda_test<FunctionMoveCtor::MAY_THROW, 2>();
402 TEST(Function, NonCopyableLambda_N2) {
403 non_copyable_lambda_test<FunctionMoveCtor::NO_THROW, 2>();
405 TEST(Function, NonCopyableLambda_T3) {
406 non_copyable_lambda_test<FunctionMoveCtor::MAY_THROW, 3>();
408 TEST(Function, NonCopyableLambda_N3) {
409 non_copyable_lambda_test<FunctionMoveCtor::NO_THROW, 3>();
412 // TEST =====================================================================
415 template <FunctionMoveCtor NEM>
416 void downsize_test() {
417 Functor<int, 10> functor;
421 EXPECT_EQ(functor(3), 123);
423 // Function with large callable storage area (twice the size of
425 Function<int(size_t, int), NEM, sizeof(functor)* 2> func2x =
427 EXPECT_FALSE(func2x.hasAllocatedMemory());
428 EXPECT_EQ(func2x(3, 200), 123);
429 EXPECT_EQ(func2x(3, 201), 200);
431 // Function with sufficient callable storage area (equal to
432 // size of the functor)
433 Function<int(size_t, int), NEM, sizeof(functor)> func1x = std::move(func2x);
434 EXPECT_THROW(func2x(0, 0), std::bad_function_call);
435 EXPECT_FALSE(func2x);
436 EXPECT_FALSE(func1x.hasAllocatedMemory());
437 EXPECT_EQ(func1x(3, 202), 201);
438 EXPECT_EQ(func1x(3, 203), 202);
440 // Function with minimal callable storage area (functor does
441 // not fit and will be moved to memory on the heap)
442 Function<int(size_t, int), NEM, 0> func0x = std::move(func1x);
443 EXPECT_THROW(func1x(0, 0), std::bad_function_call);
444 EXPECT_FALSE(func1x);
445 EXPECT_TRUE(func0x.hasAllocatedMemory());
446 EXPECT_EQ(func0x(3, 204), 203);
447 EXPECT_EQ(func0x(3, 205), 204);
449 // bonus test: move to Function with opposite NoExceptMovable
453 NEM == FunctionMoveCtor::NO_THROW ? FunctionMoveCtor::MAY_THROW
454 : FunctionMoveCtor::NO_THROW,
456 funcnot = std::move(func0x);
457 EXPECT_THROW(func0x(0, 0), std::bad_function_call);
458 EXPECT_FALSE(func0x);
459 EXPECT_TRUE(funcnot.hasAllocatedMemory());
460 EXPECT_EQ(funcnot(3, 206), 205);
461 EXPECT_EQ(funcnot(3, 207), 206);
463 TEST(Function, Downsize_T) {
464 downsize_test<FunctionMoveCtor::MAY_THROW>();
466 TEST(Function, Downsize_N) {
467 downsize_test<FunctionMoveCtor::NO_THROW>();
470 // TEST =====================================================================
473 template <FunctionMoveCtor NEM>
474 void refcount_test() {
475 Functor<int, 100> functor;
477 auto shared_int = std::make_shared<int>(100);
479 EXPECT_EQ(*shared_int, 100);
480 EXPECT_EQ(shared_int.use_count(), 1);
482 Function<int(void), NEM> func1 = [shared_int]() { return ++*shared_int; };
483 EXPECT_EQ(shared_int.use_count(), 2);
484 EXPECT_EQ(func1(), 101);
485 EXPECT_EQ(*shared_int, 101);
487 // func2: made to not fit functor.
488 Function<int(void), NEM, sizeof(functor) / 2> func2 = std::move(func1);
489 EXPECT_THROW(func1(), std::bad_function_call);
490 EXPECT_EQ(shared_int.use_count(), 2);
492 EXPECT_EQ(func2(), 102);
493 EXPECT_EQ(*shared_int, 102);
495 func2 = [shared_int]() { return ++*shared_int; };
496 EXPECT_EQ(shared_int.use_count(), 2);
497 EXPECT_EQ(func2(), 103);
498 EXPECT_EQ(*shared_int, 103);
500 // We set func2 to a lambda that captures 'functor', which forces it on
502 func2 = [functor]() { return functor(3); };
503 EXPECT_TRUE(func2.hasAllocatedMemory());
504 EXPECT_EQ(func2(), 999);
505 EXPECT_EQ(shared_int.use_count(), 1);
506 EXPECT_EQ(*shared_int, 103);
508 func2 = [shared_int]() { return ++*shared_int; };
509 EXPECT_EQ(shared_int.use_count(), 2);
510 EXPECT_EQ(func2(), 104);
511 EXPECT_EQ(*shared_int, 104);
513 // We set func2 to function pointer, which always fits into the
514 // Function object and is no-except-movable
515 func2 = &func_int_return_987;
516 EXPECT_FALSE(func2.hasAllocatedMemory());
517 EXPECT_EQ(func2(), 987);
518 EXPECT_EQ(shared_int.use_count(), 1);
519 EXPECT_EQ(*shared_int, 104);
521 TEST(Function, Refcount_T) {
522 refcount_test<FunctionMoveCtor::MAY_THROW>();
524 TEST(Function, Refcount_N) {
525 refcount_test<FunctionMoveCtor::NO_THROW>();
528 // TEST =====================================================================
531 template <FunctionMoveCtor NEM>
533 std::function<int(int)> func = [](int x) { return x + 25; };
534 EXPECT_EQ(func(100), 125);
536 Function<int(int), NEM> ufunc = std::move(func);
537 EXPECT_THROW(func(0), std::bad_function_call);
538 EXPECT_EQ(ufunc(200), 225);
540 EXPECT_EQ(ufunc.target_type(), typeid(std::function<int(int)>));
542 EXPECT_FALSE(ufunc.template target<int>());
543 EXPECT_FALSE(ufunc.template target<std::function<void(void)>>());
545 std::function<int(int)>& ufunc_target =
546 *ufunc.template target<std::function<int(int)>>();
548 EXPECT_EQ(ufunc_target(300), 325);
551 TEST(Function, Target_T) {
552 target_test<FunctionMoveCtor::MAY_THROW>();
554 TEST(Function, Target_N) {
555 target_test<FunctionMoveCtor::NO_THROW>();
558 // TEST =====================================================================
561 TEST(Function, OverloadedFunctor) {
562 struct OverloadedFunctor {
564 int operator()(int x) {
568 // variant 2 (const-overload of v1)
569 int operator()(int x) const {
574 int operator()(int x, int) {
578 // variant 4 (const-overload of v3)
579 int operator()(int x, int) const {
583 // variant 5 (non-const, has no const-overload)
584 int operator()(int x, char const*) {
588 // variant 6 (const only)
589 int operator()(int x, std::vector<int> const&) const {
593 OverloadedFunctor of;
595 Function<int(int)> variant1 = of;
596 EXPECT_EQ(variant1(15), 100 + 1 * 15);
598 Function<int(int) const> variant2 = of;
599 EXPECT_EQ(variant2(16), 100 + 2 * 16);
601 Function<int(int, int)> variant3 = of;
602 EXPECT_EQ(variant3(17, 0), 100 + 3 * 17);
604 Function<int(int, int) const> variant4 = of;
605 EXPECT_EQ(variant4(18, 0), 100 + 4 * 18);
607 Function<int(int, char const*)> variant5 = of;
608 EXPECT_EQ(variant5(19, "foo"), 100 + 5 * 19);
610 Function<int(int, std::vector<int> const&)> variant6 = of;
611 EXPECT_EQ(variant6(20, {}), 100 + 6 * 20);
612 EXPECT_EQ(variant6(20, {1, 2, 3}), 100 + 6 * 20);
614 Function<int(int, std::vector<int> const&) const> variant6const = of;
615 EXPECT_EQ(variant6const(21, {}), 100 + 6 * 21);
617 // Cast const-functions to non-const and the other way around: if the functor
618 // has both const and non-const operator()s for a given parameter signature,
619 // constructing a Function must select one of them, depending on
620 // whether the function type template parameter is const-qualified or not.
621 // When the const-ness is later changed (by moving the
622 // Function<R(Args...)const> into a Function<R(Args...)> or by
623 // calling the folly::constCastFunction which moves it into a
624 // Function<R(Args...)const>), the Function must still execute
625 // the initially selected function.
627 auto variant1_const = folly::constCastFunction(std::move(variant1));
628 EXPECT_THROW(variant1(0), std::bad_function_call);
629 EXPECT_EQ(variant1_const(22), 100 + 1 * 22);
631 Function<int(int)> variant2_nonconst = std::move(variant2);
632 EXPECT_THROW(variant2(0), std::bad_function_call);
633 EXPECT_EQ(variant2_nonconst(23), 100 + 2 * 23);
635 auto variant3_const = folly::constCastFunction(std::move(variant3));
636 EXPECT_THROW(variant3(0, 0), std::bad_function_call);
637 EXPECT_EQ(variant3_const(24, 0), 100 + 3 * 24);
639 Function<int(int, int)> variant4_nonconst = std::move(variant4);
640 EXPECT_THROW(variant4(0, 0), std::bad_function_call);
641 EXPECT_EQ(variant4_nonconst(25, 0), 100 + 4 * 25);
643 auto variant5_const = folly::constCastFunction(std::move(variant5));
644 EXPECT_THROW(variant5(0, ""), std::bad_function_call);
645 EXPECT_EQ(variant5_const(26, "foo"), 100 + 5 * 26);
647 auto variant6_const = folly::constCastFunction(std::move(variant6));
648 EXPECT_THROW(variant6(0, {}), std::bad_function_call);
649 EXPECT_EQ(variant6_const(27, {}), 100 + 6 * 27);
651 Function<int(int, std::vector<int> const&)> variant6const_nonconst =
652 std::move(variant6const);
653 EXPECT_THROW(variant6const(0, {}), std::bad_function_call);
654 EXPECT_EQ(variant6const_nonconst(28, {}), 100 + 6 * 28);
657 // TEST =====================================================================
660 TEST(Function, Lambda) {
661 // Non-mutable lambdas: can be stored in a non-const...
662 Function<int(int)> func = [](int x) { return 1000 + x; };
663 EXPECT_EQ(func(1), 1001);
665 // ...as well as in a const Function
666 Function<int(int) const> func_const = [](int x) { return 2000 + x; };
667 EXPECT_EQ(func_const(1), 2001);
669 // Mutable lambda: can only be stored in a const Function:
671 Function<int()> func_mutable = [number]() mutable { return ++number; };
672 EXPECT_EQ(func_mutable(), 3001);
673 EXPECT_EQ(func_mutable(), 3002);
675 // test after const-casting
677 Function<int(int) const> func_made_const =
678 folly::constCastFunction(std::move(func));
679 EXPECT_EQ(func_made_const(2), 1002);
680 EXPECT_THROW(func(0), std::bad_function_call);
682 Function<int(int)> func_const_made_nonconst = std::move(func_const);
683 EXPECT_EQ(func_const_made_nonconst(2), 2002);
684 EXPECT_THROW(func_const(0), std::bad_function_call);
686 Function<int() const> func_mutable_made_const =
687 folly::constCastFunction(std::move(func_mutable));
688 EXPECT_EQ(func_mutable_made_const(), 3003);
689 EXPECT_EQ(func_mutable_made_const(), 3004);
690 EXPECT_THROW(func_mutable(), std::bad_function_call);
693 // TEST =====================================================================
694 // DataMember & MemberFunction
706 TEST(Function, DataMember) {
708 MemberFunc const& cmf = mf;
711 Function<int(MemberFunc const*)> data_getter1 = &MemberFunc::x;
712 EXPECT_EQ(data_getter1(&cmf), 123);
713 Function<int(MemberFunc*)> data_getter2 = &MemberFunc::x;
714 EXPECT_EQ(data_getter2(&mf), 123);
715 Function<int(MemberFunc const&)> data_getter3 = &MemberFunc::x;
716 EXPECT_EQ(data_getter3(cmf), 123);
717 Function<int(MemberFunc&)> data_getter4 = &MemberFunc::x;
718 EXPECT_EQ(data_getter4(mf), 123);
721 TEST(Function, MemberFunction) {
723 MemberFunc const& cmf = mf;
726 Function<int(MemberFunc const*)> getter1 = &MemberFunc::getX;
727 EXPECT_EQ(getter1(&cmf), 123);
728 Function<int(MemberFunc*)> getter2 = &MemberFunc::getX;
729 EXPECT_EQ(getter2(&mf), 123);
730 Function<int(MemberFunc const&)> getter3 = &MemberFunc::getX;
731 EXPECT_EQ(getter3(cmf), 123);
732 Function<int(MemberFunc&)> getter4 = &MemberFunc::getX;
733 EXPECT_EQ(getter4(mf), 123);
735 Function<void(MemberFunc*, int)> setter1 = &MemberFunc::setX;
737 EXPECT_EQ(mf.x, 234);
739 Function<void(MemberFunc&, int)> setter2 = &MemberFunc::setX;
741 EXPECT_EQ(mf.x, 345);
744 // TEST =====================================================================
745 // CaptureCopyMoveCount & ParameterCopyMoveCount
747 class CopyMoveTracker {
749 struct ConstructorTag {};
751 CopyMoveTracker() = delete;
752 explicit CopyMoveTracker(ConstructorTag)
753 : data_(std::make_shared<std::pair<size_t, size_t>>(0, 0)) {}
755 CopyMoveTracker(CopyMoveTracker const& o) noexcept : data_(o.data_) {
758 CopyMoveTracker& operator=(CopyMoveTracker const& o) noexcept {
764 CopyMoveTracker(CopyMoveTracker&& o) noexcept : data_(o.data_) {
767 CopyMoveTracker& operator=(CopyMoveTracker&& o) noexcept {
773 size_t copyCount() const {
776 size_t moveCount() const {
777 return data_->second;
779 size_t refCount() const {
780 return data_.use_count();
782 void resetCounters() {
783 data_->first = data_->second = 0;
788 std::shared_ptr<std::pair<size_t, size_t>> data_;
791 TEST(Function, CaptureCopyMoveCount) {
792 // This test checks that no unnecessary copies/moves are made.
794 CopyMoveTracker cmt(CopyMoveTracker::ConstructorTag{});
795 EXPECT_EQ(cmt.copyCount(), 0);
796 EXPECT_EQ(cmt.moveCount(), 0);
797 EXPECT_EQ(cmt.refCount(), 1);
799 // Move into lambda, move lambda into Function
800 auto lambda1 = [cmt = std::move(cmt)]() {
801 return cmt.moveCount();
803 Function<size_t(void)> uf1 = std::move(lambda1);
805 // Max copies: 0. Max copy+moves: 2.
806 EXPECT_LE(cmt.moveCount() + cmt.copyCount(), 2);
807 EXPECT_LE(cmt.copyCount(), 0);
811 // Move into lambda, copy lambda into Function
812 auto lambda2 = [cmt = std::move(cmt)]() {
813 return cmt.moveCount();
815 Function<size_t(void)> uf2 = lambda2;
817 // Max copies: 1. Max copy+moves: 2.
818 EXPECT_LE(cmt.moveCount() + cmt.copyCount(), 2);
819 EXPECT_LE(cmt.copyCount(), 1);
821 // Invoking Function must not make copies/moves of the callable
825 EXPECT_EQ(cmt.copyCount(), 0);
826 EXPECT_EQ(cmt.moveCount(), 0);
829 TEST(Function, ParameterCopyMoveCount) {
830 // This test checks that no unnecessary copies/moves are made.
832 CopyMoveTracker cmt(CopyMoveTracker::ConstructorTag{});
833 EXPECT_EQ(cmt.copyCount(), 0);
834 EXPECT_EQ(cmt.moveCount(), 0);
835 EXPECT_EQ(cmt.refCount(), 1);
838 Function<size_t(CopyMoveTracker)> uf1 = [](CopyMoveTracker c) {
839 return c.moveCount();
844 // Max copies: 1. Max copy+moves: 2.
845 EXPECT_LE(cmt.moveCount() + cmt.copyCount(), 2);
846 EXPECT_LE(cmt.copyCount(), 1);
850 // Max copies: 1. Max copy+moves: 2.
851 EXPECT_LE(cmt.moveCount() + cmt.copyCount(), 2);
852 EXPECT_LE(cmt.copyCount(), 0);
855 Function<size_t(CopyMoveTracker&)> uf2 = [](CopyMoveTracker& c) {
856 return c.moveCount();
861 // Max copies: 0. Max copy+moves: 0.
862 EXPECT_LE(cmt.moveCount() + cmt.copyCount(), 0);
863 EXPECT_LE(cmt.copyCount(), 0);
865 // pass by const reference
866 Function<size_t(CopyMoveTracker const&)> uf3 = [](CopyMoveTracker const& c) {
867 return c.moveCount();
872 // Max copies: 0. Max copy+moves: 0.
873 EXPECT_LE(cmt.moveCount() + cmt.copyCount(), 0);
874 EXPECT_LE(cmt.copyCount(), 0);
876 // pass by rvalue reference
877 Function<size_t(CopyMoveTracker &&)> uf4 = [](CopyMoveTracker&& c) {
878 return c.moveCount();
883 // Max copies: 0. Max copy+moves: 0.
884 EXPECT_LE(cmt.moveCount() + cmt.copyCount(), 0);
885 EXPECT_LE(cmt.copyCount(), 0);
888 // TEST =====================================================================
891 enum ExceptionType { COPY, MOVE };
893 template <ExceptionType ET>
894 class CopyMoveException : public std::runtime_error {
896 using std::runtime_error::runtime_error;
899 template <bool CopyThrows, bool MoveThrows>
900 struct CopyMoveThrowsCallable {
901 int allowCopyOperations{0};
902 int allowMoveOperations{0};
904 CopyMoveThrowsCallable() = default;
905 CopyMoveThrowsCallable(CopyMoveThrowsCallable const& o) noexcept(
909 CopyMoveThrowsCallable& operator=(CopyMoveThrowsCallable const& o) noexcept(
911 allowCopyOperations = o.allowCopyOperations;
912 allowMoveOperations = o.allowMoveOperations;
914 if (allowCopyOperations > 0) {
915 --allowCopyOperations;
916 } else if (CopyThrows) {
917 throw CopyMoveException<COPY>("CopyMoveThrowsCallable copy");
921 CopyMoveThrowsCallable(CopyMoveThrowsCallable&& o) noexcept(!MoveThrows) {
922 *this = std::move(o);
924 CopyMoveThrowsCallable& operator=(CopyMoveThrowsCallable&& o) noexcept(
926 allowCopyOperations = o.allowCopyOperations;
927 allowMoveOperations = o.allowMoveOperations;
929 if (o.allowMoveOperations > 0) {
930 --allowMoveOperations;
931 } else if (MoveThrows) {
932 throw CopyMoveException<MOVE>("CopyMoveThrowsCallable move");
937 void operator()() const {}
940 TEST(Function, CopyMoveThrowsCallable) {
941 EXPECT_TRUE((std::is_nothrow_move_constructible<
942 CopyMoveThrowsCallable<false, false>>::value));
943 EXPECT_TRUE((std::is_nothrow_move_constructible<
944 CopyMoveThrowsCallable<true, false>>::value));
945 EXPECT_FALSE((std::is_nothrow_move_constructible<
946 CopyMoveThrowsCallable<false, true>>::value));
947 EXPECT_FALSE((std::is_nothrow_move_constructible<
948 CopyMoveThrowsCallable<true, true>>::value));
950 EXPECT_TRUE((std::is_nothrow_copy_constructible<
951 CopyMoveThrowsCallable<false, false>>::value));
952 EXPECT_FALSE((std::is_nothrow_copy_constructible<
953 CopyMoveThrowsCallable<true, false>>::value));
954 EXPECT_TRUE((std::is_nothrow_copy_constructible<
955 CopyMoveThrowsCallable<false, true>>::value));
956 EXPECT_FALSE((std::is_nothrow_copy_constructible<
957 CopyMoveThrowsCallable<true, true>>::value));
960 template <FunctionMoveCtor NEM, bool CopyThrows, bool MoveThrows>
961 void copy_and_move_throws_test() {
962 CopyMoveThrowsCallable<CopyThrows, MoveThrows> c;
963 Function<void(void), NEM> uf;
966 EXPECT_THROW((uf = c), CopyMoveException<COPY>);
968 EXPECT_NO_THROW((uf = c));
972 EXPECT_THROW((uf = std::move(c)), CopyMoveException<MOVE>);
974 EXPECT_NO_THROW((uf = std::move(c)));
977 c.allowMoveOperations = 1;
979 if (NEM == FunctionMoveCtor::MAY_THROW && MoveThrows) {
980 Function<void(void), NEM> uf2;
981 EXPECT_THROW((uf2 = std::move(uf)), CopyMoveException<MOVE>);
983 Function<void(void), NEM> uf2;
984 EXPECT_NO_THROW((uf2 = std::move(uf)));
987 c.allowMoveOperations = 0;
988 c.allowCopyOperations = 1;
990 if (NEM == FunctionMoveCtor::MAY_THROW && MoveThrows) {
991 Function<void(void), NEM> uf2;
992 EXPECT_THROW((uf2 = std::move(uf)), CopyMoveException<MOVE>);
994 Function<void(void), NEM> uf2;
995 EXPECT_NO_THROW((uf2 = std::move(uf)));
999 TEST(Function, CopyAndMoveThrows_TNN) {
1000 copy_and_move_throws_test<FunctionMoveCtor::MAY_THROW, false, false>();
1003 TEST(Function, CopyAndMoveThrows_NNN) {
1004 copy_and_move_throws_test<FunctionMoveCtor::NO_THROW, false, false>();
1007 TEST(Function, CopyAndMoveThrows_TTN) {
1008 copy_and_move_throws_test<FunctionMoveCtor::MAY_THROW, true, false>();
1011 TEST(Function, CopyAndMoveThrows_NTN) {
1012 copy_and_move_throws_test<FunctionMoveCtor::NO_THROW, true, false>();
1015 TEST(Function, CopyAndMoveThrows_TNT) {
1016 copy_and_move_throws_test<FunctionMoveCtor::MAY_THROW, false, true>();
1019 TEST(Function, CopyAndMoveThrows_NNT) {
1020 copy_and_move_throws_test<FunctionMoveCtor::NO_THROW, false, true>();
1023 TEST(Function, CopyAndMoveThrows_TTT) {
1024 copy_and_move_throws_test<FunctionMoveCtor::MAY_THROW, true, true>();
1027 TEST(Function, CopyAndMoveThrows_NTT) {
1028 copy_and_move_throws_test<FunctionMoveCtor::NO_THROW, true, true>();
1031 // TEST =====================================================================
1032 // VariadicTemplate & VariadicArguments
1034 struct VariadicTemplateSum {
1035 int operator()() const {
1038 template <class... Args>
1039 int operator()(int x, Args... args) const {
1040 return x + (*this)(args...);
1044 TEST(Function, VariadicTemplate) {
1045 Function<int(int)> uf1 = VariadicTemplateSum();
1046 Function<int(int, int)> uf2 = VariadicTemplateSum();
1047 Function<int(int, int, int)> uf3 = VariadicTemplateSum();
1049 EXPECT_EQ(uf1(66), 66);
1050 EXPECT_EQ(uf2(55, 44), 99);
1051 EXPECT_EQ(uf3(33, 22, 11), 66);
1054 struct VariadicArgumentsSum {
1055 int operator()(int count, ...) const {
1058 va_start(args, count);
1059 for (int i = 0; i < count; ++i) {
1060 result += va_arg(args, int);
1067 TEST(Function, VariadicArguments) {
1068 Function<int(int)> uf1 = VariadicArgumentsSum();
1069 Function<int(int, int)> uf2 = VariadicArgumentsSum();
1070 Function<int(int, int, int)> uf3 = VariadicArgumentsSum();
1072 EXPECT_EQ(uf1(0), 0);
1073 EXPECT_EQ(uf2(1, 66), 66);
1074 EXPECT_EQ(uf3(2, 55, 44), 99);
1077 // TEST =====================================================================
1078 // SafeCaptureByReference
1080 // A function can use Function const& as a parameter to signal that it
1081 // is safe to pass a lambda that captures local variables by reference.
1082 // It is safe because we know the function called can only invoke the
1083 // Function until it returns. It can't store a copy of the Function
1084 // (because it's not copyable), and it can't move the Function somewhere
1085 // else (because it gets only a const&).
1087 template <typename T>
1090 Function<void(typename T::value_type const&) const> const& func) {
1091 for (auto const& elem : range) {
1096 TEST(Function, SafeCaptureByReference) {
1097 std::vector<int> const vec = {20, 30, 40, 2, 3, 4, 200, 300, 400};
1101 // for_each's second parameter is of type Function<...> const&.
1102 // Hence we know we can safely pass it a lambda that references local
1103 // variables. There is no way the reference to x will be stored anywhere.
1104 for_each<std::vector<int>>(vec, [&sum](int x) { sum += x; });
1106 // gcc versions before 4.9 cannot deduce the type T in the above call
1107 // to for_each. Modern compiler versions can compile the following line:
1108 // for_each(vec, [&sum](int x) { sum += x; });
1110 EXPECT_EQ(sum, 999);
1113 // TEST =====================================================================
1114 // IgnoreReturnValue
1116 TEST(Function, IgnoreReturnValue) {
1119 // Assign a lambda that return int to a folly::Function that returns void.
1120 Function<void()> f = [&]() -> int { return ++x; };
1126 Function<int()> g = [&]() -> int { return ++x; };
1127 Function<void()> cg = std::move(g);
1134 // TEST =====================================================================
1135 // ReturnConvertible, ConvertReturnType
1137 TEST(Function, ReturnConvertible) {
1141 struct CDerived : CBase {};
1143 Function<double()> f1 = []() -> int { return 5; };
1144 EXPECT_EQ(f1(), 5.0);
1146 Function<int()> f2 = []() -> double { return 5.2; };
1152 Function<CBase const&()> f3 = [&]() -> CDerived const& { return derived; };
1153 EXPECT_EQ(f3().x, 55);
1155 Function<CBase const&()> f4 = [&]() -> CDerived& { return derived; };
1156 EXPECT_EQ(f4().x, 55);
1158 Function<CBase&()> f5 = [&]() -> CDerived& { return derived; };
1159 EXPECT_EQ(f5().x, 55);
1161 Function<CBase const*()> f6 = [&]() -> CDerived const* { return &derived; };
1162 EXPECT_EQ(f6()->x, 55);
1164 Function<CBase const*()> f7 = [&]() -> CDerived* { return &derived; };
1165 EXPECT_EQ(f7()->x, 55);
1167 Function<CBase*()> f8 = [&]() -> CDerived* { return &derived; };
1168 EXPECT_EQ(f8()->x, 55);
1170 Function<CBase()> f9 = [&]() -> CDerived {
1175 EXPECT_EQ(f9().x, 66);
1178 TEST(Function, ConvertReturnType) {
1182 struct CDerived : CBase {};
1184 Function<int()> f1 = []() -> int { return 5; };
1185 Function<double()> cf1 = std::move(f1);
1186 EXPECT_EQ(cf1(), 5.0);
1187 Function<int()> ccf1 = std::move(cf1);
1188 EXPECT_EQ(ccf1(), 5);
1190 Function<double()> f2 = []() -> double { return 5.2; };
1191 Function<int()> cf2 = std::move(f2);
1192 EXPECT_EQ(cf2(), 5);
1193 Function<double()> ccf2 = std::move(cf2);
1194 EXPECT_EQ(ccf2(), 5.0);
1199 Function<CDerived const&()> f3 = [&]() -> CDerived const& { return derived; };
1200 Function<CBase const&()> cf3 = std::move(f3);
1201 EXPECT_EQ(cf3().x, 55);
1203 Function<CDerived&()> f4 = [&]() -> CDerived& { return derived; };
1204 Function<CBase const&()> cf4 = std::move(f4);
1205 EXPECT_EQ(cf4().x, 55);
1207 Function<CDerived&()> f5 = [&]() -> CDerived& { return derived; };
1208 Function<CBase&()> cf5 = std::move(f5);
1209 EXPECT_EQ(cf5().x, 55);
1211 Function<CDerived const*()> f6 = [&]() -> CDerived const* {
1214 Function<CBase const*()> cf6 = std::move(f6);
1215 EXPECT_EQ(cf6()->x, 55);
1217 Function<CDerived const*()> f7 = [&]() -> CDerived* { return &derived; };
1218 Function<CBase const*()> cf7 = std::move(f7);
1219 EXPECT_EQ(cf7()->x, 55);
1221 Function<CDerived*()> f8 = [&]() -> CDerived* { return &derived; };
1222 Function<CBase*()> cf8 = std::move(f8);
1223 EXPECT_EQ(cf8()->x, 55);
1225 Function<CDerived()> f9 = [&]() -> CDerived {
1230 Function<CBase()> cf9 = std::move(f9);
1231 EXPECT_EQ(cf9().x, 66);
1234 TEST(Function, asStdFunction_void) {
1236 folly::Function<void()> f = [&] { ++i; };
1237 auto sf = std::move(f).asStdFunction();
1238 static_assert(std::is_same<decltype(sf), std::function<void()>>::value,
1239 "std::function has wrong type");
1244 TEST(Function, asStdFunction_void_const) {
1246 folly::Function<void() const> f = [&] { ++i; };
1247 auto sf = std::move(f).asStdFunction();
1248 static_assert(std::is_same<decltype(sf), std::function<void()>>::value,
1249 "std::function has wrong type");
1254 TEST(Function, asStdFunction_return) {
1256 folly::Function<int()> f = [&] {
1260 auto sf = std::move(f).asStdFunction();
1261 static_assert(std::is_same<decltype(sf), std::function<int()>>::value,
1262 "std::function has wrong type");
1263 EXPECT_EQ(42, sf());
1267 TEST(Function, asStdFunction_return_const) {
1269 folly::Function<int() const> f = [&] {
1273 auto sf = std::move(f).asStdFunction();
1274 static_assert(std::is_same<decltype(sf), std::function<int()>>::value,
1275 "std::function has wrong type");
1276 EXPECT_EQ(42, sf());
1280 TEST(Function, asStdFunction_args) {
1282 folly::Function<void(int, int)> f = [&](int x, int y) {
1286 auto sf = std::move(f).asStdFunction();
1287 static_assert(std::is_same<decltype(sf), std::function<void(int, int)>>::value,
1288 "std::function has wrong type");
1293 TEST(Function, asStdFunction_args_const) {
1295 folly::Function<void(int, int) const> f = [&](int x, int y) {
1299 auto sf = std::move(f).asStdFunction();
1300 static_assert(std::is_same<decltype(sf), std::function<void(int, int)>>::value,
1301 "std::function has wrong type");