1 | /* |
2 | * Copyright 2016-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 <memory> |
18 | |
19 | #include <folly/Function.h> |
20 | #include <folly/functional/Partial.h> |
21 | |
22 | #include <folly/portability/GTest.h> |
23 | |
24 | using folly::partial; |
25 | |
26 | int add3(int x, int y, int z) { |
27 | return 100 * x + 10 * y + z; |
28 | } |
29 | |
30 | TEST(Partial, Simple) { |
31 | auto p0 = partial(&add3); |
32 | EXPECT_EQ(123, p0(1, 2, 3)); |
33 | |
34 | auto p1 = partial(&add3, 2); |
35 | EXPECT_EQ(234, p1(3, 4)); |
36 | |
37 | auto p2 = partial(&add3, 3, 4); |
38 | EXPECT_EQ(345, p2(5)); |
39 | |
40 | auto p3 = partial(&add3, 4, 5, 6); |
41 | EXPECT_EQ(456, p3()); |
42 | } |
43 | |
44 | struct Foo { |
45 | int method(int& x, int& y, int& z) { |
46 | return 1000 + 100 * x + 10 * y + z; |
47 | } |
48 | int constMethod(int const& x, int const& y, int const& z) const { |
49 | return 2000 + 100 * x + 10 * y + z; |
50 | } |
51 | int tempMethod(int&& x, int&& y, int&& z) { |
52 | return 3000 + 100 * x + 10 * y + z; |
53 | } |
54 | }; |
55 | |
56 | TEST(Partial, ReferenceArguments) { |
57 | auto p0 = partial(&Foo::method, Foo{}, 2, 3); |
58 | int four = 4; |
59 | EXPECT_EQ(1234, p0(four)); |
60 | |
61 | auto const p1 = partial(&Foo::constMethod, Foo{}, 3, 4); |
62 | EXPECT_EQ(2345, p1(5)); |
63 | |
64 | auto p2 = partial(&Foo::tempMethod, Foo{}, 4, 5); |
65 | EXPECT_EQ(3456, std::move(p2)(6)); |
66 | } |
67 | |
68 | struct RefQualifiers { |
69 | int operator()(int x, int y, int z) & { |
70 | return 1000 + 100 * x + 10 * y + z; |
71 | } |
72 | int operator()(int x, int y, int z) const& { |
73 | return 2000 + 100 * x + 10 * y + z; |
74 | } |
75 | int operator()(int x, int y, int z) && { |
76 | return 3000 + 100 * x + 10 * y + z; |
77 | } |
78 | }; |
79 | |
80 | TEST(Partial, RefQualifiers) { |
81 | auto p = partial(RefQualifiers{}); |
82 | auto const& pconst = p; |
83 | |
84 | EXPECT_EQ(1234, p(2, 3, 4)); |
85 | EXPECT_EQ(2345, pconst(3, 4, 5)); |
86 | EXPECT_EQ(3456, std::move(p)(4, 5, 6)); |
87 | } |
88 | |
89 | struct RefQualifiers2 { |
90 | int operator()(int& x, int const& y, int z) & { |
91 | return 1000 + 100 * x + 10 * y + z; |
92 | } |
93 | int operator()(int const& x, int y, int z) const& { |
94 | return 2000 + 100 * x + 10 * y + z; |
95 | } |
96 | int operator()(int&& x, int const& y, int z) && { |
97 | return 3000 + 100 * x + 10 * y + z; |
98 | } |
99 | }; |
100 | |
101 | TEST(Partial, RefQualifiers2) { |
102 | auto p = partial(RefQualifiers2{}, 9, 8); |
103 | auto const& pconst = p; |
104 | |
105 | EXPECT_EQ(1984, p(4)); |
106 | EXPECT_EQ(2985, pconst(5)); |
107 | EXPECT_EQ(3986, std::move(p)(6)); |
108 | } |
109 | |
110 | std::unique_ptr<int> calc_uptr(std::unique_ptr<int> x, std::unique_ptr<int> y) { |
111 | *x = 100 * *x + 10 * *y; |
112 | return x; |
113 | } |
114 | |
115 | TEST(Partial, MoveOnly) { |
116 | auto five = std::make_unique<int>(5); |
117 | auto six = std::make_unique<int>(6); |
118 | |
119 | // create a partial object which holds a pointer to the `calc_uptr` function |
120 | // and a `unique_ptr<int>` for the first argument |
121 | auto p = partial(&calc_uptr, std::move(five)); |
122 | |
123 | // `five` should be moved out of |
124 | EXPECT_FALSE(five); |
125 | |
126 | // call to the partial object as rvalue, which allows the call to consume |
127 | // captured data (here: the `unique_ptr<int>` storing 5), and pass it |
128 | // the other `unique_ptr` |
129 | auto result = std::move(p)(std::move(six)); |
130 | |
131 | // ...which now should be moved out of |
132 | EXPECT_FALSE(six); |
133 | |
134 | EXPECT_EQ(560, *result); |
135 | } |
136 | |
137 | TEST(Partial, WrapInStdFunction) { |
138 | auto p1 = partial(&add3, 2); |
139 | std::function<int(int, int)> func = p1; |
140 | EXPECT_EQ(234, func(3, 4)); |
141 | } |
142 | |
143 | TEST(Partial, WrapInFollyFunction) { |
144 | auto p1 = partial(&add3, 2); |
145 | folly::Function<int(int, int)> func = p1; |
146 | EXPECT_EQ(234, func(3, 4)); |
147 | } |
148 | |