• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 FFRT_API_CPP_FUTURE_H
16 #define FFRT_API_CPP_FUTURE_H
17 #include <memory>
18 #include <optional>
19 #include <chrono>
20 #include "cpp/condition_variable.h"
21 #include "thread.h"
22 
23 namespace ffrt {
24 struct non_copyable {
25 protected:
26     non_copyable() = default;
27     ~non_copyable() = default;
28     non_copyable(const non_copyable&) = delete;
29     non_copyable& operator=(const non_copyable&) = delete;
30 };
31 enum class future_status { ready, timeout, deferred };
32 
33 namespace detail {
34 template <typename Derived>
35 struct shared_state_base : private non_copyable {
waitshared_state_base36     void wait() const noexcept
37     {
38         std::unique_lock lk(this->m_mtx);
39         wait_(lk);
40     }
41 
42     template <typename Rep, typename Period>
wait_forshared_state_base43     future_status wait_for(const std::chrono::duration<Rep, Period>& waitTime) const noexcept
44     {
45         std::unique_lock<mutex> lk(m_mtx);
46         return m_cv.wait_for(lk, waitTime, [this] { return get_derived().has_value(); }) ? future_status::ready :
47             future_status::timeout;
48     }
49 
50     template <typename Clock, typename Duration>
wait_untilshared_state_base51     future_status wait_until(const std::chrono::time_point<Clock, Duration>& tp) const noexcept
52     {
53         std::unique_lock<mutex> lk(m_mtx);
54         return m_cv.wait_until(lk, tp, [this] { return get_derived().has_value(); }) ? future_status::ready :
55             future_status::timeout;
56     }
57 
58 protected:
wait_shared_state_base59     void wait_(std::unique_lock<mutex>& lk) const noexcept
60     {
61         m_cv.wait(lk, [this] { return get_derived().has_value(); });
62     }
63 
64     mutable mutex m_mtx;
65     mutable condition_variable m_cv;
66 
67 private:
get_derivedshared_state_base68     const Derived& get_derived() const
69     {
70         return *static_cast<const Derived*>(this);
71     }
72 };
73 
74 template <typename R>
75 struct shared_state : public shared_state_base<shared_state<R>> {
set_valueshared_state76     void set_value(const R& value) noexcept
77     {
78         std::unique_lock<mutex> lk(this->m_mtx);
79         m_res.emplace(value);
80         this->m_cv.notify_all();
81     }
82 
set_valueshared_state83     void set_value(R&& value) noexcept
84     {
85         std::unique_lock<mutex> lk(this->m_mtx);
86         m_res.emplace(std::move(value));
87         this->m_cv.notify_all();
88     }
89 
getshared_state90     R& get() noexcept
91     {
92         std::unique_lock lk(this->m_mtx);
93         this->wait_(lk);
94         return m_res.value();
95     }
96 
has_valueshared_state97     bool has_value() const noexcept
98     {
99         return m_res.has_value();
100     }
101 
102 private:
103     std::optional<R> m_res;
104 };
105 
106 template <>
107 struct shared_state<void> : public shared_state_base<shared_state<void>> {
108     void set_value() noexcept
109     {
110         std::unique_lock<mutex> lk(this->m_mtx);
111         m_hasValue = true;
112         this->m_cv.notify_all();
113     }
114 
115     void get() noexcept
116     {
117         std::unique_lock lk(this->m_mtx);
118         this->wait_(lk);
119     }
120 
121     bool has_value() const noexcept
122     {
123         return m_hasValue;
124     }
125 
126 private:
127     bool m_hasValue {false};
128 };
129 }; // namespace detail
130 
131 template <typename R>
132 class future : private non_copyable {
133     template <typename>
134     friend struct promise;
135 
136     template <typename>
137     friend struct packaged_task;
138 
139 public:
140     explicit future(const std::shared_ptr<detail::shared_state<R>>& state) noexcept : m_state(state)
141     {
142     }
143 
144     future() noexcept = default;
145 
146     future(future&& fut) noexcept
147     {
148         swap(fut);
149     }
150     future& operator=(future&& fut) noexcept
151     {
152         if (this != &fut) {
153             future tmp(std::move(fut));
154             swap(tmp);
155         }
156         return *this;
157     }
158 
159     bool valid() const noexcept
160     {
161         return m_state != nullptr;
162     }
163 
164     R get() noexcept
165     {
166         auto tmp = std::move(m_state);
167         if constexpr(!std::is_void_v<R>) {
168             return std::move(tmp->get());
169         } else {
170             return tmp->get();
171         }
172     }
173 
174     template <typename Rep, typename Period>
175     future_status wait_for(const std::chrono::duration<Rep, Period>& waitTime) const noexcept
176     {
177         return m_state->wait_for(waitTime);
178     }
179 
180     template <typename Clock, typename Duration>
181     future_status wait_until(const std::chrono::time_point<Clock, Duration>& tp) const noexcept
182     {
183         return m_state->wait_until(tp);
184     }
185 
186     void wait() const noexcept
187     {
188         m_state->wait();
189     }
190 
191     void swap(future<R>& rhs) noexcept
192     {
193         std::swap(m_state, rhs.m_state);
194     }
195 
196 private:
197     std::shared_ptr<detail::shared_state<R>> m_state;
198 };
199 
200 template <typename R>
201 struct promise : private non_copyable {
202     promise() noexcept : m_state {std::make_shared<detail::shared_state<R>>()}
203     {
204     }
205     promise(promise&& p) noexcept
206     {
207         swap(p);
208     }
209     promise& operator=(promise&& p) noexcept
210     {
211         if (this != &p) {
212             promise tmp(std::move(p));
213             swap(tmp);
214         }
215         return *this;
216     }
217 
218     void set_value(const R& value) noexcept
219     {
220         m_state->set_value(value);
221     }
222 
223     void set_value(R&& value) noexcept
224     {
225         m_state->set_value(std::move(value));
226     }
227 
228     future<R> get_future() noexcept
229     {
230         return future<R> {m_state};
231     }
232 
233     void swap(promise<R>& rhs) noexcept
234     {
235         std::swap(m_state, rhs.m_state);
236     }
237 
238 private:
239     std::shared_ptr<detail::shared_state<R>> m_state;
240 };
241 
242 template <>
243 struct promise<void> : private non_copyable {
244     promise() noexcept : m_state {std::make_shared<detail::shared_state<void>>()}
245     {
246     }
247     promise(promise&& p) noexcept
248     {
249         swap(p);
250     }
251     promise& operator=(promise&& p) noexcept
252     {
253         if (this != &p) {
254             promise tmp(std::move(p));
255             swap(tmp);
256         }
257         return *this;
258     }
259 
260     void set_value() noexcept
261     {
262         m_state->set_value();
263     }
264 
265     future<void> get_future() noexcept
266     {
267         return future<void> {m_state};
268     }
269 
270     void swap(promise<void>& rhs) noexcept
271     {
272         std::swap(m_state, rhs.m_state);
273     }
274 
275 private:
276     std::shared_ptr<detail::shared_state<void>> m_state;
277 };
278 
279 template <typename F>
280 struct packaged_task;
281 
282 template <typename R, typename... Args>
283 struct packaged_task<R(Args...)> {
284     packaged_task() noexcept = default;
285 
286     packaged_task(const packaged_task& pt) noexcept
287     {
288         m_fn = pt.m_fn;
289         m_state = pt.m_state;
290     }
291 
292     packaged_task(packaged_task&& pt) noexcept
293     {
294         swap(pt);
295     }
296 
297     packaged_task& operator=(packaged_task&& pt) noexcept
298     {
299         if (this != &pt) {
300             packaged_task tmp(std::move(pt));
301             swap(tmp);
302         }
303         return *this;
304     }
305 
306     template <typename F>
307     explicit packaged_task(F&& f) noexcept
308         : m_fn {std::forward<F>(f)}, m_state {std::make_shared<detail::shared_state<R>>()}
309     {
310     }
311 
312     bool valid() const noexcept
313     {
314         return bool(m_fn) && m_state != nullptr;
315     }
316 
317     future<R> get_future() noexcept
318     {
319         return future<R> {m_state};
320     }
321 
322     void operator()(Args... args)
323     {
324         if constexpr(!std::is_void_v<R>) {
325             m_state->set_value(m_fn(std::forward<Args>(args)...));
326         } else {
327             m_fn(std::forward<Args>(args)...);
328             m_state->set_value();
329         }
330     }
331 
332     void swap(packaged_task& pt) noexcept
333     {
334         std::swap(m_fn, pt.m_fn);
335         std::swap(m_state, pt.m_state);
336     }
337 
338 private:
339     std::function<R(Args...)> m_fn;
340     std::shared_ptr<detail::shared_state<R>> m_state;
341 };
342 
343 template <typename F, typename... Args>
344 future<std::invoke_result_t<std::decay_t<F>, std::decay_t<Args>...>> async(F&& f, Args&& ... args)
345 {
346     using R = std::invoke_result_t<std::decay_t<F>, std::decay_t<Args>...>;
347     packaged_task<R(std::decay_t<Args>...)> pt {std::forward<F>(f)};
348     auto fut {pt.get_future()};
349     auto th = ffrt::thread(std::move(pt), std::forward<Args>(args)...);
350     th.detach();
351     return fut;
352 }
353 } // namespace ffrt
354 #endif
355