/* * Copyright (c) 2024 Huawei Device Co., Ltd. * 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. */ #ifndef META_API_DEFERRED_CALLBACK_H #define META_API_DEFERRED_CALLBACK_H #include #include #include #include #include META_BEGIN_NAMESPACE(); /** * @brief Implementation of ITaskQueueTask for deferred calls. */ template class QueueTask : public IntroduceInterfaces { META_INTERFACE(IntroduceInterfaces, QueueTask, "426c3d10-89e5-4cf7-a314-a5155ede1595"); public: QueueTask(Func func) : func_(BASE_NS::move(func)) {} bool Invoke() override { func_(); return false; } private: Func func_; }; template class DeferredCallable; /** * @brief Implementation of callable for deferred calls. */ template class DeferredCallable : public IntroduceInterfaces { template struct ControlBlock { ControlBlock(F f) : func_(BASE_NS::move(f)) {} void Call(Args... args) const { func_(args...); } private: const F func_; }; public: DeferredCallable(Func func, const ITaskQueue::Ptr& q) : control_(new ControlBlock(BASE_NS::move(func))), queue_(q) {} /* ~DeferredCallable() { // todo: implement to make sure there is no call in progress any more // either by using the task queue, or with synchronisation primitives } */ void Invoke(Args... args) override { auto q = queue_.lock(); if (q) { q->AddTask(ITaskQueueTask::Ptr(new QueueTask([control = BASE_NS::weak_ptr(control_), args...]() mutable { auto p = control.lock(); if (p) { p->Call(args...); } }))); } } private: BASE_NS::shared_ptr> control_; ITaskQueue::WeakPtr queue_; }; /** * @brief Make deferred callable from callable entity (e.g. lambda) by giving callable interface. * @param func Callable entity which is invoked. * @param queue Task queue that the call is posted to. */ template> auto MakeDeferred(Func func, const ITaskQueue::Ptr& queue) { using DType = DeferredCallable; return typename DType::Ptr(new DType(BASE_NS::move(func), queue)); } META_END_NAMESPACE(); #endif