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
24using folly::partial;
25
26int add3(int x, int y, int z) {
27 return 100 * x + 10 * y + z;
28}
29
30TEST(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
44struct 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
56TEST(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
68struct 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
80TEST(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
89struct 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
101TEST(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
110std::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
115TEST(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
137TEST(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
143TEST(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