xref: /aosp_15_r20/frameworks/native/include/ftl/details/function.h (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
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 #pragma once
18*38e8c45fSAndroid Build Coastguard Worker 
19*38e8c45fSAndroid Build Coastguard Worker #include <array>
20*38e8c45fSAndroid Build Coastguard Worker #include <cstddef>
21*38e8c45fSAndroid Build Coastguard Worker #include <cstdint>
22*38e8c45fSAndroid Build Coastguard Worker #include <cstring>
23*38e8c45fSAndroid Build Coastguard Worker #include <type_traits>
24*38e8c45fSAndroid Build Coastguard Worker 
25*38e8c45fSAndroid Build Coastguard Worker namespace android::ftl::details {
26*38e8c45fSAndroid Build Coastguard Worker 
27*38e8c45fSAndroid Build Coastguard Worker // The maximum allowed value for the template argument `N` in
28*38e8c45fSAndroid Build Coastguard Worker // `ftl::Function<F, N>`.
29*38e8c45fSAndroid Build Coastguard Worker constexpr size_t kFunctionMaximumN = 14;
30*38e8c45fSAndroid Build Coastguard Worker 
31*38e8c45fSAndroid Build Coastguard Worker // Converts a member function pointer type `Ret(Class::*)(Args...)` to an equivalent non-member
32*38e8c45fSAndroid Build Coastguard Worker // function type `Ret(Args...)`.
33*38e8c45fSAndroid Build Coastguard Worker 
34*38e8c45fSAndroid Build Coastguard Worker template <typename>
35*38e8c45fSAndroid Build Coastguard Worker struct remove_member_function_pointer;
36*38e8c45fSAndroid Build Coastguard Worker 
37*38e8c45fSAndroid Build Coastguard Worker template <typename Class, typename Ret, typename... Args>
38*38e8c45fSAndroid Build Coastguard Worker struct remove_member_function_pointer<Ret (Class::*)(Args...)> {
39*38e8c45fSAndroid Build Coastguard Worker   using type = Ret(Args...);
40*38e8c45fSAndroid Build Coastguard Worker };
41*38e8c45fSAndroid Build Coastguard Worker 
42*38e8c45fSAndroid Build Coastguard Worker template <typename Class, typename Ret, typename... Args>
43*38e8c45fSAndroid Build Coastguard Worker struct remove_member_function_pointer<Ret (Class::*)(Args...) const> {
44*38e8c45fSAndroid Build Coastguard Worker   using type = Ret(Args...);
45*38e8c45fSAndroid Build Coastguard Worker };
46*38e8c45fSAndroid Build Coastguard Worker 
47*38e8c45fSAndroid Build Coastguard Worker template <auto MemberFunction>
48*38e8c45fSAndroid Build Coastguard Worker using remove_member_function_pointer_t =
49*38e8c45fSAndroid Build Coastguard Worker     typename remove_member_function_pointer<decltype(MemberFunction)>::type;
50*38e8c45fSAndroid Build Coastguard Worker 
51*38e8c45fSAndroid Build Coastguard Worker // Helper functions for binding to the supported targets.
52*38e8c45fSAndroid Build Coastguard Worker 
53*38e8c45fSAndroid Build Coastguard Worker template <typename Ret, typename... Args>
54*38e8c45fSAndroid Build Coastguard Worker auto bind_opaque_no_op() -> Ret (*)(void*, Args...) {
55*38e8c45fSAndroid Build Coastguard Worker   return [](void*, Args...) -> Ret {
56*38e8c45fSAndroid Build Coastguard Worker     if constexpr (!std::is_void_v<Ret>) {
57*38e8c45fSAndroid Build Coastguard Worker       return Ret{};
58*38e8c45fSAndroid Build Coastguard Worker     }
59*38e8c45fSAndroid Build Coastguard Worker   };
60*38e8c45fSAndroid Build Coastguard Worker }
61*38e8c45fSAndroid Build Coastguard Worker 
62*38e8c45fSAndroid Build Coastguard Worker template <typename F, typename Ret, typename... Args>
63*38e8c45fSAndroid Build Coastguard Worker auto bind_opaque_function_object(const F&) -> Ret (*)(void*, Args...) {
64*38e8c45fSAndroid Build Coastguard Worker   return [](void* opaque, Args... args) -> Ret {
65*38e8c45fSAndroid Build Coastguard Worker     return std::invoke(*static_cast<F*>(opaque), std::forward<Args>(args)...);
66*38e8c45fSAndroid Build Coastguard Worker   };
67*38e8c45fSAndroid Build Coastguard Worker }
68*38e8c45fSAndroid Build Coastguard Worker 
69*38e8c45fSAndroid Build Coastguard Worker template <auto MemberFunction, typename Class, typename Ret, typename... Args>
70*38e8c45fSAndroid Build Coastguard Worker auto bind_member_function(Class* instance, Ret (*)(Args...) = nullptr) {
71*38e8c45fSAndroid Build Coastguard Worker   return [instance](Args... args) -> Ret {
72*38e8c45fSAndroid Build Coastguard Worker     return std::invoke(MemberFunction, instance, std::forward<Args>(args)...);
73*38e8c45fSAndroid Build Coastguard Worker   };
74*38e8c45fSAndroid Build Coastguard Worker }
75*38e8c45fSAndroid Build Coastguard Worker 
76*38e8c45fSAndroid Build Coastguard Worker template <auto FreeFunction, typename Ret, typename... Args>
77*38e8c45fSAndroid Build Coastguard Worker auto bind_free_function(Ret (*)(Args...) = nullptr) {
78*38e8c45fSAndroid Build Coastguard Worker   return [](Args... args) -> Ret { return std::invoke(FreeFunction, std::forward<Args>(args)...); };
79*38e8c45fSAndroid Build Coastguard Worker }
80*38e8c45fSAndroid Build Coastguard Worker 
81*38e8c45fSAndroid Build Coastguard Worker // Traits class for the opaque storage used by Function.
82*38e8c45fSAndroid Build Coastguard Worker 
83*38e8c45fSAndroid Build Coastguard Worker template <std::size_t N>
84*38e8c45fSAndroid Build Coastguard Worker struct function_opaque_storage {
85*38e8c45fSAndroid Build Coastguard Worker   // The actual type used for the opaque storage. An `N` of zero specifies the minimum useful size,
86*38e8c45fSAndroid Build Coastguard Worker   // which allows a lambda with zero or one capture args.
87*38e8c45fSAndroid Build Coastguard Worker   using type = std::array<std::intptr_t, N + 1>;
88*38e8c45fSAndroid Build Coastguard Worker 
89*38e8c45fSAndroid Build Coastguard Worker   template <typename S>
90*38e8c45fSAndroid Build Coastguard Worker   static constexpr bool require_trivially_copyable = std::is_trivially_copyable_v<S>;
91*38e8c45fSAndroid Build Coastguard Worker 
92*38e8c45fSAndroid Build Coastguard Worker   template <typename S>
93*38e8c45fSAndroid Build Coastguard Worker   static constexpr bool require_trivially_destructible = std::is_trivially_destructible_v<S>;
94*38e8c45fSAndroid Build Coastguard Worker 
95*38e8c45fSAndroid Build Coastguard Worker   template <typename S>
96*38e8c45fSAndroid Build Coastguard Worker   static constexpr bool require_will_fit_in_opaque_storage = sizeof(S) <= sizeof(type);
97*38e8c45fSAndroid Build Coastguard Worker 
98*38e8c45fSAndroid Build Coastguard Worker   template <typename S>
99*38e8c45fSAndroid Build Coastguard Worker   static constexpr bool require_alignment_compatible =
100*38e8c45fSAndroid Build Coastguard Worker       std::alignment_of_v<S> <= std::alignment_of_v<type>;
101*38e8c45fSAndroid Build Coastguard Worker 
102*38e8c45fSAndroid Build Coastguard Worker   // Copies `src` into the opaque storage, and returns that storage.
103*38e8c45fSAndroid Build Coastguard Worker   template <typename S>
104*38e8c45fSAndroid Build Coastguard Worker   static type opaque_copy(const S& src) {
105*38e8c45fSAndroid Build Coastguard Worker     // TODO: Replace with C++20 concepts/constraints which can give more details.
106*38e8c45fSAndroid Build Coastguard Worker     static_assert(require_trivially_copyable<S>,
107*38e8c45fSAndroid Build Coastguard Worker                   "ftl::Function can only store lambdas that capture trivially copyable data.");
108*38e8c45fSAndroid Build Coastguard Worker     static_assert(
109*38e8c45fSAndroid Build Coastguard Worker         require_trivially_destructible<S>,
110*38e8c45fSAndroid Build Coastguard Worker         "ftl::Function can only store lambdas that capture trivially destructible data.");
111*38e8c45fSAndroid Build Coastguard Worker     static_assert(require_will_fit_in_opaque_storage<S>,
112*38e8c45fSAndroid Build Coastguard Worker                   "ftl::Function has limited storage for lambda captured state. Maybe you need to "
113*38e8c45fSAndroid Build Coastguard Worker                   "increase N?");
114*38e8c45fSAndroid Build Coastguard Worker     static_assert(require_alignment_compatible<S>);
115*38e8c45fSAndroid Build Coastguard Worker 
116*38e8c45fSAndroid Build Coastguard Worker     type opaque;
117*38e8c45fSAndroid Build Coastguard Worker     std::memcpy(opaque.data(), &src, sizeof(S));
118*38e8c45fSAndroid Build Coastguard Worker     return opaque;
119*38e8c45fSAndroid Build Coastguard Worker   }
120*38e8c45fSAndroid Build Coastguard Worker };
121*38e8c45fSAndroid Build Coastguard Worker 
122*38e8c45fSAndroid Build Coastguard Worker // Traits class to help determine the template parameters to use for a ftl::Function, given a
123*38e8c45fSAndroid Build Coastguard Worker // function object.
124*38e8c45fSAndroid Build Coastguard Worker 
125*38e8c45fSAndroid Build Coastguard Worker template <typename F, typename = decltype(&F::operator())>
126*38e8c45fSAndroid Build Coastguard Worker struct function_traits {
127*38e8c45fSAndroid Build Coastguard Worker   // The function type `F` with which to instantiate the `Function<F, N>` template.
128*38e8c45fSAndroid Build Coastguard Worker   using type = remove_member_function_pointer_t<&F::operator()>;
129*38e8c45fSAndroid Build Coastguard Worker 
130*38e8c45fSAndroid Build Coastguard Worker   // The (minimum) size `N` with which to instantiate the `Function<F, N>` template.
131*38e8c45fSAndroid Build Coastguard Worker   static constexpr std::size_t size =
132*38e8c45fSAndroid Build Coastguard Worker       (std::max(sizeof(std::intptr_t), sizeof(F)) - 1) / sizeof(std::intptr_t);
133*38e8c45fSAndroid Build Coastguard Worker };
134*38e8c45fSAndroid Build Coastguard Worker 
135*38e8c45fSAndroid Build Coastguard Worker }  // namespace android::ftl::details
136