• 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_FUTURE_H
17 #define META_API_FUTURE_H
18 
19 #include <base/containers/type_traits.h>
20 
21 #include <meta/interface/detail/any.h>
22 #include <meta/interface/interface_helpers.h>
23 #include <meta/interface/intf_future.h>
24 
META_BEGIN_NAMESPACE()25 META_BEGIN_NAMESPACE()
26 
27 /**
28  * @brief Callable implementation for continuation functions used with futures.
29  */
30 template<typename Func>
31 class ContinuationFunction : public IntroduceInterfaces<IFutureContinuation> {
32     META_INTERFACE(
33         IntroduceInterfaces<IFutureContinuation>, ContinuationFunction, "f4736552-7365-4c8f-bbe9-a065e2c30382");
34 
35 public:
36     ContinuationFunction(Func func) : func_(BASE_NS::move(func)) {}
37 
38     IAny::Ptr Invoke(const IAny::Ptr& value) override
39     {
40         using Result = BASE_NS::remove_reference_t<decltype(func_(value))>;
41         if constexpr (!BASE_NS::is_same_v<Result, void>) {
42             return IAny::Ptr(new Any<Result>(func_(value)));
43         } else {
44             func_(value);
45             return nullptr;
46         }
47     }
48 
49 private:
50     Func func_;
51 };
52 
53 /**
54  * @brief Create continuation function from callable entity (e.g. lambda).
55  * The callable entity has to take IAny::Ptr as parameter which is the value from the future.
56  */
57 template<typename Func>
CreateContinuation(Func func)58 IFutureContinuation::Ptr CreateContinuation(Func func)
59 {
60     return IFutureContinuation::Ptr(new ContinuationFunction(BASE_NS::move(func)));
61 }
62 
63 template<typename Param>
64 struct ContinuationTypedFuntionTypeImpl {
65     using Type = void(Param);
66 };
67 
68 template<>
69 struct ContinuationTypedFuntionTypeImpl<void> {
70     using Type = void();
71 };
72 
73 template<typename Param>
74 using ContinuationTypedFuntionType = typename ContinuationTypedFuntionTypeImpl<Param>::Type;
75 
76 template<typename T>
77 T VoidResultHelper()
78 {
79     if constexpr (!BASE_NS::is_same_v<T, void>) {
80         return T {};
81     }
82 }
83 
84 template<typename Type>
85 class Future {
86 public:
87     using StateType = IFuture::StateType;
88 
89     Future(IFuture::Ptr fut = nullptr) : fut_(BASE_NS::move(fut)) {}
90     /// @see IFuture::GetState
91     StateType GetState() const
92     {
93         return fut_ ? fut_->GetState() : IFuture::ABANDONED;
94     }
95     /// @see IFuture::Wait
96     StateType Wait() const
97     {
98         return fut_ ? fut_->Wait() : IFuture::ABANDONED;
99     }
100     /// @see IFuture::WaitFor
101     StateType WaitFor(const TimeSpan& time) const
102     {
103         return fut_ ? fut_->WaitFor(time) : IFuture::ABANDONED;
104     }
105     /// @see IFuture::Then
106     IFuture::Ptr Then(const IFutureContinuation::Ptr& func, const BASE_NS::shared_ptr<ITaskQueue>& queue)
107     {
108         return fut_ ? fut_->Then(func, queue) : nullptr;
109     }
110     /**
111      * @see IFuture::Then
112      * @note Runs the continuation function in the same task queue where the future is processed.
113      */
114     IFuture::Ptr Then(const IFutureContinuation::Ptr& func)
115     {
116         return Then(func, nullptr);
117     }
118     /// Helper function which enables specifying the continuation task as a lambda function
119     template<typename Func, typename = EnableIfCanInvokeWithArguments<Func, IFutureContinuation::FunctionType>>
120     auto Then(Func func, const BASE_NS::shared_ptr<ITaskQueue>& queue)
121     {
122         return Future<decltype(func(nullptr))>(fut_->Then(CreateContinuation(func), queue));
123     }
124     /// Helper function which enables specifying the continuation task as a lambda function
125     template<typename Func, typename = EnableIfCanInvokeWithArguments<Func, ContinuationTypedFuntionType<Type>>>
126     auto Then(Func func, const BASE_NS::shared_ptr<ITaskQueue>& queue, int = 0)
127     {
128         using ReturnType = decltype(func(Type {}));
129         return Future<ReturnType>(fut_->Then(CreateContinuation([f = BASE_NS::move(func)](const IAny::Ptr& v) mutable {
130             if (v) {
131                 Type value {};
132                 if (v->GetValue(value)) {
133                     return f(value);
134                 }
135                 CORE_LOG_W("Type mismatch for future then");
136             }
137             // vc2017 chokes on having the if constexpr here directly, so use helper
138             return VoidResultHelper<ReturnType>();
139         }),
140             queue));
141     }
142     /// Helper function which enables specifying the continuation task as a lambda function
143     template<typename Func>
144     auto Then(Func func)
145     {
146         return Then(BASE_NS::move(func), nullptr);
147     }
148     /// Returns the result of the future
149     Type GetResult() const
150     {
151         if (fut_) {
152             return fut_->GetResultOr<Type>(Type {});
153         }
154         return Type {};
155     }
156     /// Returns the underlying IFuture object
157     IFuture::Ptr GetFuture() const
158     {
159         return fut_;
160     }
161     operator IFuture::Ptr() const
162     {
163         return fut_;
164     }
165     explicit operator bool() const
166     {
167         return fut_ != nullptr;
168     }
169 
170 private:
171     IFuture::Ptr fut_;
172 };
173 
174 template<typename Type>
175 Type GetResultOr(const Future<Type>& f, NonDeduced_t<Type> def)
176 {
177     auto fut = f.GetFuture();
178     if (fut) {
179         if (auto p = fut->GetResult()) {
180             return GetValue<Type>(*p, BASE_NS::move(def));
181         }
182     }
183     return BASE_NS::move(def);
184 }
185 
186 META_END_NAMESPACE()
187 
188 #endif
189