/* * Copyright 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include #include namespace android::ftl::details { // The maximum allowed value for the template argument `N` in // `ftl::Function`. constexpr size_t kFunctionMaximumN = 14; // Converts a member function pointer type `Ret(Class::*)(Args...)` to an equivalent non-member // function type `Ret(Args...)`. template struct remove_member_function_pointer; template struct remove_member_function_pointer { using type = Ret(Args...); }; template struct remove_member_function_pointer { using type = Ret(Args...); }; template using remove_member_function_pointer_t = typename remove_member_function_pointer::type; // Helper functions for binding to the supported targets. template auto bind_opaque_no_op() -> Ret (*)(void*, Args...) { return [](void*, Args...) -> Ret { if constexpr (!std::is_void_v) { return Ret{}; } }; } template auto bind_opaque_function_object(const F&) -> Ret (*)(void*, Args...) { return [](void* opaque, Args... args) -> Ret { return std::invoke(*static_cast(opaque), std::forward(args)...); }; } template auto bind_member_function(Class* instance, Ret (*)(Args...) = nullptr) { return [instance](Args... args) -> Ret { return std::invoke(MemberFunction, instance, std::forward(args)...); }; } template auto bind_free_function(Ret (*)(Args...) = nullptr) { return [](Args... args) -> Ret { return std::invoke(FreeFunction, std::forward(args)...); }; } // Traits class for the opaque storage used by Function. template struct function_opaque_storage { // The actual type used for the opaque storage. An `N` of zero specifies the minimum useful size, // which allows a lambda with zero or one capture args. using type = std::array; template static constexpr bool require_trivially_copyable = std::is_trivially_copyable_v; template static constexpr bool require_trivially_destructible = std::is_trivially_destructible_v; template static constexpr bool require_will_fit_in_opaque_storage = sizeof(S) <= sizeof(type); template static constexpr bool require_alignment_compatible = std::alignment_of_v <= std::alignment_of_v; // Copies `src` into the opaque storage, and returns that storage. template static type opaque_copy(const S& src) { // TODO: Replace with C++20 concepts/constraints which can give more details. static_assert(require_trivially_copyable, "ftl::Function can only store lambdas that capture trivially copyable data."); static_assert( require_trivially_destructible, "ftl::Function can only store lambdas that capture trivially destructible data."); static_assert(require_will_fit_in_opaque_storage, "ftl::Function has limited storage for lambda captured state. Maybe you need to " "increase N?"); static_assert(require_alignment_compatible); type opaque; std::memcpy(opaque.data(), &src, sizeof(S)); return opaque; } }; // Traits class to help determine the template parameters to use for a ftl::Function, given a // function object. template struct function_traits { // The function type `F` with which to instantiate the `Function` template. using type = remove_member_function_pointer_t<&F::operator()>; // The (minimum) size `N` with which to instantiate the `Function` template. static constexpr std::size_t size = (std::max(sizeof(std::intptr_t), sizeof(F)) - 1) / sizeof(std::intptr_t); }; } // namespace android::ftl::details