1*38e8c45fSAndroid Build Coastguard Worker /*
2*38e8c45fSAndroid Build Coastguard Worker * Copyright 2022 The Android Open Source Project
3*38e8c45fSAndroid Build Coastguard Worker *
4*38e8c45fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*38e8c45fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*38e8c45fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*38e8c45fSAndroid Build Coastguard Worker *
8*38e8c45fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*38e8c45fSAndroid Build Coastguard Worker *
10*38e8c45fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*38e8c45fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*38e8c45fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*38e8c45fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*38e8c45fSAndroid Build Coastguard Worker * limitations under the License.
15*38e8c45fSAndroid Build Coastguard Worker */
16*38e8c45fSAndroid Build Coastguard Worker
17*38e8c45fSAndroid Build Coastguard Worker #include <ftl/function.h>
18*38e8c45fSAndroid Build Coastguard Worker #include <gtest/gtest.h>
19*38e8c45fSAndroid Build Coastguard Worker
20*38e8c45fSAndroid Build Coastguard Worker #include <array>
21*38e8c45fSAndroid Build Coastguard Worker #include <cstddef>
22*38e8c45fSAndroid Build Coastguard Worker #include <cstdint>
23*38e8c45fSAndroid Build Coastguard Worker #include <string_view>
24*38e8c45fSAndroid Build Coastguard Worker #include <type_traits>
25*38e8c45fSAndroid Build Coastguard Worker
26*38e8c45fSAndroid Build Coastguard Worker namespace android::test {
27*38e8c45fSAndroid Build Coastguard Worker namespace {
28*38e8c45fSAndroid Build Coastguard Worker
29*38e8c45fSAndroid Build Coastguard Worker // Create an alias to composite requirements defined by the trait class `T` for easier testing.
30*38e8c45fSAndroid Build Coastguard Worker template <typename T, typename S>
31*38e8c45fSAndroid Build Coastguard Worker inline constexpr bool is_opaquely_storable = (T::template require_trivially_copyable<S> &&
32*38e8c45fSAndroid Build Coastguard Worker T::template require_trivially_destructible<S> &&
33*38e8c45fSAndroid Build Coastguard Worker T::template require_will_fit_in_opaque_storage<S> &&
34*38e8c45fSAndroid Build Coastguard Worker T::template require_alignment_compatible<S>);
35*38e8c45fSAndroid Build Coastguard Worker
36*38e8c45fSAndroid Build Coastguard Worker // `I` gives a count of sizeof(std::intptr_t) bytes , and `J` gives a raw count of bytes
37*38e8c45fSAndroid Build Coastguard Worker template <size_t I, size_t J = 0>
38*38e8c45fSAndroid Build Coastguard Worker struct KnownSizeFunctionObject {
39*38e8c45fSAndroid Build Coastguard Worker using Data = std::array<std::byte, sizeof(std::intptr_t) * I + J>;
operator ()android::test::__anon5a430b1f0111::KnownSizeFunctionObject40*38e8c45fSAndroid Build Coastguard Worker void operator()() const {};
41*38e8c45fSAndroid Build Coastguard Worker Data data{};
42*38e8c45fSAndroid Build Coastguard Worker };
43*38e8c45fSAndroid Build Coastguard Worker
44*38e8c45fSAndroid Build Coastguard Worker } // namespace
45*38e8c45fSAndroid Build Coastguard Worker
46*38e8c45fSAndroid Build Coastguard Worker // static_assert the expected type traits
47*38e8c45fSAndroid Build Coastguard Worker static_assert(std::is_invocable_r_v<void, ftl::Function<void()>>);
48*38e8c45fSAndroid Build Coastguard Worker static_assert(std::is_trivially_copyable_v<ftl::Function<void()>>);
49*38e8c45fSAndroid Build Coastguard Worker static_assert(std::is_trivially_destructible_v<ftl::Function<void()>>);
50*38e8c45fSAndroid Build Coastguard Worker static_assert(std::is_trivially_copy_constructible_v<ftl::Function<void()>>);
51*38e8c45fSAndroid Build Coastguard Worker static_assert(std::is_trivially_move_constructible_v<ftl::Function<void()>>);
52*38e8c45fSAndroid Build Coastguard Worker static_assert(std::is_trivially_copy_assignable_v<ftl::Function<void()>>);
53*38e8c45fSAndroid Build Coastguard Worker static_assert(std::is_trivially_move_assignable_v<ftl::Function<void()>>);
54*38e8c45fSAndroid Build Coastguard Worker
55*38e8c45fSAndroid Build Coastguard Worker template <typename T>
56*38e8c45fSAndroid Build Coastguard Worker using function_traits = ftl::details::function_traits<T>;
57*38e8c45fSAndroid Build Coastguard Worker
58*38e8c45fSAndroid Build Coastguard Worker // static_assert that the expected value of N is used for known function object sizes.
59*38e8c45fSAndroid Build Coastguard Worker static_assert(function_traits<KnownSizeFunctionObject<0, 0>>::size == 0);
60*38e8c45fSAndroid Build Coastguard Worker static_assert(function_traits<KnownSizeFunctionObject<0, 1>>::size == 0);
61*38e8c45fSAndroid Build Coastguard Worker static_assert(function_traits<KnownSizeFunctionObject<1, 0>>::size == 0);
62*38e8c45fSAndroid Build Coastguard Worker static_assert(function_traits<KnownSizeFunctionObject<1, 1>>::size == 1);
63*38e8c45fSAndroid Build Coastguard Worker static_assert(function_traits<KnownSizeFunctionObject<2, 0>>::size == 1);
64*38e8c45fSAndroid Build Coastguard Worker static_assert(function_traits<KnownSizeFunctionObject<2, 1>>::size == 2);
65*38e8c45fSAndroid Build Coastguard Worker
66*38e8c45fSAndroid Build Coastguard Worker // Check that is_function_v works
67*38e8c45fSAndroid Build Coastguard Worker static_assert(!ftl::is_function_v<KnownSizeFunctionObject<0>>);
68*38e8c45fSAndroid Build Coastguard Worker static_assert(!ftl::is_function_v<std::function<void()>>);
69*38e8c45fSAndroid Build Coastguard Worker static_assert(ftl::is_function_v<ftl::Function<void()>>);
70*38e8c45fSAndroid Build Coastguard Worker
71*38e8c45fSAndroid Build Coastguard Worker // static_assert what can and cannot be stored inside the opaque storage
72*38e8c45fSAndroid Build Coastguard Worker
73*38e8c45fSAndroid Build Coastguard Worker template <size_t N>
74*38e8c45fSAndroid Build Coastguard Worker using function_opaque_storage = ftl::details::function_opaque_storage<N>;
75*38e8c45fSAndroid Build Coastguard Worker
76*38e8c45fSAndroid Build Coastguard Worker // Function objects can be stored if they fit.
77*38e8c45fSAndroid Build Coastguard Worker static_assert(is_opaquely_storable<function_opaque_storage<0>, KnownSizeFunctionObject<0>>);
78*38e8c45fSAndroid Build Coastguard Worker static_assert(is_opaquely_storable<function_opaque_storage<0>, KnownSizeFunctionObject<1>>);
79*38e8c45fSAndroid Build Coastguard Worker static_assert(!is_opaquely_storable<function_opaque_storage<0>, KnownSizeFunctionObject<2>>);
80*38e8c45fSAndroid Build Coastguard Worker
81*38e8c45fSAndroid Build Coastguard Worker static_assert(is_opaquely_storable<function_opaque_storage<1>, KnownSizeFunctionObject<2>>);
82*38e8c45fSAndroid Build Coastguard Worker static_assert(!is_opaquely_storable<function_opaque_storage<1>, KnownSizeFunctionObject<3>>);
83*38e8c45fSAndroid Build Coastguard Worker
84*38e8c45fSAndroid Build Coastguard Worker static_assert(is_opaquely_storable<function_opaque_storage<2>, KnownSizeFunctionObject<3>>);
85*38e8c45fSAndroid Build Coastguard Worker static_assert(!is_opaquely_storable<function_opaque_storage<2>, KnownSizeFunctionObject<4>>);
86*38e8c45fSAndroid Build Coastguard Worker
87*38e8c45fSAndroid Build Coastguard Worker // Another opaque storage can be stored if it fits. This property is used to copy smaller
88*38e8c45fSAndroid Build Coastguard Worker // ftl::Functions into larger ones.
89*38e8c45fSAndroid Build Coastguard Worker static_assert(is_opaquely_storable<function_opaque_storage<2>, function_opaque_storage<0>::type>);
90*38e8c45fSAndroid Build Coastguard Worker static_assert(is_opaquely_storable<function_opaque_storage<2>, function_opaque_storage<1>::type>);
91*38e8c45fSAndroid Build Coastguard Worker static_assert(is_opaquely_storable<function_opaque_storage<2>, function_opaque_storage<2>::type>);
92*38e8c45fSAndroid Build Coastguard Worker static_assert(!is_opaquely_storable<function_opaque_storage<2>, function_opaque_storage<3>::type>);
93*38e8c45fSAndroid Build Coastguard Worker
94*38e8c45fSAndroid Build Coastguard Worker // Function objects that aren't trivially copyable or destroyable cannot be stored.
__anon5a430b1f0202null95*38e8c45fSAndroid Build Coastguard Worker auto lambda_capturing_unique_ptr = [ptr = std::unique_ptr<void*>()] { static_cast<void>(ptr); };
96*38e8c45fSAndroid Build Coastguard Worker static_assert(
97*38e8c45fSAndroid Build Coastguard Worker !is_opaquely_storable<function_opaque_storage<2>, decltype(lambda_capturing_unique_ptr)>);
98*38e8c45fSAndroid Build Coastguard Worker
99*38e8c45fSAndroid Build Coastguard Worker // Keep in sync with "Example usage" in header file.
TEST(Function,Example)100*38e8c45fSAndroid Build Coastguard Worker TEST(Function, Example) {
101*38e8c45fSAndroid Build Coastguard Worker using namespace std::string_view_literals;
102*38e8c45fSAndroid Build Coastguard Worker
103*38e8c45fSAndroid Build Coastguard Worker class MyClass {
104*38e8c45fSAndroid Build Coastguard Worker public:
105*38e8c45fSAndroid Build Coastguard Worker void on_event() const {}
106*38e8c45fSAndroid Build Coastguard Worker int on_string(int*, std::string_view) { return 1; }
107*38e8c45fSAndroid Build Coastguard Worker
108*38e8c45fSAndroid Build Coastguard Worker auto get_function() {
109*38e8c45fSAndroid Build Coastguard Worker return ftl::make_function([this] { on_event(); });
110*38e8c45fSAndroid Build Coastguard Worker }
111*38e8c45fSAndroid Build Coastguard Worker } cls;
112*38e8c45fSAndroid Build Coastguard Worker
113*38e8c45fSAndroid Build Coastguard Worker // A function container with no arguments, and returning no value.
114*38e8c45fSAndroid Build Coastguard Worker ftl::Function<void()> f;
115*38e8c45fSAndroid Build Coastguard Worker
116*38e8c45fSAndroid Build Coastguard Worker // Construct a ftl::Function containing a small lambda.
117*38e8c45fSAndroid Build Coastguard Worker f = cls.get_function();
118*38e8c45fSAndroid Build Coastguard Worker
119*38e8c45fSAndroid Build Coastguard Worker // Construct a ftl::Function that calls `cls.on_event()`.
120*38e8c45fSAndroid Build Coastguard Worker f = ftl::make_function<&MyClass::on_event>(&cls);
121*38e8c45fSAndroid Build Coastguard Worker
122*38e8c45fSAndroid Build Coastguard Worker // Create a do-nothing function.
123*38e8c45fSAndroid Build Coastguard Worker f = ftl::no_op;
124*38e8c45fSAndroid Build Coastguard Worker
125*38e8c45fSAndroid Build Coastguard Worker // Invoke the contained function.
126*38e8c45fSAndroid Build Coastguard Worker f();
127*38e8c45fSAndroid Build Coastguard Worker
128*38e8c45fSAndroid Build Coastguard Worker // Also invokes it.
129*38e8c45fSAndroid Build Coastguard Worker std::invoke(f);
130*38e8c45fSAndroid Build Coastguard Worker
131*38e8c45fSAndroid Build Coastguard Worker // Create a typedef to give a more meaningful name and bound the size.
132*38e8c45fSAndroid Build Coastguard Worker using MyFunction = ftl::Function<int(std::string_view), 2>;
133*38e8c45fSAndroid Build Coastguard Worker int* ptr = nullptr;
134*38e8c45fSAndroid Build Coastguard Worker auto f1 =
135*38e8c45fSAndroid Build Coastguard Worker MyFunction::make([cls = &cls, ptr](std::string_view sv) { return cls->on_string(ptr, sv); });
136*38e8c45fSAndroid Build Coastguard Worker int r = f1("abc"sv);
137*38e8c45fSAndroid Build Coastguard Worker
138*38e8c45fSAndroid Build Coastguard Worker // Returns a default-constructed int (0).
139*38e8c45fSAndroid Build Coastguard Worker f1 = ftl::no_op;
140*38e8c45fSAndroid Build Coastguard Worker r = f1("abc"sv);
141*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(r, 0);
142*38e8c45fSAndroid Build Coastguard Worker }
143*38e8c45fSAndroid Build Coastguard Worker
TEST(Function,BasicOperations)144*38e8c45fSAndroid Build Coastguard Worker TEST(Function, BasicOperations) {
145*38e8c45fSAndroid Build Coastguard Worker // Default constructible.
146*38e8c45fSAndroid Build Coastguard Worker ftl::Function<int()> f;
147*38e8c45fSAndroid Build Coastguard Worker
148*38e8c45fSAndroid Build Coastguard Worker // Compares as empty
149*38e8c45fSAndroid Build Coastguard Worker EXPECT_FALSE(f);
150*38e8c45fSAndroid Build Coastguard Worker EXPECT_TRUE(f == nullptr);
151*38e8c45fSAndroid Build Coastguard Worker EXPECT_FALSE(f != nullptr);
152*38e8c45fSAndroid Build Coastguard Worker EXPECT_TRUE(ftl::Function<int()>() == f);
153*38e8c45fSAndroid Build Coastguard Worker EXPECT_FALSE(ftl::Function<int()>() != f);
154*38e8c45fSAndroid Build Coastguard Worker
155*38e8c45fSAndroid Build Coastguard Worker // Assigning no_op sets it to not empty.
156*38e8c45fSAndroid Build Coastguard Worker f = ftl::no_op;
157*38e8c45fSAndroid Build Coastguard Worker
158*38e8c45fSAndroid Build Coastguard Worker // Verify it can be called, and that it returns a default constructed value.
159*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(f(), 0);
160*38e8c45fSAndroid Build Coastguard Worker
161*38e8c45fSAndroid Build Coastguard Worker // Comparable when non-empty.
162*38e8c45fSAndroid Build Coastguard Worker EXPECT_TRUE(f);
163*38e8c45fSAndroid Build Coastguard Worker EXPECT_FALSE(f == nullptr);
164*38e8c45fSAndroid Build Coastguard Worker EXPECT_TRUE(f != nullptr);
165*38e8c45fSAndroid Build Coastguard Worker EXPECT_FALSE(ftl::Function<int()>() == f);
166*38e8c45fSAndroid Build Coastguard Worker EXPECT_TRUE(ftl::Function<int()>() != f);
167*38e8c45fSAndroid Build Coastguard Worker
168*38e8c45fSAndroid Build Coastguard Worker // Constructing from nullptr means empty.
169*38e8c45fSAndroid Build Coastguard Worker f = ftl::Function<int()>{nullptr};
170*38e8c45fSAndroid Build Coastguard Worker EXPECT_FALSE(f);
171*38e8c45fSAndroid Build Coastguard Worker
172*38e8c45fSAndroid Build Coastguard Worker // Assigning nullptr means it is empty.
173*38e8c45fSAndroid Build Coastguard Worker f = nullptr;
174*38e8c45fSAndroid Build Coastguard Worker EXPECT_FALSE(f);
175*38e8c45fSAndroid Build Coastguard Worker
176*38e8c45fSAndroid Build Coastguard Worker // Move construction
177*38e8c45fSAndroid Build Coastguard Worker f = ftl::no_op;
178*38e8c45fSAndroid Build Coastguard Worker ftl::Function<int()> g{std::move(f)};
179*38e8c45fSAndroid Build Coastguard Worker EXPECT_TRUE(g != nullptr);
180*38e8c45fSAndroid Build Coastguard Worker
181*38e8c45fSAndroid Build Coastguard Worker // Move assignment
182*38e8c45fSAndroid Build Coastguard Worker f = nullptr;
183*38e8c45fSAndroid Build Coastguard Worker f = std::move(g);
184*38e8c45fSAndroid Build Coastguard Worker EXPECT_TRUE(f != nullptr);
185*38e8c45fSAndroid Build Coastguard Worker
186*38e8c45fSAndroid Build Coastguard Worker // Copy construction
187*38e8c45fSAndroid Build Coastguard Worker ftl::Function<int()> h{f};
188*38e8c45fSAndroid Build Coastguard Worker EXPECT_TRUE(h != nullptr);
189*38e8c45fSAndroid Build Coastguard Worker
190*38e8c45fSAndroid Build Coastguard Worker // Copy assignment
191*38e8c45fSAndroid Build Coastguard Worker g = h;
192*38e8c45fSAndroid Build Coastguard Worker EXPECT_TRUE(g != nullptr);
193*38e8c45fSAndroid Build Coastguard Worker }
194*38e8c45fSAndroid Build Coastguard Worker
TEST(Function,CanMoveConstructFromLambda)195*38e8c45fSAndroid Build Coastguard Worker TEST(Function, CanMoveConstructFromLambda) {
196*38e8c45fSAndroid Build Coastguard Worker auto lambda = [] {};
197*38e8c45fSAndroid Build Coastguard Worker ftl::Function<void()> f{std::move(lambda)};
198*38e8c45fSAndroid Build Coastguard Worker }
199*38e8c45fSAndroid Build Coastguard Worker
TEST(Function,TerseDeducedConstructAndAssignFromLambda)200*38e8c45fSAndroid Build Coastguard Worker TEST(Function, TerseDeducedConstructAndAssignFromLambda) {
201*38e8c45fSAndroid Build Coastguard Worker auto f = ftl::Function([] { return 1; });
202*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(f(), 1);
203*38e8c45fSAndroid Build Coastguard Worker
204*38e8c45fSAndroid Build Coastguard Worker f = [] { return 2; };
205*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(f(), 2);
206*38e8c45fSAndroid Build Coastguard Worker }
207*38e8c45fSAndroid Build Coastguard Worker
208*38e8c45fSAndroid Build Coastguard Worker namespace {
209*38e8c45fSAndroid Build Coastguard Worker
210*38e8c45fSAndroid Build Coastguard Worker struct ImplicitConversionsHelper {
exactandroid::test::__anon5a430b1f0811::ImplicitConversionsHelper211*38e8c45fSAndroid Build Coastguard Worker auto exact(int) -> int { return 0; }
inexactandroid::test::__anon5a430b1f0811::ImplicitConversionsHelper212*38e8c45fSAndroid Build Coastguard Worker auto inexact(long) -> short { return 0; }
213*38e8c45fSAndroid Build Coastguard Worker // TODO: Switch to `auto templated(auto x)` with C++20
214*38e8c45fSAndroid Build Coastguard Worker template <typename T>
templatedandroid::test::__anon5a430b1f0811::ImplicitConversionsHelper215*38e8c45fSAndroid Build Coastguard Worker T templated(T x) {
216*38e8c45fSAndroid Build Coastguard Worker return x;
217*38e8c45fSAndroid Build Coastguard Worker }
218*38e8c45fSAndroid Build Coastguard Worker
static_exactandroid::test::__anon5a430b1f0811::ImplicitConversionsHelper219*38e8c45fSAndroid Build Coastguard Worker static auto static_exact(int) -> int { return 0; }
static_inexactandroid::test::__anon5a430b1f0811::ImplicitConversionsHelper220*38e8c45fSAndroid Build Coastguard Worker static auto static_inexact(long) -> short { return 0; }
221*38e8c45fSAndroid Build Coastguard Worker // TODO: Switch to `static auto static_templated(auto x)` with C++20
222*38e8c45fSAndroid Build Coastguard Worker template <typename T>
static_templatedandroid::test::__anon5a430b1f0811::ImplicitConversionsHelper223*38e8c45fSAndroid Build Coastguard Worker static T static_templated(T x) {
224*38e8c45fSAndroid Build Coastguard Worker return x;
225*38e8c45fSAndroid Build Coastguard Worker }
226*38e8c45fSAndroid Build Coastguard Worker };
227*38e8c45fSAndroid Build Coastguard Worker
228*38e8c45fSAndroid Build Coastguard Worker } // namespace
229*38e8c45fSAndroid Build Coastguard Worker
TEST(Function,ImplicitConversions)230*38e8c45fSAndroid Build Coastguard Worker TEST(Function, ImplicitConversions) {
231*38e8c45fSAndroid Build Coastguard Worker using Function = ftl::Function<int(int)>;
232*38e8c45fSAndroid Build Coastguard Worker auto check = [](Function f) { return f(0); };
233*38e8c45fSAndroid Build Coastguard Worker auto exact = [](int) -> int { return 0; };
234*38e8c45fSAndroid Build Coastguard Worker auto inexact = [](long) -> short { return 0; };
235*38e8c45fSAndroid Build Coastguard Worker auto templated = [](auto x) { return x; };
236*38e8c45fSAndroid Build Coastguard Worker
237*38e8c45fSAndroid Build Coastguard Worker ImplicitConversionsHelper helper;
238*38e8c45fSAndroid Build Coastguard Worker
239*38e8c45fSAndroid Build Coastguard Worker // Note, `check(nullptr)` would crash, so we can only check if it would be invocable.
240*38e8c45fSAndroid Build Coastguard Worker static_assert(std::is_invocable_v<decltype(check), decltype(nullptr)>);
241*38e8c45fSAndroid Build Coastguard Worker
242*38e8c45fSAndroid Build Coastguard Worker // Note: We invoke each of these to fully expand all the templates involved.
243*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(check(ftl::no_op), 0);
244*38e8c45fSAndroid Build Coastguard Worker
245*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(check(exact), 0);
246*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(check(inexact), 0);
247*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(check(templated), 0);
248*38e8c45fSAndroid Build Coastguard Worker
249*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(check(Function::make<&ImplicitConversionsHelper::exact>(&helper)), 0);
250*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(check(Function::make<&ImplicitConversionsHelper::inexact>(&helper)), 0);
251*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(check(Function::make<&ImplicitConversionsHelper::templated<int>>(&helper)), 0);
252*38e8c45fSAndroid Build Coastguard Worker
253*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(check(Function::make<&ImplicitConversionsHelper::static_exact>()), 0);
254*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(check(Function::make<&ImplicitConversionsHelper::static_inexact>()), 0);
255*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(check(Function::make<&ImplicitConversionsHelper::static_templated<int>>()), 0);
256*38e8c45fSAndroid Build Coastguard Worker }
257*38e8c45fSAndroid Build Coastguard Worker
TEST(Function,MakeWithNonConstMemberFunction)258*38e8c45fSAndroid Build Coastguard Worker TEST(Function, MakeWithNonConstMemberFunction) {
259*38e8c45fSAndroid Build Coastguard Worker struct Observer {
260*38e8c45fSAndroid Build Coastguard Worker bool called = false;
261*38e8c45fSAndroid Build Coastguard Worker void setCalled() { called = true; }
262*38e8c45fSAndroid Build Coastguard Worker } observer;
263*38e8c45fSAndroid Build Coastguard Worker
264*38e8c45fSAndroid Build Coastguard Worker auto f = ftl::make_function<&Observer::setCalled>(&observer);
265*38e8c45fSAndroid Build Coastguard Worker
266*38e8c45fSAndroid Build Coastguard Worker f();
267*38e8c45fSAndroid Build Coastguard Worker
268*38e8c45fSAndroid Build Coastguard Worker EXPECT_TRUE(observer.called);
269*38e8c45fSAndroid Build Coastguard Worker
270*38e8c45fSAndroid Build Coastguard Worker EXPECT_TRUE(f == ftl::Function<void()>::make<&Observer::setCalled>(&observer));
271*38e8c45fSAndroid Build Coastguard Worker }
272*38e8c45fSAndroid Build Coastguard Worker
TEST(Function,MakeWithConstMemberFunction)273*38e8c45fSAndroid Build Coastguard Worker TEST(Function, MakeWithConstMemberFunction) {
274*38e8c45fSAndroid Build Coastguard Worker struct Observer {
275*38e8c45fSAndroid Build Coastguard Worker mutable bool called = false;
276*38e8c45fSAndroid Build Coastguard Worker void setCalled() const { called = true; }
277*38e8c45fSAndroid Build Coastguard Worker } observer;
278*38e8c45fSAndroid Build Coastguard Worker
279*38e8c45fSAndroid Build Coastguard Worker const auto f = ftl::make_function<&Observer::setCalled>(&observer);
280*38e8c45fSAndroid Build Coastguard Worker
281*38e8c45fSAndroid Build Coastguard Worker f();
282*38e8c45fSAndroid Build Coastguard Worker
283*38e8c45fSAndroid Build Coastguard Worker EXPECT_TRUE(observer.called);
284*38e8c45fSAndroid Build Coastguard Worker
285*38e8c45fSAndroid Build Coastguard Worker EXPECT_TRUE(f == ftl::Function<void()>::make<&Observer::setCalled>(&observer));
286*38e8c45fSAndroid Build Coastguard Worker }
287*38e8c45fSAndroid Build Coastguard Worker
TEST(Function,MakeWithConstClassPointer)288*38e8c45fSAndroid Build Coastguard Worker TEST(Function, MakeWithConstClassPointer) {
289*38e8c45fSAndroid Build Coastguard Worker const struct Observer {
290*38e8c45fSAndroid Build Coastguard Worker mutable bool called = false;
291*38e8c45fSAndroid Build Coastguard Worker void setCalled() const { called = true; }
292*38e8c45fSAndroid Build Coastguard Worker } observer;
293*38e8c45fSAndroid Build Coastguard Worker
294*38e8c45fSAndroid Build Coastguard Worker const auto f = ftl::make_function<&Observer::setCalled>(&observer);
295*38e8c45fSAndroid Build Coastguard Worker
296*38e8c45fSAndroid Build Coastguard Worker f();
297*38e8c45fSAndroid Build Coastguard Worker
298*38e8c45fSAndroid Build Coastguard Worker EXPECT_TRUE(observer.called);
299*38e8c45fSAndroid Build Coastguard Worker
300*38e8c45fSAndroid Build Coastguard Worker EXPECT_TRUE(f == ftl::Function<void()>::make<&Observer::setCalled>(&observer));
301*38e8c45fSAndroid Build Coastguard Worker }
302*38e8c45fSAndroid Build Coastguard Worker
TEST(Function,MakeWithNonCapturingLambda)303*38e8c45fSAndroid Build Coastguard Worker TEST(Function, MakeWithNonCapturingLambda) {
304*38e8c45fSAndroid Build Coastguard Worker auto f = ftl::make_function([](int a, int b) { return a + b; });
305*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(f(1, 2), 3);
306*38e8c45fSAndroid Build Coastguard Worker }
307*38e8c45fSAndroid Build Coastguard Worker
TEST(Function,MakeWithCapturingLambda)308*38e8c45fSAndroid Build Coastguard Worker TEST(Function, MakeWithCapturingLambda) {
309*38e8c45fSAndroid Build Coastguard Worker bool called = false;
310*38e8c45fSAndroid Build Coastguard Worker auto f = ftl::make_function([&called](int a, int b) {
311*38e8c45fSAndroid Build Coastguard Worker called = true;
312*38e8c45fSAndroid Build Coastguard Worker return a + b;
313*38e8c45fSAndroid Build Coastguard Worker });
314*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(f(1, 2), 3);
315*38e8c45fSAndroid Build Coastguard Worker EXPECT_TRUE(called);
316*38e8c45fSAndroid Build Coastguard Worker }
317*38e8c45fSAndroid Build Coastguard Worker
TEST(Function,MakeWithCapturingMutableLambda)318*38e8c45fSAndroid Build Coastguard Worker TEST(Function, MakeWithCapturingMutableLambda) {
319*38e8c45fSAndroid Build Coastguard Worker bool called = false;
320*38e8c45fSAndroid Build Coastguard Worker auto f = ftl::make_function([&called](int a, int b) mutable {
321*38e8c45fSAndroid Build Coastguard Worker called = true;
322*38e8c45fSAndroid Build Coastguard Worker return a + b;
323*38e8c45fSAndroid Build Coastguard Worker });
324*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(f(1, 2), 3);
325*38e8c45fSAndroid Build Coastguard Worker EXPECT_TRUE(called);
326*38e8c45fSAndroid Build Coastguard Worker }
327*38e8c45fSAndroid Build Coastguard Worker
TEST(Function,MakeWithThreePointerCapturingLambda)328*38e8c45fSAndroid Build Coastguard Worker TEST(Function, MakeWithThreePointerCapturingLambda) {
329*38e8c45fSAndroid Build Coastguard Worker bool my_bool = false;
330*38e8c45fSAndroid Build Coastguard Worker int my_int = 0;
331*38e8c45fSAndroid Build Coastguard Worker float my_float = 0.f;
332*38e8c45fSAndroid Build Coastguard Worker
333*38e8c45fSAndroid Build Coastguard Worker auto f = ftl::make_function(
334*38e8c45fSAndroid Build Coastguard Worker [ptr_bool = &my_bool, ptr_int = &my_int, ptr_float = &my_float](int a, int b) mutable {
335*38e8c45fSAndroid Build Coastguard Worker *ptr_bool = true;
336*38e8c45fSAndroid Build Coastguard Worker *ptr_int = 1;
337*38e8c45fSAndroid Build Coastguard Worker *ptr_float = 1.f;
338*38e8c45fSAndroid Build Coastguard Worker
339*38e8c45fSAndroid Build Coastguard Worker return a + b;
340*38e8c45fSAndroid Build Coastguard Worker });
341*38e8c45fSAndroid Build Coastguard Worker
342*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(f(1, 2), 3);
343*38e8c45fSAndroid Build Coastguard Worker
344*38e8c45fSAndroid Build Coastguard Worker EXPECT_TRUE(my_bool);
345*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(my_int, 1);
346*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(my_float, 1.f);
347*38e8c45fSAndroid Build Coastguard Worker }
348*38e8c45fSAndroid Build Coastguard Worker
TEST(Function,MakeWithFreeFunction)349*38e8c45fSAndroid Build Coastguard Worker TEST(Function, MakeWithFreeFunction) {
350*38e8c45fSAndroid Build Coastguard Worker auto f = ftl::make_function<&std::make_unique<int, int>>();
351*38e8c45fSAndroid Build Coastguard Worker std::unique_ptr<int> unique_int = f(1);
352*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(unique_int);
353*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(*unique_int, 1);
354*38e8c45fSAndroid Build Coastguard Worker }
355*38e8c45fSAndroid Build Coastguard Worker
TEST(Function,CopyToLarger)356*38e8c45fSAndroid Build Coastguard Worker TEST(Function, CopyToLarger) {
357*38e8c45fSAndroid Build Coastguard Worker int counter = 0;
358*38e8c45fSAndroid Build Coastguard Worker ftl::Function<void()> a{[ptr_counter = &counter] { (*ptr_counter)++; }};
359*38e8c45fSAndroid Build Coastguard Worker ftl::Function<void(), 1> b = a;
360*38e8c45fSAndroid Build Coastguard Worker ftl::Function<void(), 2> c = a;
361*38e8c45fSAndroid Build Coastguard Worker
362*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(counter, 0);
363*38e8c45fSAndroid Build Coastguard Worker a();
364*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(counter, 1);
365*38e8c45fSAndroid Build Coastguard Worker b();
366*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(counter, 2);
367*38e8c45fSAndroid Build Coastguard Worker c();
368*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(counter, 3);
369*38e8c45fSAndroid Build Coastguard Worker
370*38e8c45fSAndroid Build Coastguard Worker b = [ptr_counter = &counter] { (*ptr_counter) += 2; };
371*38e8c45fSAndroid Build Coastguard Worker c = [ptr_counter = &counter] { (*ptr_counter) += 3; };
372*38e8c45fSAndroid Build Coastguard Worker
373*38e8c45fSAndroid Build Coastguard Worker b();
374*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(counter, 5);
375*38e8c45fSAndroid Build Coastguard Worker c();
376*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(counter, 8);
377*38e8c45fSAndroid Build Coastguard Worker }
378*38e8c45fSAndroid Build Coastguard Worker
379*38e8c45fSAndroid Build Coastguard Worker } // namespace android::test
380