1 /* 2 * Copyright (c) 2024 Huawei Device Co., Ltd. 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 * http://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 16 #ifndef OHOS_FFI_CJ_LAMBDA_H 17 #define OHOS_FFI_CJ_LAMBDA_H 18 19 #include <cstdint> 20 #include <tuple> 21 22 #include "ffi_remote_data.h" 23 24 #ifndef FFI_EXPORT 25 #ifndef WINDOWS_PLATFORM 26 #define FFI_EXPORT __attribute__((visibility("default"))) 27 #else 28 #define FFI_EXPORT __declspec(dllexport) 29 #endif 30 #endif 31 32 class FFI_EXPORT CJLambda { 33 template <size_t I> 34 struct TupleRuntimeHelper { 35 template <typename T> GetElementAddrTupleRuntimeHelper36 static void* GetElementAddr(T& tup, size_t idx) 37 { 38 if (idx == I - 1) { 39 return &(std::get<I - 1>(tup)); 40 } else { 41 return TupleRuntimeHelper<I - 1>::GetElementAddr(tup, idx); 42 } 43 } 44 }; 45 46 template <> 47 struct TupleRuntimeHelper<0> { 48 template <typename T> 49 static void* GetElementAddr(T& tup, size_t idx) 50 { 51 // Unreachable 52 return nullptr; 53 } 54 }; 55 56 template <typename... Types> 57 static inline void* GetElementAddr(std::tuple<Types...> const& tup, size_t idx) 58 { 59 return TupleRuntimeHelper<sizeof...(Types)>::GetElementAddr(tup, idx); 60 } 61 62 template <typename... Types> 63 static inline void* GetElementAddr(std::tuple<Types...>& tup, size_t idx) 64 { 65 return TupleRuntimeHelper<sizeof...(Types)>::GetElementAddr(tup, idx); 66 } 67 public: 68 template<class... I> 69 static std::function<void(I...)> Create(void (*callback)(I...)) 70 { 71 auto handle = OHOS::FFI::RemoteData::Create<OHOS::FFI::CJLambdaRemoteData>(reinterpret_cast<int64_t>(callback)); 72 return [handle](I...args) -> void { 73 constexpr int32_t argc = std::tuple_size_v<std::tuple<I...>>; 74 if (argc == 0) { 75 InvokeLambda(handle->GetID(), argc, nullptr, nullptr); 76 return; 77 } 78 auto argsTuple = std::make_tuple(args...); 79 void* argv[argc]; 80 for (size_t i = 0; i < argc; ++i) { 81 argv[i] = GetElementAddr(argsTuple, i); 82 } 83 InvokeLambda(handle->GetID(), argc, argv, nullptr); 84 }; 85 } 86 87 template<class... I, class R> 88 static std::function<R(I...)> Create(R (*callback)(I...)) 89 { 90 auto handle = OHOS::FFI::RemoteData::Create<OHOS::FFI::CJLambdaRemoteData>(reinterpret_cast<int64_t>(callback)); 91 return [handle](I...args) -> R { 92 R res; 93 constexpr int32_t argc = std::tuple_size_v<std::tuple<I...>>; 94 if (argc == 0) { 95 InvokeLambda(handle->GetID(), argc, nullptr, &res); 96 return res; 97 } 98 auto argsTuple = std::make_tuple(args...); 99 void* argv[argc]; 100 for (size_t i = 0; i < argc; ++i) { 101 argv[i] = GetElementAddr(argsTuple, i); 102 } 103 InvokeLambda(handle->GetID(), argc, argv, &res); 104 return res; 105 }; 106 } 107 108 private: 109 static inline void InvokeLambda(int64_t lambdaId, int32_t argc, void** argv, void* result) 110 { 111 auto invoker = CJFFIFnInvoker::GetInstance()->GetCJFuncs().atCOHOSFFICallbackInvoker; 112 invoker(lambdaId, argc, argv, result); 113 } 114 }; 115 116 #endif // OHOS_FFI_CJ_LAMBDA_H 117