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         {
79             std::unique_lock<mutex> lk(this->m_mtx);
80             m_res.emplace(value);
81         }
82         this->m_cv.notify_all();
83     }
84 
set_valueshared_state85     void set_value(R&& value) noexcept
86     {
87         {
88             std::unique_lock<mutex> lk(this->m_mtx);
89             m_res.emplace(std::move(value));
90         }
91         this->m_cv.notify_all();
92     }
93 
getshared_state94     R& get() noexcept
95     {
96         std::unique_lock lk(this->m_mtx);
97         this->wait_(lk);
98         return m_res.value();
99     }
100 
has_valueshared_state101     bool has_value() const noexcept
102     {
103         return m_res.has_value();
104     }
105 
106 private:
107     std::optional<R> m_res;
108 };
109 
110 template <>
111 struct shared_state<void> : public shared_state_base<shared_state<void>> {
112     void set_value() noexcept
113     {
114         {
115             std::unique_lock<mutex> lk(this->m_mtx);
116             m_hasValue = true;
117         }
118         this->m_cv.notify_all();
119     }
120 
121     void get() noexcept
122     {
123         std::unique_lock lk(this->m_mtx);
124         this->wait_(lk);
125     }
126 
127     bool has_value() const noexcept
128     {
129         return m_hasValue;
130     }
131 
132 private:
133     bool m_hasValue {false};
134 };
135 }; // namespace detail
136 
137 template <typename R>
138 class future : private non_copyable {
139     template <typename>
140     friend struct promise;
141 
142     template <typename>
143     friend struct packaged_task;
144 
145 public:
146     explicit future(const std::shared_ptr<detail::shared_state<R>>& state) noexcept : m_state(state)
147     {
148     }
149 
150     future() noexcept = default;
151 
152     future(future&& fut) noexcept
153     {
154         swap(fut);
155     }
156     future& operator=(future&& fut) noexcept
157     {
158         if (this != &fut) {
159             future tmp(std::move(fut));
160             swap(tmp);
161         }
162         return *this;
163     }
164 
165     bool valid() const noexcept
166     {
167         return m_state != nullptr;
168     }
169 
170     R get() noexcept
171     {
172         auto tmp = std::move(m_state);
173         if constexpr(!std::is_void_v<R>) {
174             return std::move(tmp->get());
175         } else {
176             return tmp->get();
177         }
178     }
179 
180     template <typename Rep, typename Period>
181     future_status wait_for(const std::chrono::duration<Rep, Period>& waitTime) const noexcept
182     {
183         return m_state->wait_for(waitTime);
184     }
185 
186     template <typename Clock, typename Duration>
187     future_status wait_until(const std::chrono::time_point<Clock, Duration>& tp) const noexcept
188     {
189         return m_state->wait_until(tp);
190     }
191 
192     void wait() const noexcept
193     {
194         m_state->wait();
195     }
196 
197     void swap(future<R>& rhs) noexcept
198     {
199         std::swap(m_state, rhs.m_state);
200     }
201 
202 private:
203     std::shared_ptr<detail::shared_state<R>> m_state;
204 };
205 
206 template <typename R>
207 struct promise : private non_copyable {
208     promise() noexcept : m_state {std::make_shared<detail::shared_state<R>>()}
209     {
210     }
211     promise(promise&& p) noexcept
212     {
213         swap(p);
214     }
215     promise& operator=(promise&& p) noexcept
216     {
217         if (this != &p) {
218             promise tmp(std::move(p));
219             swap(tmp);
220         }
221         return *this;
222     }
223 
224     void set_value(const R& value) noexcept
225     {
226         m_state->set_value(value);
227     }
228 
229     void set_value(R&& value) noexcept
230     {
231         m_state->set_value(std::move(value));
232     }
233 
234     future<R> get_future() noexcept
235     {
236         return future<R> {m_state};
237     }
238 
239     void swap(promise<R>& rhs) noexcept
240     {
241         std::swap(m_state, rhs.m_state);
242     }
243 
244 private:
245     std::shared_ptr<detail::shared_state<R>> m_state;
246 };
247 
248 template <>
249 struct promise<void> : private non_copyable {
250     promise() noexcept : m_state {std::make_shared<detail::shared_state<void>>()}
251     {
252     }
253     promise(promise&& p) noexcept
254     {
255         swap(p);
256     }
257     promise& operator=(promise&& p) noexcept
258     {
259         if (this != &p) {
260             promise tmp(std::move(p));
261             swap(tmp);
262         }
263         return *this;
264     }
265 
266     void set_value() noexcept
267     {
268         m_state->set_value();
269     }
270 
271     future<void> get_future() noexcept
272     {
273         return future<void> {m_state};
274     }
275 
276     void swap(promise<void>& rhs) noexcept
277     {
278         std::swap(m_state, rhs.m_state);
279     }
280 
281 private:
282     std::shared_ptr<detail::shared_state<void>> m_state;
283 };
284 
285 template <typename F>
286 struct packaged_task;
287 
288 template <typename R, typename... Args>
289 struct packaged_task<R(Args...)> {
290     packaged_task() noexcept = default;
291 
292     packaged_task(const packaged_task& pt) noexcept
293     {
294         m_fn = pt.m_fn;
295         m_state = pt.m_state;
296     }
297 
298     packaged_task(packaged_task&& pt) noexcept
299     {
300         swap(pt);
301     }
302 
303     packaged_task& operator=(packaged_task&& pt) noexcept
304     {
305         if (this != &pt) {
306             packaged_task tmp(std::move(pt));
307             swap(tmp);
308         }
309         return *this;
310     }
311 
312     template <typename F>
313     explicit packaged_task(F&& f) noexcept
314         : m_fn {std::forward<F>(f)}, m_state {std::make_shared<detail::shared_state<R>>()}
315     {
316     }
317 
318     bool valid() const noexcept
319     {
320         return bool(m_fn) && m_state != nullptr;
321     }
322 
323     future<R> get_future() noexcept
324     {
325         return future<R> {m_state};
326     }
327 
328     void operator()(Args... args)
329     {
330         if constexpr(!std::is_void_v<R>) {
331             m_state->set_value(m_fn(std::forward<Args>(args)...));
332         } else {
333             m_fn(std::forward<Args>(args)...);
334             m_state->set_value();
335         }
336     }
337 
338     void swap(packaged_task& pt) noexcept
339     {
340         std::swap(m_fn, pt.m_fn);
341         std::swap(m_state, pt.m_state);
342     }
343 
344 private:
345     std::function<R(Args...)> m_fn;
346     std::shared_ptr<detail::shared_state<R>> m_state;
347 };
348 
349 template <typename F, typename... Args>
350 future<std::invoke_result_t<std::decay_t<F>, std::decay_t<Args>...>> async(F&& f, Args&& ... args)
351 {
352     using R = std::invoke_result_t<std::decay_t<F>, std::decay_t<Args>...>;
353     packaged_task<R(std::decay_t<Args>...)> pt {std::forward<F>(f)};
354     auto fut {pt.get_future()};
355     auto th = ffrt::thread(std::move(pt), std::forward<Args>(args)...);
356     th.detach();
357     return fut;
358 }
359 } // namespace ffrt
360 #endif
361