• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 META_API_FUNCTION_H
17 #define META_API_FUNCTION_H
18 
19 #include <meta/api/call_context.h>
20 #include <meta/base/capture.h>
21 #include <meta/interface/builtin_objects.h>
22 #include <meta/interface/interface_helpers.h>
23 #include <meta/interface/intf_cloneable.h>
24 #include <meta/interface/intf_function.h>
25 #include <meta/interface/object_macros.h>
26 
META_BEGIN_NAMESPACE()27 META_BEGIN_NAMESPACE()
28 
29 /**
30  * @brief Function implementation that is used for the meta function system.
31  */
32 template<typename Interface, typename Func>
33 class DefaultFunction final : public IntroduceInterfaces<IObject, IFunction, ICloneable> {
34 public:
35     ~DefaultFunction() override = default;
36     DefaultFunction& operator=(const DefaultFunction&) noexcept = delete;
37     META_NO_MOVE(DefaultFunction)
38 
39     BASE_NS::string GetName() const override
40     {
41         return name_;
42     }
43 
44     IObject::ConstPtr GetDestination() const override
45     {
46         return interface_pointer_cast<IObject>(obj_);
47     }
48 
49     void Invoke(const ICallContext::Ptr& context) const override
50     {
51         func_(obj_, context);
52     }
53 
54     ICallContext::Ptr CreateCallContext() const override
55     {
56         if (context_) {
57             return GetValue<ICallContext::Ptr>(*context_());
58         }
59         return nullptr;
60     }
61 
62     BASE_NS::shared_ptr<CORE_NS::IInterface> GetClone() const override
63     {
64         BASE_NS::shared_ptr<DefaultFunction> p(new DefaultFunction(*this));
65         return interface_pointer_cast<CORE_NS::IInterface>(p);
66     }
67 
68     ObjectId GetClassId() const override
69     {
70         return {};
71     }
72     BASE_NS::string_view GetClassName() const override
73     {
74         return "Function";
75     }
76     BASE_NS::vector<BASE_NS::Uid> GetInterfaces() const override
77     {
78         return GetInterfacesVector();
79     }
80 
81     DefaultFunction(BASE_NS::string n, BASE_NS::shared_ptr<Interface> obj, Func f, Internal::MetaValue* context)
82         : name_(BASE_NS::move(n)), obj_(obj), func_(BASE_NS::move(f)), context_(context)
83     {}
84 
85 protected:
86     DefaultFunction(const DefaultFunction& s) : name_(s.name_), obj_(s.obj_), func_(s.func_), context_(s.context_) {}
87 
88 protected:
89     BASE_NS::string name_;
90     BASE_NS::weak_ptr<Interface> obj_;
91     Func func_;
92     Internal::MetaValue* const context_;
93 };
94 
95 /**
96  * @brief Create DefaultFunction object for obj+memfun (used in metadata initialisation)
97  */
98 template<typename Interface, typename Func>
CreateFunction(BASE_NS::string_view name,BASE_NS::shared_ptr<Interface> obj,Func func,Internal::MetaValue * context)99 IFunction::Ptr CreateFunction(
100     BASE_NS::string_view name, BASE_NS::shared_ptr<Interface> obj, Func func, Internal::MetaValue* context)
101 {
102     auto l = [func](auto obj, const ICallContext::Ptr& context) {
103         if (auto o = obj.lock()) {
104             CallFunction(context, o.get(), func);
105         }
106     };
107     return IFunction::Ptr(
108         new DefaultFunction<Interface, decltype(l)>(BASE_NS::string(name), obj, BASE_NS::move(l), context));
109 }
110 
111 /**
112  * @brief Create DefaultFunction object from lambda
113  */
114 template<typename Func, typename = EnableIfBindFunction<Func>>
CreateBindFunction(Func func)115 IFunction::Ptr CreateBindFunction(Func func)
116 {
117     auto ccontext = []() {
118         ::BASE_NS::string_view arr[] = { "" };
119         return META_NS::ConstructAny<META_NS::ICallContext::Ptr>(
120             CreateCallContextImpl<decltype(func())>(ParamNameToView(arr)));
121     };
122     // wrap to make CallFunction to work with operator()(auto...)
123     auto wrapper = [func]() mutable { return func(); };
124     auto l = [wrapper](auto, const ICallContext::Ptr& context) { ::META_NS::CallFunction(context, wrapper); };
125     return IFunction::Ptr(new DefaultFunction<IObject, decltype(l)>("Bind", nullptr, BASE_NS::move(l), ccontext));
126 }
127 
128 /**
129  * @brief Create DefaultFunction object from lambda
130  */
131 template<typename Func, typename... Args>
CreateBindFunctionSafe(Func func,Args &&...args)132 IFunction::Ptr CreateBindFunctionSafe(Func func, Args&&... args)
133 {
134     return CreateBindFunction(CaptureSafe(BASE_NS::move(func), BASE_NS::forward<Args>(args)...));
135 }
136 
137 /**
138  * @brief Create forwarding function object
139  */
CreateFunction(const IObject::Ptr & obj,BASE_NS::string_view name)140 inline IFunction::Ptr CreateFunction(const IObject::Ptr& obj, BASE_NS::string_view name)
141 {
142     if (auto f = META_NS::GetObjectRegistry().Create<ISettableFunction>(ClassId::SettableFunction)) {
143         if (f->SetTarget(obj, name)) {
144             return f;
145         }
146     }
147     return nullptr;
148 }
149 
150 /**
151  * @brief Helper class for meta function call result.
152  */
153 template<typename Type>
154 struct CallResult {
155     explicit operator bool() const
156     {
157         return success;
158     }
159 
160     /**
161      * @brief Call context that was used for the call.
162      */
163     ICallContext::Ptr context;
164     /**
165      * @brief True if it was possible to make the call (i.e. the argument types match the parameters).
166      */
167     bool success {};
168     /**
169      * @brief Return value of the function call.
170      */
171     Type value {};
172 };
173 
174 template<>
175 struct CallResult<void> {
176     explicit operator bool() const
177     {
178         return success;
179     }
180 
181     ICallContext::Ptr context;
182     bool success {};
183 };
184 
185 template<typename Ret, typename... Args, size_t... Index>
186 CallResult<Ret> CallMetaFunctionImpl(const IFunction::Ptr& func, IndexSequence<Index...>, Args&&... args)
187 {
188     auto context = func->CreateCallContext();
189     if (!context) {
190         return {};
191     }
192     auto params = context->GetParameters();
193     // Allow to use defaults from call context
194     if (params.size() < sizeof...(Args)) {
195         context->ReportError("invalid meta call");
196         return { context };
197     }
198 
199     if (!(true && ... && Set<PlainType_t<Args>>(context, params[Index].name, args))) {
200         context->ReportError("invalid meta call");
201         return { context };
202     }
203 
204     func->Invoke(context);
205     if (context->Succeeded()) {
206         if constexpr (BASE_NS::is_same_v<Ret, void>) {
207             return CallResult<Ret> { context, true };
208         }
209         if constexpr (!BASE_NS::is_same_v<Ret, void>) {
210             if (auto p = GetResult<Ret>(context)) {
211                 return CallResult<Ret> { context, true, *p };
212             }
213         }
214     }
215     return { context };
216 }
217 
218 /**
219  * @brief Call function via interface with the given arguments.
220  * @param func Function to call.
221  * @param args Arguments for the function call.
222  * @return Result of the call.
223  * @see CallResult
224  */
225 template<typename Ret, typename... Args>
226 CallResult<Ret> CallMetaFunction(const IFunction::Ptr& func, Args&&... args)
227 {
228     return CallMetaFunctionImpl<Ret>(func, MakeIndexSequenceFor<Args...>(), BASE_NS::forward<Args>(args)...);
229 }
230 
231 template<typename Signature>
232 struct IsFunctionCompatibleImpl;
233 
234 template<typename Ret, typename... Args>
235 struct IsFunctionCompatibleImpl<Ret(Args...)> {
236     template<size_t... Index>
237     static bool Call(const IFunction::Ptr& func, IndexSequence<Index...>)
238     {
239         auto context = func->CreateCallContext();
240         // e.g. wrong number of parameters when implementing meta function
241         if (!context) {
242             return false;
243         }
244 
245         auto params = context->GetParameters();
246         // Allow to use defaults from call context
247         if (params.size() < sizeof...(Args)) {
248             return false;
249         }
250 
251         // if we have void, allow any return type, it will just be ignored
252         if constexpr (!BASE_NS::is_same_v<Ret, void>) {
253             if (!IsCompatibleWith<Ret>(context->GetResult())) {
254                 return false;
255             }
256         }
257 
258         if (!(true && ... && IsCompatibleWith<Args>(*params[Index].value))) {
259             return false;
260         }
261         return true;
262     }
263     static bool Call(const IFunction::Ptr& func)
264     {
265         if constexpr ((true && ... && HasUid_v<PlainType_t<Args>>)) {
266             return Call(func, MakeIndexSequenceFor<Args...>());
267         }
268         return false;
269     }
270 };
271 
272 /**
273  * @brief Check if function is compatible with given signature (The return type and parameter types match).
274  */
275 template<typename FuncSignature>
276 bool IsFunctionCompatible(const IFunction::Ptr& func)
277 {
278     return IsFunctionCompatibleImpl<FuncSignature>::Call(func);
279 }
280 
281 META_END_NAMESPACE()
282 
283 #endif
284