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_FUTURE
|
---|
30 | #define LIBCPP_BITS_THREAD_FUTURE
|
---|
31 |
|
---|
32 | #include <__bits/thread/future_common.hpp>
|
---|
33 | #include <__bits/thread/shared_state.hpp>
|
---|
34 | #include <__bits/utility/forward_move.hpp>
|
---|
35 | #include <cassert>
|
---|
36 |
|
---|
37 | namespace std
|
---|
38 | {
|
---|
39 | /**
|
---|
40 | * 30.6.6, class template future:
|
---|
41 | */
|
---|
42 |
|
---|
43 | namespace aux
|
---|
44 | {
|
---|
45 | /**
|
---|
46 | * Note: Because of shared_future, this base class
|
---|
47 | * does implement copy constructor and copy
|
---|
48 | * assignment operator. This means that the
|
---|
49 | * children (std::future) need to delete this
|
---|
50 | * constructor and operator themselves.
|
---|
51 | */
|
---|
52 | template<class R>
|
---|
53 | class future_base
|
---|
54 | {
|
---|
55 | public:
|
---|
56 | future_base() noexcept
|
---|
57 | : state_{nullptr}
|
---|
58 | { /* DUMMY BODY */ }
|
---|
59 |
|
---|
60 | future_base(const future_base& rhs)
|
---|
61 | : state_{rhs.state_}
|
---|
62 | {
|
---|
63 | state_->increment();
|
---|
64 | }
|
---|
65 |
|
---|
66 | future_base(future_base&& rhs) noexcept
|
---|
67 | : state_{move(rhs.state_)}
|
---|
68 | {
|
---|
69 | rhs.state_ = nullptr;
|
---|
70 | }
|
---|
71 |
|
---|
72 | future_base(aux::shared_state<R>* state)
|
---|
73 | : state_{state}
|
---|
74 | {
|
---|
75 | /**
|
---|
76 | * Note: This is a custom non-standard constructor that allows
|
---|
77 | * us to create a future directly from a shared state. This
|
---|
78 | * should never be a problem as aux::shared_state is a private
|
---|
79 | * type and future has no constructor templates.
|
---|
80 | */
|
---|
81 | }
|
---|
82 |
|
---|
83 | virtual ~future_base()
|
---|
84 | {
|
---|
85 | release_state_();
|
---|
86 | }
|
---|
87 |
|
---|
88 | future_base& operator=(const future_base& rhs)
|
---|
89 | {
|
---|
90 | release_state_();
|
---|
91 | state_ = rhs.state_;
|
---|
92 |
|
---|
93 | state_->increment();
|
---|
94 |
|
---|
95 | return *this;
|
---|
96 | }
|
---|
97 |
|
---|
98 | future_base& operator=(future_base&& rhs) noexcept
|
---|
99 | {
|
---|
100 | release_state_();
|
---|
101 | state_ = move(rhs.state_);
|
---|
102 | rhs.state_ = nullptr;
|
---|
103 | }
|
---|
104 |
|
---|
105 | bool valid() const noexcept
|
---|
106 | {
|
---|
107 | return state_ != nullptr;
|
---|
108 | }
|
---|
109 |
|
---|
110 | void wait() const noexcept
|
---|
111 | {
|
---|
112 | assert(state_);
|
---|
113 |
|
---|
114 | state_->wait();
|
---|
115 | }
|
---|
116 |
|
---|
117 | template<class Rep, class Period>
|
---|
118 | future_status
|
---|
119 | wait_for(const chrono::duration<Rep, Period>& rel_time) const
|
---|
120 | {
|
---|
121 | assert(state_);
|
---|
122 |
|
---|
123 | return state_->wait_for(rel_time);
|
---|
124 | }
|
---|
125 |
|
---|
126 | template<class Clock, class Duration>
|
---|
127 | future_status
|
---|
128 | wait_until(
|
---|
129 | const chrono::time_point<Clock, Duration>& abs_time
|
---|
130 | ) const
|
---|
131 | {
|
---|
132 | assert(state_);
|
---|
133 |
|
---|
134 | return state_->wait_until(abs_time);
|
---|
135 | }
|
---|
136 |
|
---|
137 | protected:
|
---|
138 | void release_state_()
|
---|
139 | {
|
---|
140 | if (!state_)
|
---|
141 | return;
|
---|
142 |
|
---|
143 | /**
|
---|
144 | * Note: This is the 'release' move described in
|
---|
145 | * 30.6.4 (5).
|
---|
146 | * Last reference to state -> destroy state.
|
---|
147 | * Decrement refcount of state otherwise.
|
---|
148 | * Will not block, unless all following hold:
|
---|
149 | * 1) State was created by call to std::async.
|
---|
150 | * 2) State is not yet ready.
|
---|
151 | * 3) This was the last reference to the shared state.
|
---|
152 | */
|
---|
153 | if (state_->decrement())
|
---|
154 | {
|
---|
155 | /**
|
---|
156 | * The destroy call handles the special case
|
---|
157 | * when 1) - 3) hold.
|
---|
158 | */
|
---|
159 | state_->destroy();
|
---|
160 | delete state_;
|
---|
161 | state_ = nullptr;
|
---|
162 | }
|
---|
163 | }
|
---|
164 |
|
---|
165 | aux::shared_state<R>* state_;
|
---|
166 | };
|
---|
167 | }
|
---|
168 |
|
---|
169 | template<class R>
|
---|
170 | class shared_future;
|
---|
171 |
|
---|
172 | template<class R>
|
---|
173 | class future: public aux::future_base<R>
|
---|
174 | {
|
---|
175 | friend class shared_future<R>;
|
---|
176 |
|
---|
177 | public:
|
---|
178 | future() noexcept
|
---|
179 | : aux::future_base<R>{}
|
---|
180 | { /* DUMMY BODY */ }
|
---|
181 |
|
---|
182 | future(const future&) = delete;
|
---|
183 |
|
---|
184 | future(future&& rhs) noexcept
|
---|
185 | : aux::future_base<R>{move(rhs.state_)}
|
---|
186 | { /* DUMMY BODY */ }
|
---|
187 |
|
---|
188 | future(aux::shared_state<R>* state)
|
---|
189 | : aux::future_base<R>{state}
|
---|
190 | { /* DUMMY BODY */ }
|
---|
191 |
|
---|
192 | future& operator=(const future&) = delete;
|
---|
193 |
|
---|
194 | future& operator=(future&& rhs) noexcept = default;
|
---|
195 |
|
---|
196 | shared_future<R> share()
|
---|
197 | {
|
---|
198 | return shared_future<R>{move(*this)};
|
---|
199 | }
|
---|
200 |
|
---|
201 | R get()
|
---|
202 | {
|
---|
203 | assert(this->state_);
|
---|
204 |
|
---|
205 | this->wait();
|
---|
206 |
|
---|
207 | if (this->state_->has_exception())
|
---|
208 | this->state_->throw_stored_exception();
|
---|
209 |
|
---|
210 | return move(this->state_->get());
|
---|
211 | }
|
---|
212 | };
|
---|
213 |
|
---|
214 | template<class R>
|
---|
215 | class future<R&>: public aux::future_base<R*>
|
---|
216 | {
|
---|
217 | friend class shared_future<R&>;
|
---|
218 |
|
---|
219 | public:
|
---|
220 | future() noexcept
|
---|
221 | : aux::future_base<R*>{}
|
---|
222 | { /* DUMMY BODY */ }
|
---|
223 |
|
---|
224 | future(const future&) = delete;
|
---|
225 |
|
---|
226 | future(future&& rhs) noexcept
|
---|
227 | : aux::future_base<R*>{move(rhs.state_)}
|
---|
228 | { /* DUMMY BODY */ }
|
---|
229 |
|
---|
230 | future(aux::shared_state<R*>* state)
|
---|
231 | : aux::future_base<R*>{state}
|
---|
232 | { /* DUMMY BODY */ }
|
---|
233 |
|
---|
234 | future& operator=(const future&) = delete;
|
---|
235 |
|
---|
236 | future& operator=(future&& rhs) noexcept = default;
|
---|
237 |
|
---|
238 | shared_future<R&> share()
|
---|
239 | {
|
---|
240 | return shared_future<R&>{move(*this)};
|
---|
241 | }
|
---|
242 |
|
---|
243 | R& get()
|
---|
244 | {
|
---|
245 | assert(this->state_);
|
---|
246 |
|
---|
247 | this->wait();
|
---|
248 |
|
---|
249 | if (this->state_->has_exception())
|
---|
250 | this->state_->throw_stored_exception();
|
---|
251 |
|
---|
252 | assert(this->state_->get());
|
---|
253 | return *this->state_->get();
|
---|
254 | }
|
---|
255 | };
|
---|
256 |
|
---|
257 | template<>
|
---|
258 | class future<void>: public aux::future_base<void>
|
---|
259 | {
|
---|
260 | friend class shared_future<void>;
|
---|
261 |
|
---|
262 | public:
|
---|
263 | future() noexcept
|
---|
264 | : aux::future_base<void>{}
|
---|
265 | { /* DUMMY BODY */ }
|
---|
266 |
|
---|
267 | future(const future&) = delete;
|
---|
268 |
|
---|
269 | future(future&& rhs) noexcept
|
---|
270 | : aux::future_base<void>{move(rhs.state_)}
|
---|
271 | { /* DUMMY BODY */ }
|
---|
272 |
|
---|
273 | future(aux::shared_state<void>* state)
|
---|
274 | : aux::future_base<void>{state}
|
---|
275 | { /* DUMMY BODY */ }
|
---|
276 |
|
---|
277 | future& operator=(const future&) = delete;
|
---|
278 |
|
---|
279 | future& operator=(future&& rhs) noexcept = default;
|
---|
280 |
|
---|
281 | /**
|
---|
282 | * Note: This is just forward declaration, implementation
|
---|
283 | * provided in shared_future.hpp to avoid problems
|
---|
284 | * with incomplete types.
|
---|
285 | */
|
---|
286 | shared_future<void> share();
|
---|
287 |
|
---|
288 | void get()
|
---|
289 | {
|
---|
290 | assert(this->state_);
|
---|
291 |
|
---|
292 | this->wait();
|
---|
293 |
|
---|
294 | if (this->state_->has_exception())
|
---|
295 | this->state_->throw_stored_exception();
|
---|
296 | }
|
---|
297 | };
|
---|
298 | }
|
---|
299 |
|
---|
300 | #endif
|
---|