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 #ifndef META_API_DEFERRED_CALLBACK_H
16 #define META_API_DEFERRED_CALLBACK_H
17 
18 #include <meta/base/interface_traits.h>
19 #include <meta/interface/interface_helpers.h>
20 #include <meta/interface/intf_lifecycle.h>
21 #include <meta/interface/intf_task_queue.h>
22 #include <meta/interface/simple_event.h>
23 
24 META_BEGIN_NAMESPACE();
25 
26 /**
27  * @brief Implementation of ITaskQueueTask for deferred calls.
28  */
29 template<typename Func>
30 class QueueTask : public IntroduceInterfaces<ITaskQueueTask> {
31     META_INTERFACE(IntroduceInterfaces<ITaskQueueTask>, QueueTask, "426c3d10-89e5-4cf7-a314-a5155ede1595");
32 
33 public:
QueueTask(Func func)34     QueueTask(Func func) : func_(BASE_NS::move(func)) {}
35 
Invoke()36     bool Invoke() override
37     {
38         func_();
39         return false;
40     }
41 
42 private:
43     Func func_;
44 };
45 
46 template<typename Func, typename Interface, typename Signature = typename Interface::FunctionType>
47 class DeferredCallable;
48 
49 /**
50  * @brief Implementation of callable for deferred calls.
51  */
52 template<typename Func, typename Interface, typename... Args>
53 class DeferredCallable<Func, Interface, void(Args...)> : public IntroduceInterfaces<Interface> {
54     template<typename F>
55     struct ControlBlock {
ControlBlockControlBlock56         ControlBlock(F f) : func_(BASE_NS::move(f)) {}
57 
CallControlBlock58         void Call(Args... args) const
59         {
60             func_(args...);
61         }
62 
63     private:
64         const F func_;
65     };
66 
67 public:
DeferredCallable(Func func,const ITaskQueue::Ptr & q)68     DeferredCallable(Func func, const ITaskQueue::Ptr& q)
69         : control_(new ControlBlock<Func>(BASE_NS::move(func))), queue_(q)
70     {}
71 
72     /*
73     ~DeferredCallable()
74     {
75         // todo: implement to make sure there is no call in progress any more
76         // either by using the task queue, or with synchronisation primitives
77     }
78     */
Invoke(Args...args)79     void Invoke(Args... args) override
80     {
81         auto q = queue_.lock();
82         if (q) {
83             q->AddTask(ITaskQueueTask::Ptr(new QueueTask([control = BASE_NS::weak_ptr(control_), args...]() mutable {
84                 auto p = control.lock();
85                 if (p) {
86                     p->Call(args...);
87                 }
88             })));
89         }
90     }
91 
92 private:
93     BASE_NS::shared_ptr<ControlBlock<Func>> control_;
94     ITaskQueue::WeakPtr queue_;
95 };
96 
97 /**
98  * @brief Make deferred callable from callable entity (e.g. lambda) by giving callable interface.
99  * @param func Callable entity which is invoked.
100  * @param queue Task queue that the call is posted to.
101  */
102 template<typename CallableInterface, typename Func,
103     typename = EnableIfCanInvokeWithArguments<Func, typename CallableInterface::FunctionType>>
MakeDeferred(Func func,const ITaskQueue::Ptr & queue)104 auto MakeDeferred(Func func, const ITaskQueue::Ptr& queue)
105 {
106     using DType = DeferredCallable<Func, CallableInterface>;
107     return typename DType::Ptr(new DType(BASE_NS::move(func), queue));
108 }
109 META_END_NAMESPACE();
110 #endif
111