source: mainline/uspace/lib/cpp/include/__bits/thread/packaged_task.hpp@ e49d0ac

Last change on this file since e49d0ac was b57ba05, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 3 years ago

Update headers in C++ files

  • Property mode set to 100644
File size: 6.2 KB
Line 
1/*
2 * SPDX-FileCopyrightText: 2019 Jaroslav Jindrak
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#ifndef LIBCPP_BITS_THREAD_PACKAGED_TASK
8#define LIBCPP_BITS_THREAD_PACKAGED_TASK
9
10#include <__bits/exception.hpp>
11#include <__bits/functional/function.hpp>
12#include <__bits/memory/allocator_traits.hpp>
13#include <__bits/thread/future.hpp>
14#include <__bits/thread/future_common.hpp>
15#include <__bits/thread/shared_state.hpp>
16#include <type_traits>
17#include <utility>
18
19namespace std
20{
21 /**
22 * 30.6.9, class template packaged_task:
23 */
24
25 /**
26 * Note: The base template is not defined because
27 * we require the template parameter to be
28 * a callable object (e.g. a function). This
29 * is achieved by the R(Args...) specialization
30 * below.
31 */
32 template<class>
33 class packaged_task;
34
35 template<class R, class... Args>
36 class packaged_task<R(Args...)>
37 {
38 public:
39 packaged_task() noexcept
40 : func_{}, state_{}
41 { /* DUMMY BODY */ }
42
43 template<
44 class F, enable_if_t<
45 !is_same_v<
46 decay_t<F>, packaged_task<R(Args...)>
47 >, int
48 > = 0
49 >
50 explicit packaged_task(F&& f)
51 : func_{forward<F>(f)}, state_{new aux::shared_state<R>{}}
52 { /* DUMMY BODY */ }
53
54 template<
55 class F, class Allocator, enable_if_t<
56 is_same_v<
57 decay_t<F>, packaged_task<R(Args...)>
58 >, int
59 > = 0
60 >
61 explicit packaged_task(allocator_arg_t, const Allocator& a, F&& f)
62 : func_{forward<F>(f)}, state_{}
63 {
64 typename allocator_traits<
65 Allocator
66 >::template rebind_alloc<aux::shared_state<R>> rebound{a};
67
68 state_ = rebound.allocate(1);
69 rebound.construct(state_);
70 }
71
72 ~packaged_task()
73 {
74 if (state_)
75 {
76 if (!state_->is_set())
77 {
78 state_->set_exception(make_exception_ptr(
79 future_error{make_error_code(future_errc::broken_promise)}
80 ));
81 state_->mark_set(true);
82 }
83
84 if (state_->decrement())
85 {
86 state_->destroy();
87 delete state_;
88 state_ = nullptr;
89 }
90 }
91 }
92
93 packaged_task(const packaged_task&) = delete;
94 packaged_task& operator=(const packaged_task&) = delete;
95
96 packaged_task(packaged_task&& rhs)
97 : func_{move(rhs.func_)}, state_{move(rhs.state_)}
98 { /* DUMMY BODY */ }
99
100 packaged_task& operator=(packaged_task&& rhs)
101 {
102 if (state_)
103 {
104 if (state_->decrement())
105 {
106 state_->destroy();
107 delete state_;
108 state_ = nullptr;
109 }
110 }
111
112 func_ = move(rhs.func_);
113 state_ = move(rhs.state_);
114 rhs.state_ = nullptr;
115
116 return *this;
117 }
118
119 void swap(packaged_task& other) noexcept
120 {
121 std::swap(func_, other.func_);
122 std::swap(state_, other.state_);
123 }
124
125 bool valid() const noexcept
126 {
127 return state_ != nullptr;
128 }
129
130 future<R> get_future()
131 {
132 if (!state_)
133 throw future_error{make_error_code(future_errc::no_state)};
134
135 state_->increment();
136
137 return future<R>{state_};
138 }
139
140 /**
141 * Note: This is how the signature is in the standard,
142 * should be investigated and verified.
143 */
144 void operator()(Args... args)
145 {
146 if (!state_)
147 throw future_error{make_error_code(future_errc::no_state)};
148 if (state_->is_set())
149 {
150 throw future_error{
151 make_error_code(future_errc::promise_already_satisfied)
152 };
153 }
154
155 try
156 {
157 state_->set_value(invoke(func_, args...));
158 }
159 catch(const exception& __exception)
160 {
161 state_->set_exception(make_exception_ptr(__exception));
162 }
163 }
164
165 void make_ready_at_thread_exit(Args... args)
166 {
167 if (!state_)
168 throw future_error{make_error_code(future_errc::no_state)};
169 if (state_->is_set())
170 {
171 throw future_error{
172 make_error_code(future_errc::promise_already_satisfied)
173 };
174 }
175
176 try
177 {
178 state_->set_value(invoke(func_, args...), false);
179 aux::set_state_value_at_thread_exit(this->state_);
180 }
181 catch(const exception& __exception)
182 {
183 state_->set_exception(make_exception_ptr(__exception), false);
184 aux::set_state_exception_at_thread_exit(this->state_);
185 }
186 }
187
188 void reset()
189 {
190 if (!state_)
191 throw future_error{make_error_code(future_errc::no_state)};
192
193 *this = packaged_task{move(func_)};
194 }
195
196 private:
197 function<R(Args...)> func_;
198
199 aux::shared_state<R>* state_;
200 };
201
202 template<class R, class... Args>
203 void swap(packaged_task<R(Args...)>& lhs, packaged_task<R(Args...)>& rhs) noexcept
204 {
205 lhs.swap(rhs);
206 };
207
208 template<class R, class Alloc>
209 struct uses_allocator<packaged_task<R>, Alloc>: true_type
210 { /* DUMMY BODY */ };
211}
212
213#endif
Note: See TracBrowser for help on using the repository browser.