1 // Copyright 2022 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/functional/function_ref.h"
6
7 #include <stdint.h>
8
9 #include <concepts>
10 #include <optional>
11
12 #include "base/compiler_specific.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 #include "third_party/abseil-cpp/absl/functional/function_ref.h"
15
16 namespace base {
17
18 namespace {
19
Func(float)20 char Func(float) {
21 return 'a';
22 }
23
24 } // namespace
25
TEST(FunctionRef,Lambda)26 TEST(FunctionRef, Lambda) {
27 auto add = [](int a, int b) { return a + b; };
28
29 {
30 const FunctionRef<int(int, int)> ref = add;
31 EXPECT_EQ(19, ref(17, 2));
32 }
33
34 {
35 const auto add_const = add;
36 const FunctionRef<int(int, int)> ref = add_const;
37 EXPECT_EQ(19, ref(17, 2));
38 }
39 }
40
TEST(FunctionRef,CapturingLambda)41 TEST(FunctionRef, CapturingLambda) {
42 int x = 3;
43 const auto lambda = [&x] { return x; };
44 FunctionRef<int()> ref = lambda;
45 EXPECT_EQ(3, ref());
46 }
47
TEST(FunctionRef,FunctionPtr)48 TEST(FunctionRef, FunctionPtr) {
49 [](FunctionRef<char(float)> ref) { EXPECT_EQ('a', ref(1.0)); }(&Func);
50 const FunctionRef<char(float)> ref = +[](float) { return 'a'; };
51 EXPECT_EQ('a', ref(1.0f));
52 }
53
TEST(FunctionRef,Functor)54 TEST(FunctionRef, Functor) {
55 struct S {
56 int operator()(int x) const { return x; }
57 };
58 const S s;
59 const FunctionRef<int(int)> ref = s;
60 EXPECT_EQ(17, ref(17));
61 }
62
TEST(FunctionRef,Method)63 TEST(FunctionRef, Method) {
64 struct S {
65 int Method() const { return value; }
66
67 const int value;
68 };
69 const S s(25);
70 [&s](FunctionRef<int(const S*)> ref) { EXPECT_EQ(25, ref(&s)); }(&S::Method);
71 }
72
73 // If we construct from another `FunctionRef`, that should work fine, even if
74 // the input is destroyed before we call the output. In other words, we should
75 // reference the underlying callable, not the `FunctionRef`.
76 //
77 // We construct in a `noinline` function to maximize the chance that ASAN
78 // notices the use-after-free if we get this wrong.
ConstructFromLValue(std::optional<FunctionRef<int ()>> & ref)79 NOINLINE void ConstructFromLValue(std::optional<FunctionRef<int()>>& ref) {
80 const auto return_17 = [] { return 17; };
81 FunctionRef<int()> other = return_17;
82 ref.emplace(other);
83 }
ConstructFromConstLValue(std::optional<FunctionRef<int ()>> & ref)84 NOINLINE void ConstructFromConstLValue(std::optional<FunctionRef<int()>>& ref) {
85 const auto return_17 = [] { return 17; };
86 const FunctionRef<int()> other = return_17;
87 ref.emplace(other);
88 }
ConstructFromRValue(std::optional<FunctionRef<int ()>> & ref)89 NOINLINE void ConstructFromRValue(std::optional<FunctionRef<int()>>& ref) {
90 const auto return_17 = [] { return 17; };
91 using Ref = FunctionRef<int()>;
92 ref.emplace(Ref(return_17));
93 }
ConstructFromConstRValue(std::optional<FunctionRef<int ()>> & ref)94 NOINLINE void ConstructFromConstRValue(std::optional<FunctionRef<int()>>& ref) {
95 const auto return_17 = [] { return 17; };
96 using Ref = const FunctionRef<int()>;
97 ref.emplace(Ref(return_17));
98 }
TEST(FunctionRef,ConstructionFromOtherFunctionRefObjects)99 TEST(FunctionRef, ConstructionFromOtherFunctionRefObjects) {
100 using Ref = FunctionRef<int()>;
101 std::optional<Ref> ref;
102
103 ConstructFromLValue(ref);
104 EXPECT_EQ(17, (*ref)());
105
106 ConstructFromConstLValue(ref);
107 EXPECT_EQ(17, (*ref)());
108
109 ConstructFromRValue(ref);
110 EXPECT_EQ(17, (*ref)());
111
112 ConstructFromConstRValue(ref);
113 EXPECT_EQ(17, (*ref)());
114
115 // It shouldn't be possible to construct from `FunctionRef` objects with
116 // differing signatures, even if they are compatible with `int()`.
117 static_assert(!std::constructible_from<Ref, FunctionRef<void()>>);
118 static_assert(!std::constructible_from<Ref, FunctionRef<int(int)>>);
119 static_assert(!std::constructible_from<Ref, FunctionRef<int64_t()>>);
120
121 // Check again with various qualifiers.
122 static_assert(!std::constructible_from<Ref, const FunctionRef<void()>>);
123 static_assert(!std::constructible_from<Ref, FunctionRef<void()>&>);
124 static_assert(!std::constructible_from<Ref, FunctionRef<void()>&&>);
125 static_assert(!std::constructible_from<Ref, const FunctionRef<void()>&>);
126 static_assert(!std::constructible_from<Ref, const FunctionRef<void()>&&>);
127 }
128
129 // `FunctionRef` allows functors with convertible return types to be adapted.
TEST(FunctionRef,ConvertibleReturnTypes)130 TEST(FunctionRef, ConvertibleReturnTypes) {
131 {
132 const auto lambda = [] { return true; };
133 const FunctionRef<int()> ref = lambda;
134 EXPECT_EQ(1, ref());
135 }
136
137 {
138 class Base {};
139 class Derived : public Base {};
140
141 const auto lambda = []() -> Derived* { return nullptr; };
142 const FunctionRef<const Base*()> ref = lambda;
143 EXPECT_EQ(nullptr, ref());
144 }
145 }
146
TEST(FunctionRef,ConstructionFromInexactMatches)147 TEST(FunctionRef, ConstructionFromInexactMatches) {
148 // Lambda.
149 const auto lambda = [](int32_t x) { return x; };
150
151 // Capturing lambda.
152 const auto capturing_lambda = [&](int32_t x) { return lambda(x); };
153
154 // Function pointer.
155 int32_t (*const function_ptr)(int32_t) = +lambda;
156
157 // Functor.
158 struct Functor {
159 int32_t operator()(int32_t x) const { return x; }
160 };
161 const Functor functor;
162
163 // Method.
164 struct Obj {
165 int32_t Method(int32_t x) const { return x; }
166 };
167 int32_t (Obj::*const method)(int32_t) const = &Obj::Method;
168
169 // Each of the objects above should work for a `FunctionRef` with a
170 // convertible return type. In this case, they all return `int32_t`, which
171 // should be seamlessly convertible to `int64_t` below.
172 static_assert(
173 std::constructible_from<FunctionRef<int64_t(int32_t)>, decltype(lambda)>);
174 static_assert(std::constructible_from<FunctionRef<int64_t(int32_t)>,
175 decltype(capturing_lambda)>);
176 static_assert(std::constructible_from<FunctionRef<int64_t(int32_t)>,
177 decltype(function_ptr)>);
178 static_assert(std::constructible_from<FunctionRef<int64_t(int32_t)>,
179 decltype(functor)>);
180 static_assert(
181 std::constructible_from<FunctionRef<int64_t(const Obj*, int32_t)>,
182 decltype(method)>);
183
184 // It shouldn't be possible to construct a `FunctionRef` from any of the
185 // objects above if we discard the return value.
186 static_assert(
187 !std::constructible_from<FunctionRef<void(int32_t)>, decltype(lambda)>);
188 static_assert(!std::constructible_from<FunctionRef<void(int32_t)>,
189 decltype(capturing_lambda)>);
190 static_assert(!std::constructible_from<FunctionRef<void(int32_t)>,
191 decltype(function_ptr)>);
192 static_assert(
193 !std::constructible_from<FunctionRef<void(int32_t)>, decltype(functor)>);
194 static_assert(!std::constructible_from<FunctionRef<void(const Obj*, int32_t)>,
195 decltype(method)>);
196
197 // It shouldn't be possible to construct a `FunctionRef` from a pointer to a
198 // functor, even with a compatible signature.
199 static_assert(!std::constructible_from<FunctionRef<int32_t(int32_t)>,
200 decltype(&functor)>);
201 }
202
TEST(FunctionRef,ConstructionFromAbslFunctionRef)203 TEST(FunctionRef, ConstructionFromAbslFunctionRef) {
204 // It shouldn't be possible to construct a `FunctionRef` from an
205 // `absl::FunctionRef`, whether the signatures are compatible or not.
206 using Ref = FunctionRef<int(int)>;
207 static_assert(!std::is_constructible_v<Ref, absl::FunctionRef<void()>>);
208 static_assert(!std::is_constructible_v<Ref, absl::FunctionRef<void(int)>>);
209 static_assert(!std::is_constructible_v<Ref, absl::FunctionRef<int(int)>>);
210
211 // Check again with various qualifiers.
212 using AbslRef = absl::FunctionRef<int(int)>;
213 static_assert(!std::is_constructible_v<Ref, const AbslRef>);
214 static_assert(!std::is_constructible_v<Ref, AbslRef&>);
215 static_assert(!std::is_constructible_v<Ref, AbslRef&&>);
216 static_assert(!std::is_constructible_v<Ref, const AbslRef&>);
217 static_assert(!std::is_constructible_v<Ref, const AbslRef&&>);
218 }
219
220 } // namespace base
221