1 // Copyright 2017 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "absl/base/internal/invoke.h"
16
17 #include <functional>
18 #include <memory>
19 #include <string>
20 #include <utility>
21
22 #include "gmock/gmock.h"
23 #include "gtest/gtest.h"
24 #include "absl/memory/memory.h"
25 #include "absl/strings/str_cat.h"
26
27 namespace absl {
28 ABSL_NAMESPACE_BEGIN
29 namespace base_internal {
30 namespace {
31
Function(int a,int b)32 int Function(int a, int b) { return a - b; }
33
Sink(std::unique_ptr<int> p)34 int Sink(std::unique_ptr<int> p) {
35 return *p;
36 }
37
Factory(int n)38 std::unique_ptr<int> Factory(int n) {
39 return make_unique<int>(n);
40 }
41
NoOp()42 void NoOp() {}
43
44 struct ConstFunctor {
operator ()absl::base_internal::__anonb19a4de20111::ConstFunctor45 int operator()(int a, int b) const { return a - b; }
46 };
47
48 struct MutableFunctor {
operator ()absl::base_internal::__anonb19a4de20111::MutableFunctor49 int operator()(int a, int b) { return a - b; }
50 };
51
52 struct EphemeralFunctor {
operator ()absl::base_internal::__anonb19a4de20111::EphemeralFunctor53 int operator()(int a, int b) && { return a - b; }
54 };
55
56 struct OverloadedFunctor {
57 template <typename... Args>
operator ()absl::base_internal::__anonb19a4de20111::OverloadedFunctor58 std::string operator()(const Args&... args) & {
59 return StrCat("&", args...);
60 }
61 template <typename... Args>
operator ()absl::base_internal::__anonb19a4de20111::OverloadedFunctor62 std::string operator()(const Args&... args) const& {
63 return StrCat("const&", args...);
64 }
65 template <typename... Args>
operator ()absl::base_internal::__anonb19a4de20111::OverloadedFunctor66 std::string operator()(const Args&... args) && {
67 return StrCat("&&", args...);
68 }
69 };
70
71 struct Class {
Methodabsl::base_internal::__anonb19a4de20111::Class72 int Method(int a, int b) { return a - b; }
ConstMethodabsl::base_internal::__anonb19a4de20111::Class73 int ConstMethod(int a, int b) const { return a - b; }
RefMethodabsl::base_internal::__anonb19a4de20111::Class74 int RefMethod(int a, int b) & { return a - b; }
RefRefMethodabsl::base_internal::__anonb19a4de20111::Class75 int RefRefMethod(int a, int b) && { return a - b; }
NoExceptMethodabsl::base_internal::__anonb19a4de20111::Class76 int NoExceptMethod(int a, int b) noexcept { return a - b; }
VolatileMethodabsl::base_internal::__anonb19a4de20111::Class77 int VolatileMethod(int a, int b) volatile { return a - b; }
78
79 int member;
80 };
81
82 struct FlipFlop {
ConstMethodabsl::base_internal::__anonb19a4de20111::FlipFlop83 int ConstMethod() const { return member; }
operator *absl::base_internal::__anonb19a4de20111::FlipFlop84 FlipFlop operator*() const { return {-member}; }
85
86 int member;
87 };
88
89 // CallMaybeWithArg(f) resolves either to Invoke(f) or Invoke(f, 42), depending
90 // on which one is valid.
91 template <typename F>
Invoke(std::declval<const F &> ())92 decltype(Invoke(std::declval<const F&>())) CallMaybeWithArg(const F& f) {
93 return Invoke(f);
94 }
95
96 template <typename F>
CallMaybeWithArg(const F & f)97 decltype(Invoke(std::declval<const F&>(), 42)) CallMaybeWithArg(const F& f) {
98 return Invoke(f, 42);
99 }
100
TEST(InvokeTest,Function)101 TEST(InvokeTest, Function) {
102 EXPECT_EQ(1, Invoke(Function, 3, 2));
103 EXPECT_EQ(1, Invoke(&Function, 3, 2));
104 }
105
TEST(InvokeTest,NonCopyableArgument)106 TEST(InvokeTest, NonCopyableArgument) {
107 EXPECT_EQ(42, Invoke(Sink, make_unique<int>(42)));
108 }
109
TEST(InvokeTest,NonCopyableResult)110 TEST(InvokeTest, NonCopyableResult) {
111 EXPECT_THAT(Invoke(Factory, 42), ::testing::Pointee(42));
112 }
113
TEST(InvokeTest,VoidResult)114 TEST(InvokeTest, VoidResult) {
115 Invoke(NoOp);
116 }
117
TEST(InvokeTest,ConstFunctor)118 TEST(InvokeTest, ConstFunctor) {
119 EXPECT_EQ(1, Invoke(ConstFunctor(), 3, 2));
120 }
121
TEST(InvokeTest,MutableFunctor)122 TEST(InvokeTest, MutableFunctor) {
123 MutableFunctor f;
124 EXPECT_EQ(1, Invoke(f, 3, 2));
125 EXPECT_EQ(1, Invoke(MutableFunctor(), 3, 2));
126 }
127
TEST(InvokeTest,EphemeralFunctor)128 TEST(InvokeTest, EphemeralFunctor) {
129 EphemeralFunctor f;
130 EXPECT_EQ(1, Invoke(std::move(f), 3, 2));
131 EXPECT_EQ(1, Invoke(EphemeralFunctor(), 3, 2));
132 }
133
TEST(InvokeTest,OverloadedFunctor)134 TEST(InvokeTest, OverloadedFunctor) {
135 OverloadedFunctor f;
136 const OverloadedFunctor& cf = f;
137
138 EXPECT_EQ("&", Invoke(f));
139 EXPECT_EQ("& 42", Invoke(f, " 42"));
140
141 EXPECT_EQ("const&", Invoke(cf));
142 EXPECT_EQ("const& 42", Invoke(cf, " 42"));
143
144 EXPECT_EQ("&&", Invoke(std::move(f)));
145 EXPECT_EQ("&& 42", Invoke(std::move(f), " 42"));
146 }
147
TEST(InvokeTest,ReferenceWrapper)148 TEST(InvokeTest, ReferenceWrapper) {
149 ConstFunctor cf;
150 MutableFunctor mf;
151 EXPECT_EQ(1, Invoke(std::cref(cf), 3, 2));
152 EXPECT_EQ(1, Invoke(std::ref(cf), 3, 2));
153 EXPECT_EQ(1, Invoke(std::ref(mf), 3, 2));
154 }
155
TEST(InvokeTest,MemberFunction)156 TEST(InvokeTest, MemberFunction) {
157 std::unique_ptr<Class> p(new Class);
158 std::unique_ptr<const Class> cp(new Class);
159 std::unique_ptr<volatile Class> vp(new Class);
160
161 EXPECT_EQ(1, Invoke(&Class::Method, p, 3, 2));
162 EXPECT_EQ(1, Invoke(&Class::Method, p.get(), 3, 2));
163 EXPECT_EQ(1, Invoke(&Class::Method, *p, 3, 2));
164 EXPECT_EQ(1, Invoke(&Class::RefMethod, p, 3, 2));
165 EXPECT_EQ(1, Invoke(&Class::RefMethod, p.get(), 3, 2));
166 EXPECT_EQ(1, Invoke(&Class::RefMethod, *p, 3, 2));
167 EXPECT_EQ(1, Invoke(&Class::RefRefMethod, std::move(*p), 3, 2)); // NOLINT
168 EXPECT_EQ(1, Invoke(&Class::NoExceptMethod, p, 3, 2));
169 EXPECT_EQ(1, Invoke(&Class::NoExceptMethod, p.get(), 3, 2));
170 EXPECT_EQ(1, Invoke(&Class::NoExceptMethod, *p, 3, 2));
171
172 EXPECT_EQ(1, Invoke(&Class::ConstMethod, p, 3, 2));
173 EXPECT_EQ(1, Invoke(&Class::ConstMethod, p.get(), 3, 2));
174 EXPECT_EQ(1, Invoke(&Class::ConstMethod, *p, 3, 2));
175
176 EXPECT_EQ(1, Invoke(&Class::ConstMethod, cp, 3, 2));
177 EXPECT_EQ(1, Invoke(&Class::ConstMethod, cp.get(), 3, 2));
178 EXPECT_EQ(1, Invoke(&Class::ConstMethod, *cp, 3, 2));
179
180 EXPECT_EQ(1, Invoke(&Class::VolatileMethod, p, 3, 2));
181 EXPECT_EQ(1, Invoke(&Class::VolatileMethod, p.get(), 3, 2));
182 EXPECT_EQ(1, Invoke(&Class::VolatileMethod, *p, 3, 2));
183 EXPECT_EQ(1, Invoke(&Class::VolatileMethod, vp, 3, 2));
184 EXPECT_EQ(1, Invoke(&Class::VolatileMethod, vp.get(), 3, 2));
185 EXPECT_EQ(1, Invoke(&Class::VolatileMethod, *vp, 3, 2));
186
187 EXPECT_EQ(1, Invoke(&Class::Method, make_unique<Class>(), 3, 2));
188 EXPECT_EQ(1, Invoke(&Class::ConstMethod, make_unique<Class>(), 3, 2));
189 EXPECT_EQ(1, Invoke(&Class::ConstMethod, make_unique<const Class>(), 3, 2));
190 }
191
TEST(InvokeTest,DataMember)192 TEST(InvokeTest, DataMember) {
193 std::unique_ptr<Class> p(new Class{42});
194 std::unique_ptr<const Class> cp(new Class{42});
195 EXPECT_EQ(42, Invoke(&Class::member, p));
196 EXPECT_EQ(42, Invoke(&Class::member, *p));
197 EXPECT_EQ(42, Invoke(&Class::member, p.get()));
198
199 Invoke(&Class::member, p) = 42;
200 Invoke(&Class::member, p.get()) = 42;
201
202 EXPECT_EQ(42, Invoke(&Class::member, cp));
203 EXPECT_EQ(42, Invoke(&Class::member, *cp));
204 EXPECT_EQ(42, Invoke(&Class::member, cp.get()));
205 }
206
TEST(InvokeTest,FlipFlop)207 TEST(InvokeTest, FlipFlop) {
208 FlipFlop obj = {42};
209 // This call could resolve to (obj.*&FlipFlop::ConstMethod)() or
210 // ((*obj).*&FlipFlop::ConstMethod)(). We verify that it's the former.
211 EXPECT_EQ(42, Invoke(&FlipFlop::ConstMethod, obj));
212 EXPECT_EQ(42, Invoke(&FlipFlop::member, obj));
213 }
214
TEST(InvokeTest,SfinaeFriendly)215 TEST(InvokeTest, SfinaeFriendly) {
216 CallMaybeWithArg(NoOp);
217 EXPECT_THAT(CallMaybeWithArg(Factory), ::testing::Pointee(42));
218 }
219
220 } // namespace
221 } // namespace base_internal
222 ABSL_NAMESPACE_END
223 } // namespace absl
224