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>
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);
279 EXPECT_EQ(mf2(100), 125);
280 EXPECT_EQ(mf1(100), 211);
282 Function<int(int)> mf3(nullptr);
283 EXPECT_EQ(mf3, nullptr);
287 EXPECT_EQ(mf3(100), 211);
288 EXPECT_EQ(mf1, nullptr);
290 Function<int(int)> mf4([](int x) { return x + 222; });
291 EXPECT_EQ(mf4(100), 322);
294 EXPECT_EQ(mf4(100), 211);
295 EXPECT_EQ(mf3(100), 322);
298 EXPECT_EQ(mf3, nullptr);
299 EXPECT_EQ(mf1(100), 322);
301 TEST(Function, Swap_TT) {
302 swap_test<FunctionMoveCtor::MAY_THROW, FunctionMoveCtor::MAY_THROW>();
304 TEST(Function, Swap_TN) {
305 swap_test<FunctionMoveCtor::MAY_THROW, FunctionMoveCtor::NO_THROW>();
307 TEST(Function, Swap_NT) {
308 swap_test<FunctionMoveCtor::NO_THROW, FunctionMoveCtor::MAY_THROW>();
310 TEST(Function, Swap_NN) {
311 swap_test<FunctionMoveCtor::NO_THROW, FunctionMoveCtor::NO_THROW>();
314 // TEST =====================================================================
317 template <FunctionMoveCtor NEM>
319 Function<float(float, float), NEM> fnc = floatMult;
320 auto task = std::bind(std::move(fnc), 2.f, 4.f);
321 EXPECT_THROW(fnc(0, 0), std::bad_function_call);
322 EXPECT_EQ(task(), 8);
323 auto task2(std::move(task));
324 EXPECT_THROW(task(), std::bad_function_call);
325 EXPECT_EQ(task2(), 8);
327 TEST(Function, Bind_T) {
328 bind_test<FunctionMoveCtor::MAY_THROW>();
330 TEST(Function, Bind_N) {
331 bind_test<FunctionMoveCtor::NO_THROW>();
334 // TEST =====================================================================
337 template <FunctionMoveCtor NEM, size_t S>
338 void non_copyable_lambda_test() {
339 auto unique_ptr_int = folly::make_unique<int>(900);
340 EXPECT_EQ(*unique_ptr_int, 900);
342 char fooData[64] = {0};
343 EXPECT_EQ(fooData[0], 0); // suppress gcc warning about fooData not being used
345 auto functor = std::bind(
346 [fooData](std::unique_ptr<int>& up) mutable { return ++*up; },
347 std::move(unique_ptr_int));
349 EXPECT_EQ(functor(), 901);
351 Function<int(void), NEM, sizeof(functor)* S / 2> func = std::move(functor);
353 func.hasAllocatedMemory(),
354 S < 2 || (NEM == FunctionMoveCtor::NO_THROW &&
355 !std::is_nothrow_move_constructible<decltype(functor)>::value));
357 EXPECT_EQ(func(), 902);
359 TEST(Function, NonCopyableLambda_T0) {
360 non_copyable_lambda_test<FunctionMoveCtor::MAY_THROW, 0>();
362 TEST(Function, NonCopyableLambda_N0) {
363 non_copyable_lambda_test<FunctionMoveCtor::NO_THROW, 0>();
365 TEST(Function, NonCopyableLambda_T1) {
366 non_copyable_lambda_test<FunctionMoveCtor::MAY_THROW, 1>();
368 TEST(Function, NonCopyableLambda_N1) {
369 non_copyable_lambda_test<FunctionMoveCtor::NO_THROW, 1>();
371 TEST(Function, NonCopyableLambda_T2) {
372 non_copyable_lambda_test<FunctionMoveCtor::MAY_THROW, 2>();
374 TEST(Function, NonCopyableLambda_N2) {
375 non_copyable_lambda_test<FunctionMoveCtor::NO_THROW, 2>();
377 TEST(Function, NonCopyableLambda_T3) {
378 non_copyable_lambda_test<FunctionMoveCtor::MAY_THROW, 3>();
380 TEST(Function, NonCopyableLambda_N3) {
381 non_copyable_lambda_test<FunctionMoveCtor::NO_THROW, 3>();
384 // TEST =====================================================================
387 template <FunctionMoveCtor NEM>
388 void downsize_test() {
389 Functor<int, 10> functor;
393 EXPECT_EQ(functor(3), 123);
395 // Function with large callable storage area (twice the size of
397 Function<int(size_t, int), NEM, sizeof(functor)* 2> func2x =
399 EXPECT_FALSE(func2x.hasAllocatedMemory());
400 EXPECT_EQ(func2x(3, 200), 123);
401 EXPECT_EQ(func2x(3, 201), 200);
403 // Function with sufficient callable storage area (equal to
404 // size of the functor)
405 Function<int(size_t, int), NEM, sizeof(functor)> func1x = std::move(func2x);
406 EXPECT_THROW(func2x(0, 0), std::bad_function_call);
407 EXPECT_FALSE(func2x);
408 EXPECT_FALSE(func1x.hasAllocatedMemory());
409 EXPECT_EQ(func1x(3, 202), 201);
410 EXPECT_EQ(func1x(3, 203), 202);
412 // Function with minimal callable storage area (functor does
413 // not fit and will be moved to memory on the heap)
414 Function<int(size_t, int), NEM, 0> func0x = std::move(func1x);
415 EXPECT_THROW(func1x(0, 0), std::bad_function_call);
416 EXPECT_FALSE(func1x);
417 EXPECT_TRUE(func0x.hasAllocatedMemory());
418 EXPECT_EQ(func0x(3, 204), 203);
419 EXPECT_EQ(func0x(3, 205), 204);
421 // bonus test: move to Function with opposite NoExceptMovable
425 NEM == FunctionMoveCtor::NO_THROW ? FunctionMoveCtor::MAY_THROW
426 : FunctionMoveCtor::NO_THROW,
428 funcnot = std::move(func0x);
429 EXPECT_THROW(func0x(0, 0), std::bad_function_call);
430 EXPECT_FALSE(func0x);
431 EXPECT_TRUE(funcnot.hasAllocatedMemory());
432 EXPECT_EQ(funcnot(3, 206), 205);
433 EXPECT_EQ(funcnot(3, 207), 206);
435 TEST(Function, Downsize_T) {
436 downsize_test<FunctionMoveCtor::MAY_THROW>();
438 TEST(Function, Downsize_N) {
439 downsize_test<FunctionMoveCtor::NO_THROW>();
442 // TEST =====================================================================
445 template <FunctionMoveCtor NEM>
446 void refcount_test() {
447 Functor<int, 100> functor;
449 auto shared_int = std::make_shared<int>(100);
451 EXPECT_EQ(*shared_int, 100);
452 EXPECT_EQ(shared_int.use_count(), 1);
454 Function<int(void), NEM> func1 = [shared_int]() { return ++*shared_int; };
455 EXPECT_EQ(shared_int.use_count(), 2);
456 EXPECT_EQ(func1(), 101);
457 EXPECT_EQ(*shared_int, 101);
459 // func2: made to not fit functor.
460 Function<int(void), NEM, sizeof(functor) / 2> func2 = std::move(func1);
461 EXPECT_THROW(func1(), std::bad_function_call);
462 EXPECT_EQ(shared_int.use_count(), 2);
464 EXPECT_EQ(func2(), 102);
465 EXPECT_EQ(*shared_int, 102);
467 func2 = [shared_int]() { return ++*shared_int; };
468 EXPECT_EQ(shared_int.use_count(), 2);
469 EXPECT_EQ(func2(), 103);
470 EXPECT_EQ(*shared_int, 103);
472 // We set func2 to a lambda that captures 'functor', which forces it on
474 func2 = [functor]() { return functor(3); };
475 EXPECT_TRUE(func2.hasAllocatedMemory());
476 EXPECT_EQ(func2(), 999);
477 EXPECT_EQ(shared_int.use_count(), 1);
478 EXPECT_EQ(*shared_int, 103);
480 func2 = [shared_int]() { return ++*shared_int; };
481 EXPECT_EQ(shared_int.use_count(), 2);
482 EXPECT_EQ(func2(), 104);
483 EXPECT_EQ(*shared_int, 104);
485 // We set func2 to function pointer, which always fits into the
486 // Function object and is no-except-movable
487 func2 = &func_int_return_987;
488 EXPECT_FALSE(func2.hasAllocatedMemory());
489 EXPECT_EQ(func2(), 987);
490 EXPECT_EQ(shared_int.use_count(), 1);
491 EXPECT_EQ(*shared_int, 104);
493 TEST(Function, Refcount_T) {
494 refcount_test<FunctionMoveCtor::MAY_THROW>();
496 TEST(Function, Refcount_N) {
497 refcount_test<FunctionMoveCtor::NO_THROW>();
500 // TEST =====================================================================
503 template <FunctionMoveCtor NEM>
505 std::function<int(int)> func = [](int x) { return x + 25; };
506 EXPECT_EQ(func(100), 125);
508 Function<int(int), NEM> ufunc = std::move(func);
509 EXPECT_THROW(func(0), std::bad_function_call);
510 EXPECT_EQ(ufunc(200), 225);
512 EXPECT_EQ(ufunc.target_type(), typeid(std::function<int(int)>));
514 EXPECT_FALSE(ufunc.template target<int>());
515 EXPECT_FALSE(ufunc.template target<std::function<void(void)>>());
517 std::function<int(int)>& ufunc_target =
518 *ufunc.template target<std::function<int(int)>>();
520 EXPECT_EQ(ufunc_target(300), 325);
523 TEST(Function, Target_T) {
524 target_test<FunctionMoveCtor::MAY_THROW>();
526 TEST(Function, Target_N) {
527 target_test<FunctionMoveCtor::NO_THROW>();
530 // TEST =====================================================================
533 TEST(Function, OverloadedFunctor) {
534 struct OverloadedFunctor {
536 int operator()(int x) {
540 // variant 2 (const-overload of v1)
541 int operator()(int x) const {
546 int operator()(int x, int) {
550 // variant 4 (const-overload of v3)
551 int operator()(int x, int) const {
555 // variant 5 (non-const, has no const-overload)
556 int operator()(int x, char const*) {
560 // variant 6 (const only)
561 int operator()(int x, std::vector<int> const&) const {
565 OverloadedFunctor of;
567 Function<int(int)> variant1 = of;
568 EXPECT_EQ(variant1(15), 100 + 1 * 15);
570 Function<int(int) const> variant2 = of;
571 EXPECT_EQ(variant2(16), 100 + 2 * 16);
573 Function<int(int, int)> variant3 = of;
574 EXPECT_EQ(variant3(17, 0), 100 + 3 * 17);
576 Function<int(int, int) const> variant4 = of;
577 EXPECT_EQ(variant4(18, 0), 100 + 4 * 18);
579 Function<int(int, char const*)> variant5 = of;
580 EXPECT_EQ(variant5(19, "foo"), 100 + 5 * 19);
582 Function<int(int, std::vector<int> const&)> variant6 = of;
583 EXPECT_EQ(variant6(20, {}), 100 + 6 * 20);
584 EXPECT_EQ(variant6(20, {1, 2, 3}), 100 + 6 * 20);
586 Function<int(int, std::vector<int> const&) const> variant6const = of;
587 EXPECT_EQ(variant6const(21, {}), 100 + 6 * 21);
589 // Cast const-functions to non-const and the other way around: if the functor
590 // has both const and non-const operator()s for a given parameter signature,
591 // constructing a Function must select one of them, depending on
592 // whether the function type template parameter is const-qualified or not.
593 // When the const-ness is later changed (by moving the
594 // Function<R(Args...)const> into a Function<R(Args...)> or by
595 // calling the folly::constCastFunction which moves it into a
596 // Function<R(Args...)const>), the Function must still execute
597 // the initially selected function.
599 auto variant1_const = folly::constCastFunction(std::move(variant1));
600 EXPECT_THROW(variant1(0), std::bad_function_call);
601 EXPECT_EQ(variant1_const(22), 100 + 1 * 22);
603 Function<int(int)> variant2_nonconst = std::move(variant2);
604 EXPECT_THROW(variant2(0), std::bad_function_call);
605 EXPECT_EQ(variant2_nonconst(23), 100 + 2 * 23);
607 auto variant3_const = folly::constCastFunction(std::move(variant3));
608 EXPECT_THROW(variant3(0, 0), std::bad_function_call);
609 EXPECT_EQ(variant3_const(24, 0), 100 + 3 * 24);
611 Function<int(int, int)> variant4_nonconst = std::move(variant4);
612 EXPECT_THROW(variant4(0, 0), std::bad_function_call);
613 EXPECT_EQ(variant4_nonconst(25, 0), 100 + 4 * 25);
615 auto variant5_const = folly::constCastFunction(std::move(variant5));
616 EXPECT_THROW(variant5(0, ""), std::bad_function_call);
617 EXPECT_EQ(variant5_const(26, "foo"), 100 + 5 * 26);
619 auto variant6_const = folly::constCastFunction(std::move(variant6));
620 EXPECT_THROW(variant6(0, {}), std::bad_function_call);
621 EXPECT_EQ(variant6_const(27, {}), 100 + 6 * 27);
623 Function<int(int, std::vector<int> const&)> variant6const_nonconst =
624 std::move(variant6const);
625 EXPECT_THROW(variant6const(0, {}), std::bad_function_call);
626 EXPECT_EQ(variant6const_nonconst(28, {}), 100 + 6 * 28);
629 // TEST =====================================================================
632 TEST(Function, Lambda) {
633 // Non-mutable lambdas: can be stored in a non-const...
634 Function<int(int)> func = [](int x) { return 1000 + x; };
635 EXPECT_EQ(func(1), 1001);
637 // ...as well as in a const Function
638 Function<int(int) const> func_const = [](int x) { return 2000 + x; };
639 EXPECT_EQ(func_const(1), 2001);
641 // Mutable lambda: can only be stored in a const Function:
643 Function<int()> func_mutable = [number]() mutable { return ++number; };
644 EXPECT_EQ(func_mutable(), 3001);
645 EXPECT_EQ(func_mutable(), 3002);
647 // test after const-casting
649 Function<int(int) const> func_made_const =
650 folly::constCastFunction(std::move(func));
651 EXPECT_EQ(func_made_const(2), 1002);
652 EXPECT_THROW(func(0), std::bad_function_call);
654 Function<int(int)> func_const_made_nonconst = std::move(func_const);
655 EXPECT_EQ(func_const_made_nonconst(2), 2002);
656 EXPECT_THROW(func_const(0), std::bad_function_call);
658 Function<int() const> func_mutable_made_const =
659 folly::constCastFunction(std::move(func_mutable));
660 EXPECT_EQ(func_mutable_made_const(), 3003);
661 EXPECT_EQ(func_mutable_made_const(), 3004);
662 EXPECT_THROW(func_mutable(), std::bad_function_call);
665 // TEST =====================================================================
666 // DataMember & MemberFunction
678 TEST(Function, DataMember) {
680 MemberFunc const& cmf = mf;
683 Function<int(MemberFunc const*)> data_getter1 = &MemberFunc::x;
684 EXPECT_EQ(data_getter1(&cmf), 123);
685 Function<int(MemberFunc*)> data_getter2 = &MemberFunc::x;
686 EXPECT_EQ(data_getter2(&mf), 123);
687 Function<int(MemberFunc const&)> data_getter3 = &MemberFunc::x;
688 EXPECT_EQ(data_getter3(cmf), 123);
689 Function<int(MemberFunc&)> data_getter4 = &MemberFunc::x;
690 EXPECT_EQ(data_getter4(mf), 123);
693 TEST(Function, MemberFunction) {
695 MemberFunc const& cmf = mf;
698 Function<int(MemberFunc const*)> getter1 = &MemberFunc::getX;
699 EXPECT_EQ(getter1(&cmf), 123);
700 Function<int(MemberFunc*)> getter2 = &MemberFunc::getX;
701 EXPECT_EQ(getter2(&mf), 123);
702 Function<int(MemberFunc const&)> getter3 = &MemberFunc::getX;
703 EXPECT_EQ(getter3(cmf), 123);
704 Function<int(MemberFunc&)> getter4 = &MemberFunc::getX;
705 EXPECT_EQ(getter4(mf), 123);
707 Function<void(MemberFunc*, int)> setter1 = &MemberFunc::setX;
709 EXPECT_EQ(mf.x, 234);
711 Function<void(MemberFunc&, int)> setter2 = &MemberFunc::setX;
713 EXPECT_EQ(mf.x, 345);
716 // TEST =====================================================================
717 // CaptureCopyMoveCount & ParameterCopyMoveCount
719 class CopyMoveTracker {
721 struct ConstructorTag {};
723 CopyMoveTracker() = delete;
724 explicit CopyMoveTracker(ConstructorTag)
725 : data_(std::make_shared<std::pair<size_t, size_t>>(0, 0)) {}
727 CopyMoveTracker(CopyMoveTracker const& o) noexcept : data_(o.data_) {
730 CopyMoveTracker& operator=(CopyMoveTracker const& o) noexcept {
736 CopyMoveTracker(CopyMoveTracker&& o) noexcept : data_(o.data_) {
739 CopyMoveTracker& operator=(CopyMoveTracker&& o) noexcept {
745 size_t copyCount() const {
748 size_t moveCount() const {
749 return data_->second;
751 size_t refCount() const {
752 return data_.use_count();
754 void resetCounters() {
755 data_->first = data_->second = 0;
760 std::shared_ptr<std::pair<size_t, size_t>> data_;
763 TEST(Function, CaptureCopyMoveCount) {
764 // This test checks that no unnecessary copies/moves are made.
766 CopyMoveTracker cmt(CopyMoveTracker::ConstructorTag{});
767 EXPECT_EQ(cmt.copyCount(), 0);
768 EXPECT_EQ(cmt.moveCount(), 0);
769 EXPECT_EQ(cmt.refCount(), 1);
771 // Move into lambda, move lambda into Function
772 auto lambda1 = [cmt = std::move(cmt)]() {
773 return cmt.moveCount();
775 Function<size_t(void)> uf1 = std::move(lambda1);
777 // Max copies: 0. Max copy+moves: 2.
778 EXPECT_LE(cmt.moveCount() + cmt.copyCount(), 2);
779 EXPECT_LE(cmt.copyCount(), 0);
783 // Move into lambda, copy lambda into Function
784 auto lambda2 = [cmt = std::move(cmt)]() {
785 return cmt.moveCount();
787 Function<size_t(void)> uf2 = lambda2;
789 // Max copies: 1. Max copy+moves: 2.
790 EXPECT_LE(cmt.moveCount() + cmt.copyCount(), 2);
791 EXPECT_LE(cmt.copyCount(), 1);
793 // Invoking Function must not make copies/moves of the callable
797 EXPECT_EQ(cmt.copyCount(), 0);
798 EXPECT_EQ(cmt.moveCount(), 0);
801 TEST(Function, ParameterCopyMoveCount) {
802 // This test checks that no unnecessary copies/moves are made.
804 CopyMoveTracker cmt(CopyMoveTracker::ConstructorTag{});
805 EXPECT_EQ(cmt.copyCount(), 0);
806 EXPECT_EQ(cmt.moveCount(), 0);
807 EXPECT_EQ(cmt.refCount(), 1);
810 Function<size_t(CopyMoveTracker)> uf1 = [](CopyMoveTracker c) {
811 return c.moveCount();
816 // Max copies: 1. Max copy+moves: 2.
817 EXPECT_LE(cmt.moveCount() + cmt.copyCount(), 2);
818 EXPECT_LE(cmt.copyCount(), 1);
822 // Max copies: 1. Max copy+moves: 2.
823 EXPECT_LE(cmt.moveCount() + cmt.copyCount(), 2);
824 EXPECT_LE(cmt.copyCount(), 0);
827 Function<size_t(CopyMoveTracker&)> uf2 = [](CopyMoveTracker& c) {
828 return c.moveCount();
833 // Max copies: 0. Max copy+moves: 0.
834 EXPECT_LE(cmt.moveCount() + cmt.copyCount(), 0);
835 EXPECT_LE(cmt.copyCount(), 0);
837 // pass by const reference
838 Function<size_t(CopyMoveTracker const&)> uf3 = [](CopyMoveTracker const& c) {
839 return c.moveCount();
844 // Max copies: 0. Max copy+moves: 0.
845 EXPECT_LE(cmt.moveCount() + cmt.copyCount(), 0);
846 EXPECT_LE(cmt.copyCount(), 0);
848 // pass by rvalue reference
849 Function<size_t(CopyMoveTracker &&)> uf4 = [](CopyMoveTracker&& c) {
850 return c.moveCount();
855 // Max copies: 0. Max copy+moves: 0.
856 EXPECT_LE(cmt.moveCount() + cmt.copyCount(), 0);
857 EXPECT_LE(cmt.copyCount(), 0);
860 // TEST =====================================================================
863 enum ExceptionType { COPY, MOVE };
865 template <ExceptionType ET>
866 class CopyMoveException : public std::runtime_error {
868 using std::runtime_error::runtime_error;
871 template <bool CopyThrows, bool MoveThrows>
872 struct CopyMoveThrowsCallable {
873 int allowCopyOperations{0};
874 int allowMoveOperations{0};
876 CopyMoveThrowsCallable() = default;
877 CopyMoveThrowsCallable(CopyMoveThrowsCallable const& o) noexcept(
881 CopyMoveThrowsCallable& operator=(CopyMoveThrowsCallable const& o) noexcept(
883 allowCopyOperations = o.allowCopyOperations;
884 allowMoveOperations = o.allowMoveOperations;
886 if (allowCopyOperations > 0) {
887 --allowCopyOperations;
888 } else if (CopyThrows) {
889 throw CopyMoveException<COPY>("CopyMoveThrowsCallable copy");
893 CopyMoveThrowsCallable(CopyMoveThrowsCallable&& o) noexcept(!MoveThrows) {
894 *this = std::move(o);
896 CopyMoveThrowsCallable& operator=(CopyMoveThrowsCallable&& o) noexcept(
898 allowCopyOperations = o.allowCopyOperations;
899 allowMoveOperations = o.allowMoveOperations;
901 if (o.allowMoveOperations > 0) {
902 --allowMoveOperations;
903 } else if (MoveThrows) {
904 throw CopyMoveException<MOVE>("CopyMoveThrowsCallable move");
909 void operator()() const {}
912 TEST(Function, CopyMoveThrowsCallable) {
913 EXPECT_TRUE((std::is_nothrow_move_constructible<
914 CopyMoveThrowsCallable<false, false>>::value));
915 EXPECT_TRUE((std::is_nothrow_move_constructible<
916 CopyMoveThrowsCallable<true, false>>::value));
917 EXPECT_FALSE((std::is_nothrow_move_constructible<
918 CopyMoveThrowsCallable<false, true>>::value));
919 EXPECT_FALSE((std::is_nothrow_move_constructible<
920 CopyMoveThrowsCallable<true, true>>::value));
922 EXPECT_TRUE((std::is_nothrow_copy_constructible<
923 CopyMoveThrowsCallable<false, false>>::value));
924 EXPECT_FALSE((std::is_nothrow_copy_constructible<
925 CopyMoveThrowsCallable<true, false>>::value));
926 EXPECT_TRUE((std::is_nothrow_copy_constructible<
927 CopyMoveThrowsCallable<false, true>>::value));
928 EXPECT_FALSE((std::is_nothrow_copy_constructible<
929 CopyMoveThrowsCallable<true, true>>::value));
932 template <FunctionMoveCtor NEM, bool CopyThrows, bool MoveThrows>
933 void copy_and_move_throws_test() {
934 CopyMoveThrowsCallable<CopyThrows, MoveThrows> c;
935 Function<void(void), NEM> uf;
938 EXPECT_THROW((uf = c), CopyMoveException<COPY>);
940 EXPECT_NO_THROW((uf = c));
944 EXPECT_THROW((uf = std::move(c)), CopyMoveException<MOVE>);
946 EXPECT_NO_THROW((uf = std::move(c)));
949 c.allowMoveOperations = 1;
951 if (NEM == FunctionMoveCtor::MAY_THROW && MoveThrows) {
952 Function<void(void), NEM> uf2;
953 EXPECT_THROW((uf2 = std::move(uf)), CopyMoveException<MOVE>);
955 Function<void(void), NEM> uf2;
956 EXPECT_NO_THROW((uf2 = std::move(uf)));
959 c.allowMoveOperations = 0;
960 c.allowCopyOperations = 1;
962 if (NEM == FunctionMoveCtor::MAY_THROW && MoveThrows) {
963 Function<void(void), NEM> uf2;
964 EXPECT_THROW((uf2 = std::move(uf)), CopyMoveException<MOVE>);
966 Function<void(void), NEM> uf2;
967 EXPECT_NO_THROW((uf2 = std::move(uf)));
971 TEST(Function, CopyAndMoveThrows_TNN) {
972 copy_and_move_throws_test<FunctionMoveCtor::MAY_THROW, false, false>();
975 TEST(Function, CopyAndMoveThrows_NNN) {
976 copy_and_move_throws_test<FunctionMoveCtor::NO_THROW, false, false>();
979 TEST(Function, CopyAndMoveThrows_TTN) {
980 copy_and_move_throws_test<FunctionMoveCtor::MAY_THROW, true, false>();
983 TEST(Function, CopyAndMoveThrows_NTN) {
984 copy_and_move_throws_test<FunctionMoveCtor::NO_THROW, true, false>();
987 TEST(Function, CopyAndMoveThrows_TNT) {
988 copy_and_move_throws_test<FunctionMoveCtor::MAY_THROW, false, true>();
991 TEST(Function, CopyAndMoveThrows_NNT) {
992 copy_and_move_throws_test<FunctionMoveCtor::NO_THROW, false, true>();
995 TEST(Function, CopyAndMoveThrows_TTT) {
996 copy_and_move_throws_test<FunctionMoveCtor::MAY_THROW, true, true>();
999 TEST(Function, CopyAndMoveThrows_NTT) {
1000 copy_and_move_throws_test<FunctionMoveCtor::NO_THROW, true, true>();
1003 // TEST =====================================================================
1004 // VariadicTemplate & VariadicArguments
1006 struct VariadicTemplateSum {
1007 int operator()() const {
1010 template <class... Args>
1011 int operator()(int x, Args... args) const {
1012 return x + (*this)(args...);
1016 TEST(Function, VariadicTemplate) {
1017 Function<int(int)> uf1 = VariadicTemplateSum();
1018 Function<int(int, int)> uf2 = VariadicTemplateSum();
1019 Function<int(int, int, int)> uf3 = VariadicTemplateSum();
1021 EXPECT_EQ(uf1(66), 66);
1022 EXPECT_EQ(uf2(55, 44), 99);
1023 EXPECT_EQ(uf3(33, 22, 11), 66);
1026 struct VariadicArgumentsSum {
1027 int operator()(int count, ...) const {
1030 va_start(args, count);
1031 for (int i = 0; i < count; ++i) {
1032 result += va_arg(args, int);
1039 TEST(Function, VariadicArguments) {
1040 Function<int(int)> uf1 = VariadicArgumentsSum();
1041 Function<int(int, int)> uf2 = VariadicArgumentsSum();
1042 Function<int(int, int, int)> uf3 = VariadicArgumentsSum();
1044 EXPECT_EQ(uf1(0), 0);
1045 EXPECT_EQ(uf2(1, 66), 66);
1046 EXPECT_EQ(uf3(2, 55, 44), 99);
1049 // TEST =====================================================================
1050 // SafeCaptureByReference
1052 // A function can use Function const& as a parameter to signal that it
1053 // is safe to pass a lambda that captures local variables by reference.
1054 // It is safe because we know the function called can only invoke the
1055 // Function until it returns. It can't store a copy of the Function
1056 // (because it's not copyable), and it can't move the Function somewhere
1057 // else (because it gets only a const&).
1059 template <typename T>
1062 Function<void(typename T::value_type const&) const> const& func) {
1063 for (auto const& elem : range) {
1068 TEST(Function, SafeCaptureByReference) {
1069 std::vector<int> const vec = {20, 30, 40, 2, 3, 4, 200, 300, 400};
1073 // for_each's second parameter is of type Function<...> const&.
1074 // Hence we know we can safely pass it a lambda that references local
1075 // variables. There is no way the reference to x will be stored anywhere.
1076 for_each<std::vector<int>>(vec, [&sum](int x) { sum += x; });
1078 // gcc versions before 4.9 cannot deduce the type T in the above call
1079 // to for_each. Modern compiler versions can compile the following line:
1080 // for_each(vec, [&sum](int x) { sum += x; });
1082 EXPECT_EQ(sum, 999);
1085 // TEST =====================================================================
1086 // IgnoreReturnValue
1088 TEST(Function, IgnoreReturnValue) {
1091 // Assign a lambda that return int to a folly::Function that returns void.
1092 Function<void()> f = [&]() -> int { return ++x; };
1098 Function<int()> g = [&]() -> int { return ++x; };
1099 Function<void()> cg = std::move(g);
1106 // TEST =====================================================================
1107 // ReturnConvertible, ConvertReturnType
1109 TEST(Function, ReturnConvertible) {
1113 struct CDerived : CBase {};
1115 Function<double()> f1 = []() -> int { return 5; };
1116 EXPECT_EQ(f1(), 5.0);
1118 Function<int()> f2 = []() -> double { return 5.2; };
1124 Function<CBase const&()> f3 = [&]() -> CDerived const& { return derived; };
1125 EXPECT_EQ(f3().x, 55);
1127 Function<CBase const&()> f4 = [&]() -> CDerived& { return derived; };
1128 EXPECT_EQ(f4().x, 55);
1130 Function<CBase&()> f5 = [&]() -> CDerived& { return derived; };
1131 EXPECT_EQ(f5().x, 55);
1133 Function<CBase const*()> f6 = [&]() -> CDerived const* { return &derived; };
1134 EXPECT_EQ(f6()->x, 55);
1136 Function<CBase const*()> f7 = [&]() -> CDerived* { return &derived; };
1137 EXPECT_EQ(f7()->x, 55);
1139 Function<CBase*()> f8 = [&]() -> CDerived* { return &derived; };
1140 EXPECT_EQ(f8()->x, 55);
1142 Function<CBase()> f9 = [&]() -> CDerived {
1147 EXPECT_EQ(f9().x, 66);
1150 TEST(Function, ConvertReturnType) {
1154 struct CDerived : CBase {};
1156 Function<int()> f1 = []() -> int { return 5; };
1157 Function<double()> cf1 = std::move(f1);
1158 EXPECT_EQ(cf1(), 5.0);
1159 Function<int()> ccf1 = std::move(cf1);
1160 EXPECT_EQ(ccf1(), 5);
1162 Function<double()> f2 = []() -> double { return 5.2; };
1163 Function<int()> cf2 = std::move(f2);
1164 EXPECT_EQ(cf2(), 5);
1165 Function<double()> ccf2 = std::move(cf2);
1166 EXPECT_EQ(ccf2(), 5.0);
1171 Function<CDerived const&()> f3 = [&]() -> CDerived const& { return derived; };
1172 Function<CBase const&()> cf3 = std::move(f3);
1173 EXPECT_EQ(cf3().x, 55);
1175 Function<CDerived&()> f4 = [&]() -> CDerived& { return derived; };
1176 Function<CBase const&()> cf4 = std::move(f4);
1177 EXPECT_EQ(cf4().x, 55);
1179 Function<CDerived&()> f5 = [&]() -> CDerived& { return derived; };
1180 Function<CBase&()> cf5 = std::move(f5);
1181 EXPECT_EQ(cf5().x, 55);
1183 Function<CDerived const*()> f6 = [&]() -> CDerived const* {
1186 Function<CBase const*()> cf6 = std::move(f6);
1187 EXPECT_EQ(cf6()->x, 55);
1189 Function<CDerived const*()> f7 = [&]() -> CDerived* { return &derived; };
1190 Function<CBase const*()> cf7 = std::move(f7);
1191 EXPECT_EQ(cf7()->x, 55);
1193 Function<CDerived*()> f8 = [&]() -> CDerived* { return &derived; };
1194 Function<CBase*()> cf8 = std::move(f8);
1195 EXPECT_EQ(cf8()->x, 55);
1197 Function<CDerived()> f9 = [&]() -> CDerived {
1202 Function<CBase()> cf9 = std::move(f9);
1203 EXPECT_EQ(cf9().x, 66);