source: mainline/uspace/lib/cpp/include/__bits/thread/promise.hpp@ 0f43be5

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 0f43be5 was 0f43be5, checked in by Jaroslav Jindrak <dzejrou@…>, 6 years ago

cpp: implemented promise and future for references

  • Property mode set to 100644
File size: 10.5 KB
Line 
1/*
2 * Copyright (c) 2019 Jaroslav Jindrak
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#ifndef LIBCPP_BITS_THREAD_PROMISE
30#define LIBCPP_BITS_THREAD_PROMISE
31
32#include <__bits/thread/future.hpp>
33#include <__bits/thread/shared_state.hpp>
34#include <__bits/aux.hpp>
35#include <utility>
36
37namespace std
38{
39 /**
40 * 30.6.5, class template promise:
41 */
42
43 namespace aux
44 {
45 template<class R>
46 class promise_base
47 {
48 public:
49 promise_base()
50 : state_{new aux::shared_state<R>{}}
51 { /* DUMMY BODY */ }
52
53 template<class Allocator>
54 promise_base(allocator_arg_t, const Allocator& a)
55 : promise_base{}
56 {
57 // TODO: Use the allocator.
58 }
59
60 promise_base(promise_base&& rhs) noexcept
61 : state_{}
62 {
63 state_ = rhs.state_;
64 rhs.state_ = nullptr;
65 }
66
67 promise_base(const promise_base&) = delete;
68
69 virtual ~promise_base()
70 {
71 this->abandon_state_();
72 }
73
74 promise_base& operator=(promise_base&& rhs) noexcept
75 {
76 abandon_state_();
77 promise_base{move(rhs)}.swap(*this);
78
79 return *this;
80 }
81
82 promise_base& operator=(const promise_base&) = delete;
83
84 void swap(promise_base& other) noexcept
85 {
86 std::swap(state_, other.state_);
87 }
88
89 void set_exception(exception_ptr ptr)
90 {
91 assert(state_);
92
93 state_->set_exception(ptr);
94 }
95
96 void set_exception_at_thread_exit(exception_ptr)
97 {
98 // TODO: No exception handling, no-op at this time.
99 }
100
101 protected:
102 void abandon_state_()
103 {
104 if (!state_)
105 return;
106
107 /**
108 * Note: This is the 'abandon' move described in
109 * 30.6.4 (7).
110 * 1) If state is not ready:
111 * a) Store exception of type future_error with
112 * error condition broken_promise.
113 * b) Mark state as ready.
114 * 2) Release the state.
115 */
116
117 if (!state_->is_set())
118 {
119 // TODO: Store future_error.
120 state_->mark_set(true);
121 }
122
123 if (state_->decrement())
124 {
125 state_->destroy();
126 delete state_;
127 state_ = nullptr;
128 }
129 }
130
131 aux::shared_state<R>* state_;
132 };
133 }
134
135 template<class R>
136 class promise: public aux::promise_base<R>
137 {
138 public:
139 promise()
140 : aux::promise_base<R>{}
141 { /* DUMMY BODY */ }
142
143 template<class Allocator>
144 promise(allocator_arg_t, const Allocator& a)
145 : aux::promise_base<R>{}
146 {
147 // TODO: Use the allocator.
148 }
149
150 promise(promise&& rhs) noexcept
151 : aux::promise_base<R>{move(rhs)}
152 { /* DUMMY BODY */ }
153
154 promise(const promise&) = delete;
155
156 ~promise() override = default;
157
158 promise& operator=(promise&& rhs) noexcept = default;
159
160 promise& operator=(const promise&) = delete;
161
162 future<R> get_future()
163 {
164 return future<R>{this->state_};
165 }
166
167 void set_value(const R& val)
168 {
169 if (!this->state_)
170 throw future_error{make_error_code(future_errc::no_state)};
171 if (this->state_->is_set())
172 {
173 throw future_error{
174 make_error_code(future_errc::promise_already_satisfied)
175 };
176 }
177
178 this->state_->set_value(val, true);
179 }
180
181 void set_value(R&& val)
182 {
183 if (!this->state_)
184 throw future_error{make_error_code(future_errc::no_state)};
185 if (this->state_->is_set())
186 {
187 throw future_error{
188 make_error_code(future_errc::promise_already_satisfied)
189 };
190 }
191
192 this->state_->set_value(forward<R>(val), true);
193 }
194
195 void set_value_at_thread_exit(const R& val)
196 {
197 if (!this->state_)
198 throw future_error{make_error_code(future_errc::no_state)};
199 if (this->state_->is_set())
200 {
201 throw future_error{
202 make_error_code(future_errc::promise_already_satisfied)
203 };
204 }
205
206 this->state_->set_value(val, false);
207 // TODO: schedule it to be set as ready when thread exits
208 }
209
210 void set_value_at_thread_exit(R&& val)
211 {
212 if (!this->state_)
213 throw future_error{make_error_code(future_errc::no_state)};
214 if (this->state_->is_set())
215 {
216 throw future_error{
217 make_error_code(future_errc::promise_already_satisfied)
218 };
219 }
220
221 this->state_->set_value(forward<R>(val), false);
222 // TODO: schedule it to be set as ready when thread exits
223 }
224 };
225
226 template<class R>
227 class promise<R&>: public aux::promise_base<R*>
228 {
229 public:
230 promise()
231 : aux::promise_base<R*>{}
232 { /* DUMMY BODY */ }
233
234 template<class Allocator>
235 promise(allocator_arg_t, const Allocator& a)
236 : aux::promise_base<R*>{}
237 {
238 // TODO: Use the allocator.
239 }
240
241 promise(promise&& rhs) noexcept
242 : aux::promise_base<R*>{move(rhs)}
243 { /* DUMMY BODY */ }
244
245 promise(const promise&) = delete;
246
247 ~promise() override = default;
248
249 promise& operator=(promise&& rhs) noexcept = default;
250
251 promise& operator=(const promise&) = delete;
252
253 future<R&> get_future()
254 {
255 return future<R&>{this->state_};
256 }
257
258 void set_value(R& val)
259 {
260 if (!this->state_)
261 throw future_error{make_error_code(future_errc::no_state)};
262 if (this->state_->is_set())
263 {
264 throw future_error{
265 make_error_code(future_errc::promise_already_satisfied)
266 };
267 }
268
269 this->state_->set_value(&val, true);
270 }
271
272 void set_value_at_thread_exit(R& val)
273 {
274 if (!this->state_)
275 throw future_error{make_error_code(future_errc::no_state)};
276 if (this->state_->is_set())
277 {
278 throw future_error{
279 make_error_code(future_errc::promise_already_satisfied)
280 };
281 }
282
283 this->state_->set_value(&val, false);
284 // TODO: schedule it to be set as ready when thread exits
285 }
286 };
287
288 template<>
289 class promise<void>: public aux::promise_base<void>
290 {
291 public:
292 promise()
293 : aux::promise_base<void>{}
294 { /* DUMMY BODY */ }
295
296 template<class Allocator>
297 promise(allocator_arg_t, const Allocator& a)
298 : aux::promise_base<void>{}
299 {
300 // TODO: Use the allocator.
301 }
302
303 promise(promise&& rhs) noexcept
304 : aux::promise_base<void>{move(rhs)}
305 { /* DUMMY BODY */ }
306
307 promise(const promise&) = delete;
308
309 ~promise() override = default;
310
311 promise& operator=(promise&& rhs) noexcept = default;
312
313 promise& operator=(const promise&) = delete;
314
315 future<void> get_future()
316 {
317 return future<void>{this->state_};
318 }
319
320 void set_value()
321 {
322 if (!this->state_)
323 throw future_error{make_error_code(future_errc::no_state)};
324 if (this->state_->is_set())
325 {
326 throw future_error{
327 make_error_code(future_errc::promise_already_satisfied)
328 };
329 }
330
331 this->state_->set_value();
332 }
333 };
334
335 template<class R>
336 void swap(promise<R>& lhs, promise<R>& rhs) noexcept
337 {
338 lhs.swap(rhs);
339 }
340
341 template<class R, class Alloc>
342 struct uses_allocator<promise<R>, Alloc>: true_type
343 { /* DUMMY BODY */ };
344}
345
346#endif
Note: See TracBrowser for help on using the repository browser.