1 // Copyright (c) 2007-2013 Hartmut Kaiser 2 // 3 // Distributed under the Boost Software License, Version 1.0. (See accompanying 4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5 6 #if !defined(HPX_LCOS_LOCAL_PROMISE_MAR_01_2012_0121PM) 7 #define HPX_LCOS_LOCAL_PROMISE_MAR_01_2012_0121PM 8 9 #include <hpx/config.hpp> 10 #include <hpx/lcos_fwd.hpp> 11 #include <hpx/lcos/detail/future_data.hpp> 12 #include <hpx/lcos/future.hpp> 13 #include <hpx/throw_exception.hpp> 14 #include <hpx/traits/future_access.hpp> 15 #include <hpx/util/allocator_deleter.hpp> 16 #include <hpx/util/unused.hpp> 17 18 #include <boost/intrusive_ptr.hpp> 19 #include <boost/utility/swap.hpp> 20 21 #include <exception> 22 #include <memory> 23 #include <utility> 24 #include <type_traits> 25 26 namespace hpx { namespace lcos { namespace local 27 { 28 namespace detail 29 { 30 template <typename R, typename SharedState> 31 class promise_base 32 { 33 typedef SharedState shared_state_type; 34 typedef typename shared_state_type::init_no_addref init_no_addref; 35 36 public: promise_base()37 promise_base() 38 : shared_state_(new shared_state_type(init_no_addref{}), false) 39 , future_retrieved_(false) 40 {} 41 42 template <typename Allocator> promise_base(std::allocator_arg_t,Allocator const & a)43 promise_base(std::allocator_arg_t, Allocator const& a) 44 : shared_state_() 45 , future_retrieved_(false) 46 { 47 typedef typename traits::detail::shared_state_allocator< 48 SharedState, Allocator 49 >::type allocator_shared_state_type; 50 51 typedef typename 52 std::allocator_traits<Allocator>::template 53 rebind_alloc<allocator_shared_state_type> 54 other_allocator; 55 typedef std::allocator_traits<other_allocator> traits; 56 typedef std::unique_ptr< 57 allocator_shared_state_type, 58 util::allocator_deleter<other_allocator> 59 > unique_pointer; 60 61 other_allocator alloc(a); 62 unique_pointer p (traits::allocate(alloc, 1), 63 util::allocator_deleter<other_allocator>{alloc}); 64 65 traits::construct(alloc, p.get(), init_no_addref{}, alloc); 66 shared_state_.reset(p.release(), false); 67 } 68 promise_base(promise_base && other)69 promise_base(promise_base&& other) noexcept 70 : shared_state_(std::move(other.shared_state_)) 71 , future_retrieved_(other.future_retrieved_) 72 { 73 other.shared_state_ = nullptr; 74 other.future_retrieved_ = false; 75 } 76 ~promise_base()77 ~promise_base() 78 { 79 check_abandon_shared_state( 80 "local::detail::promise_base<R>::~promise_base()"); 81 } 82 operator =(promise_base && other)83 promise_base& operator=(promise_base&& other) noexcept 84 { 85 if (this != &other) 86 { 87 this->check_abandon_shared_state( 88 "local::detail::promise_base<R>::operator="); 89 90 shared_state_ = std::move(other.shared_state_); 91 future_retrieved_ = other.future_retrieved_; 92 93 other.shared_state_ = nullptr; 94 other.future_retrieved_ = false; 95 } 96 return *this; 97 } 98 swap(promise_base & other)99 void swap(promise_base& other) noexcept 100 { 101 boost::swap(shared_state_, other.shared_state_); 102 boost::swap(future_retrieved_, other.future_retrieved_); 103 } 104 valid() const105 bool valid() const noexcept 106 { 107 return shared_state_ != nullptr; 108 } 109 get_future(error_code & ec=throws)110 future<R> get_future(error_code& ec = throws) 111 { 112 if (future_retrieved_) 113 { 114 HPX_THROWS_IF(ec, future_already_retrieved, 115 "local::detail::promise_base<R>::get_future", 116 "future has already been retrieved from this promise"); 117 return future<R>(); 118 } 119 120 if (shared_state_ == nullptr) 121 { 122 HPX_THROWS_IF(ec, no_state, 123 "local::detail::promise_base<R>::get_future", 124 "this promise has no valid shared state"); 125 return future<R>(); 126 } 127 128 future_retrieved_ = true; 129 return traits::future_access<future<R> >::create(shared_state_); 130 } 131 132 template <typename... Ts> 133 typename std::enable_if< 134 std::is_constructible<R, Ts&&...>::value || 135 std::is_void<R>::value 136 >::type set_value(Ts &&...ts)137 set_value(Ts&&... ts) 138 { 139 if (shared_state_ == nullptr) 140 { 141 HPX_THROW_EXCEPTION(no_state, 142 "local::detail::promise_base<R>::set_value", 143 "this promise has no valid shared state"); 144 return; 145 } 146 147 if (shared_state_->is_ready()) 148 { 149 HPX_THROW_EXCEPTION(promise_already_satisfied, 150 "local::detail::promise_base<R>::set_value", 151 "result has already been stored for this promise"); 152 return; 153 } 154 155 shared_state_->set_value(std::forward<Ts>(ts)...); 156 } 157 158 template <typename T> set_exception(T && value)159 void set_exception(T&& value) 160 { 161 if (shared_state_ == nullptr) 162 { 163 HPX_THROW_EXCEPTION(no_state, 164 "local::detail::promise_base<R>::set_exception", 165 "this promise has no valid shared state"); 166 return; 167 } 168 169 if (shared_state_->is_ready()) 170 { 171 HPX_THROW_EXCEPTION(promise_already_satisfied, 172 "local::detail::promise_base<R>::set_exception", 173 "result has already been stored for this promise"); 174 return; 175 } 176 177 shared_state_->set_exception(std::forward<T>(value)); 178 } 179 180 protected: check_abandon_shared_state(const char * fun)181 void check_abandon_shared_state(const char* fun) 182 { 183 if (shared_state_ != nullptr && future_retrieved_ && 184 !shared_state_->is_ready()) 185 { 186 shared_state_->set_error(broken_promise, fun, 187 "abandoning not ready shared state"); 188 } 189 } 190 191 boost::intrusive_ptr<shared_state_type> shared_state_; 192 bool future_retrieved_; 193 }; 194 } 195 196 /////////////////////////////////////////////////////////////////////////// 197 template <typename R> 198 class promise : public detail::promise_base<R> 199 { 200 typedef detail::promise_base<R> base_type; 201 202 public: 203 // Effects: constructs a promise object and a shared state. promise()204 promise() 205 : base_type() 206 {} 207 208 // Effects: constructs a promise object and a shared state. The 209 // constructor uses the allocator a to allocate the memory for the 210 // shared state. 211 template <typename Allocator> promise(std::allocator_arg_t,Allocator const & a)212 promise(std::allocator_arg_t, Allocator const& a) 213 : base_type(std::allocator_arg, a) 214 {} 215 216 // Effects: constructs a new promise object and transfers ownership of 217 // the shared state of other (if any) to the newly- 218 // constructed object. 219 // Postcondition: other has no shared state. promise(promise && other)220 promise(promise&& other) noexcept 221 : base_type(std::move(other)) 222 {} 223 224 // Effects: Abandons any shared state ~promise()225 ~promise() 226 {} 227 228 // Effects: Abandons any shared state (30.6.4) and then as if 229 // promise(std::move(other)).swap(*this). 230 // Returns: *this. operator =(promise && other)231 promise& operator=(promise&& other) noexcept 232 { 233 base_type::operator=(std::move(other)); 234 return *this; 235 } 236 237 // Effects: Exchanges the shared state of *this and other. 238 // Postcondition: *this has the shared state (if any) that other had 239 // prior to the call to swap. other has the shared state 240 // (if any) that *this had prior to the call to swap. swap(promise & other)241 void swap(promise& other) noexcept 242 { 243 base_type::swap(other); 244 } 245 246 // Returns: true only if *this refers to a shared state. valid() const247 bool valid() const noexcept 248 { 249 return base_type::valid(); 250 } 251 252 // Returns: A future<R> object with the same shared state as *this. 253 // Throws: future_error if *this has no shared state or if get_future 254 // has already been called on a promise with the same shared 255 // state as *this. 256 // Error conditions: 257 // - future_already_retrieved if get_future has already been called 258 // on a promise with the same shared state as *this. 259 // - no_state if *this has no shared state. get_future(error_code & ec=throws)260 future<R> get_future(error_code& ec = throws) 261 { 262 return base_type::get_future(ec); 263 } 264 265 // Effects: atomically stores the value r in the shared state and makes 266 // that state ready (30.6.4). 267 // Throws: 268 // - future_error if its shared state already has a stored value or 269 // exception, or 270 // - any exception thrown by the constructor selected to copy an 271 // object of R. 272 // Error conditions: 273 // - promise_already_satisfied if its shared state already has a 274 // stored value or exception. 275 // - no_state if *this has no shared state. set_value(R const & r)276 void set_value(R const& r) 277 { 278 base_type::set_value(r); 279 } 280 281 // Effects: atomically stores the value r in the shared state and makes 282 // that state ready (30.6.4). 283 // Throws: 284 // - future_error if its shared state already has a stored value or 285 // exception, or 286 // - any exception thrown by the constructor selected to move an 287 // object of R. 288 // Error conditions: 289 // - promise_already_satisfied if its shared state already has a 290 // stored value or exception. 291 // - no_state if *this has no shared state. set_value(R && r)292 void set_value(R&& r) 293 { 294 base_type::set_value(std::move(r)); 295 } 296 297 // Extension (see wg21.link/P0319) 298 // 299 // Effects: atomically initializes the stored value as if 300 // direct-non-list-initializing an object of type R with the 301 // arguments forward<Args>(args)...) in the shared state and 302 // makes that state ready. 303 // Requires: 304 // - std::is_constructible<R, Ts&&...>::value == true 305 // Throws: 306 // - future_error if its shared state already has a stored value or 307 // exception, or 308 // - any exception thrown by the constructor selected to move an 309 // object of R. 310 // Error conditions: 311 // - promise_already_satisfied if its shared state already has a 312 // stored value or exception. 313 // - no_state if *this has no shared state. 314 template <typename ... Ts> set_value(Ts &&...ts)315 void set_value(Ts&&... ts) 316 { 317 base_type::set_value(std::forward<Ts>(ts)...); 318 } 319 320 // Effects: atomically stores the exception pointer p in the shared 321 // state and makes that state ready (30.6.4). 322 // Throws: future_error if its shared state already has a stored value 323 // or exception. 324 // Error conditions: 325 // - promise_already_satisfied if its shared state already has a 326 // stored value or exception. 327 // - no_state if *this has no shared state. set_exception(std::exception_ptr e)328 void set_exception(std::exception_ptr e) 329 { 330 base_type::set_exception(std::move(e)); 331 } 332 }; 333 334 template <typename R> 335 class promise<R&> : public detail::promise_base<R&> 336 { 337 typedef detail::promise_base<R&> base_type; 338 339 public: 340 // Effects: constructs a promise object and a shared state. promise()341 promise() 342 : base_type() 343 {} 344 345 // Effects: constructs a promise object and a shared state. The 346 // constructor uses the allocator a to allocate the memory for the 347 // shared state. 348 template <typename Allocator> promise(std::allocator_arg_t,Allocator const & a)349 promise(std::allocator_arg_t, Allocator const& a) 350 : base_type(std::allocator_arg, a) 351 {} 352 353 // Effects: constructs a new promise object and transfers ownership of 354 // the shared state of other (if any) to the newly- 355 // constructed object. 356 // Postcondition: other has no shared state. promise(promise && other)357 promise(promise&& other) noexcept 358 : base_type(std::move(other)) 359 {} 360 361 // Effects: Abandons any shared state ~promise()362 ~promise() 363 {} 364 365 // Effects: Abandons any shared state (30.6.4) and then as if 366 // promise(std::move(other)).swap(*this). 367 // Returns: *this. operator =(promise && other)368 promise& operator=(promise&& other) noexcept 369 { 370 base_type::operator=(std::move(other)); 371 return *this; 372 } 373 374 // Effects: Exchanges the shared state of *this and other. 375 // Postcondition: *this has the shared state (if any) that other had 376 // prior to the call to swap. other has the shared state 377 // (if any) that *this had prior to the call to swap. swap(promise & other)378 void swap(promise& other) noexcept 379 { 380 base_type::swap(other); 381 } 382 383 // Returns: true only if *this refers to a shared state. valid() const384 bool valid() const noexcept 385 { 386 return base_type::valid(); 387 } 388 389 // Returns: A future<R> object with the same shared state as *this. 390 // Throws: future_error if *this has no shared state or if get_future 391 // has already been called on a promise with the same shared 392 // state as *this. 393 // Error conditions: 394 // - future_already_retrieved if get_future has already been called 395 // on a promise with the same shared state as *this. 396 // - no_state if *this has no shared state. get_future(error_code & ec=throws)397 future<R&> get_future(error_code& ec = throws) 398 { 399 return base_type::get_future(ec); 400 } 401 402 // Effects: atomically stores the value r in the shared state and makes 403 // that state ready (30.6.4). 404 // Throws: 405 // - future_error if its shared state already has a stored value or 406 // exception. 407 // Error conditions: 408 // - promise_already_satisfied if its shared state already has a 409 // stored value or exception. 410 // - no_state if *this has no shared state. set_value(R & r)411 void set_value(R& r) 412 { 413 base_type::set_value(r); 414 } 415 416 // Effects: atomically stores the exception pointer p in the shared 417 // state and makes that state ready (30.6.4). 418 // Throws: future_error if its shared state already has a stored value 419 // or exception. 420 // Error conditions: 421 // - promise_already_satisfied if its shared state already has a 422 // stored value or exception. 423 // - no_state if *this has no shared state. set_exception(std::exception_ptr e)424 void set_exception(std::exception_ptr e) 425 { 426 base_type::set_exception(std::move(e)); 427 } 428 }; 429 430 template <> 431 class promise<void> : public detail::promise_base<void> 432 { 433 typedef detail::promise_base<void> base_type; 434 435 public: 436 // Effects: constructs a promise object and a shared state. promise()437 promise() 438 : base_type() 439 {} 440 441 // Effects: constructs a promise object and a shared state. The 442 // constructor uses the allocator a to allocate the memory for the 443 // shared state. 444 template <typename Allocator> promise(std::allocator_arg_t,Allocator const & a)445 promise(std::allocator_arg_t, Allocator const& a) 446 : base_type(std::allocator_arg, a) 447 {} 448 449 // Effects: constructs a new promise object and transfers ownership of 450 // the shared state of other (if any) to the newly- 451 // constructed object. 452 // Postcondition: other has no shared state. promise(promise && other)453 promise(promise&& other) noexcept 454 : base_type(std::move(other)) 455 {} 456 457 // Effects: Abandons any shared state ~promise()458 ~promise() 459 {} 460 461 // Effects: Abandons any shared state (30.6.4) and then as if 462 // promise(std::move(other)).swap(*this). 463 // Returns: *this. operator =(promise && other)464 promise& operator=(promise&& other) noexcept 465 { 466 base_type::operator=(std::move(other)); 467 return *this; 468 } 469 470 // Effects: Exchanges the shared state of *this and other. 471 // Postcondition: *this has the shared state (if any) that other had 472 // prior to the call to swap. other has the shared state 473 // (if any) that *this had prior to the call to swap. swap(promise & other)474 void swap(promise& other) noexcept 475 { 476 base_type::swap(other); 477 } 478 479 // Returns: true only if *this refers to a shared state. valid() const480 bool valid() const noexcept 481 { 482 return base_type::valid(); 483 } 484 485 // Returns: A future<R> object with the same shared state as *this. 486 // Throws: future_error if *this has no shared state or if get_future 487 // has already been called on a promise with the same shared 488 // state as *this. 489 // Error conditions: 490 // - future_already_retrieved if get_future has already been called 491 // on a promise with the same shared state as *this. 492 // - no_state if *this has no shared state. get_future(error_code & ec=throws)493 future<void> get_future(error_code& ec = throws) 494 { 495 return base_type::get_future(ec); 496 } 497 498 // Effects: atomically stores the value r in the shared state and makes 499 // that state ready (30.6.4). 500 // Throws: 501 // - future_error if its shared state already has a stored value or 502 // exception, or 503 // - any exception thrown by the constructor selected to copy an 504 // object of R. 505 // Error conditions: 506 // - promise_already_satisfied if its shared state already has a 507 // stored value or exception. 508 // - no_state if *this has no shared state. set_value()509 void set_value() 510 { 511 base_type::set_value(hpx::util::unused); 512 } 513 514 // Effects: atomically stores the exception pointer p in the shared 515 // state and makes that state ready (30.6.4). 516 // Throws: future_error if its shared state already has a stored value 517 // or exception. 518 // Error conditions: 519 // - promise_already_satisfied if its shared state already has a 520 // stored value or exception. 521 // - no_state if *this has no shared state. set_exception(std::exception_ptr e)522 void set_exception(std::exception_ptr e) 523 { 524 base_type::set_exception(std::move(e)); 525 } 526 }; 527 528 template <typename R> swap(promise<R> & x,promise<R> & y)529 void swap(promise<R>& x, promise<R>& y) noexcept 530 { 531 x.swap(y); 532 } 533 }}} 534 535 namespace std 536 { 537 // Requires: Allocator shall be an allocator (17.6.3.5) 538 template <typename R, typename Allocator> 539 struct uses_allocator<hpx::lcos::local::promise<R>, Allocator> 540 : std::true_type 541 {}; 542 } 543 544 #endif 545