// -*- C++ -*- //===--------------------------- future -----------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef _LIBCPP_FUTURE #define _LIBCPP_FUTURE /* future synopsis namespace std { enum class future_errc { broken_promise, future_already_retrieved, promise_already_satisfied, no_state }; enum class launch { any, async, sync }; enum class future_status { ready, timeout, deferred }; template <> struct is_error_code_enum : public true_type { }; error_code make_error_code(future_errc e); error_condition make_error_condition(future_errc e); const error_category& future_category(); class future_error : public logic_error { public: future_error(error_code ec); // exposition only const error_code& code() const throw(); const char* what() const throw(); }; template class promise { public: promise(); template promise(allocator_arg_t, const Allocator& a); promise(promise&& rhs); promise(const promise& rhs) = delete; ~promise(); // assignment promise& operator=(promise&& rhs); promise& operator=(const promise& rhs) = delete; void swap(promise& other); // retrieving the result future get_future(); // setting the result void set_value(const R& r); void set_value(R&& r); void set_exception(exception_ptr p); // setting the result with deferred notification void set_value_at_thread_exit(const R& r); void set_value_at_thread_exit(R&& r); void set_exception_at_thread_exit(exception_ptr p); }; template class promise { public: promise(); template promise(allocator_arg_t, const Allocator& a); promise(promise&& rhs); promise(const promise& rhs) = delete; ~promise(); // assignment promise& operator=(promise&& rhs); promise& operator=(const promise& rhs) = delete; void swap(promise& other); // retrieving the result future get_future(); // setting the result void set_value(R& r); void set_exception(exception_ptr p); // setting the result with deferred notification void set_value_at_thread_exit(R&); void set_exception_at_thread_exit(exception_ptr p); }; template <> class promise { public: promise(); template promise(allocator_arg_t, const Allocator& a); promise(promise&& rhs); promise(const promise& rhs) = delete; ~promise(); // assignment promise& operator=(promise&& rhs); promise& operator=(const promise& rhs) = delete; void swap(promise& other); // retrieving the result future get_future(); // setting the result void set_value(); void set_exception(exception_ptr p); // setting the result with deferred notification void set_value_at_thread_exit(); void set_exception_at_thread_exit(exception_ptr p); }; template void swap(promise& x, promise& y); template struct uses_allocator, Alloc> : public true_type {}; template class future { public: future(); future(future&&); future(const future& rhs) = delete; ~future(); future& operator=(const future& rhs) = delete; future& operator=(future&&); // retrieving the value R get(); // functions to check state bool valid() const; void wait() const; template future_status wait_for(const chrono::duration& rel_time) const; template future_status wait_until(const chrono::time_point& abs_time) const; }; template class future { public: future(); future(future&&); future(const future& rhs) = delete; ~future(); future& operator=(const future& rhs) = delete; future& operator=(future&&); // retrieving the value R& get(); // functions to check state bool valid() const; void wait() const; template future_status wait_for(const chrono::duration& rel_time) const; template future_status wait_until(const chrono::time_point& abs_time) const; }; template <> class future { public: future(); future(future&&); future(const future& rhs) = delete; ~future(); future& operator=(const future& rhs) = delete; future& operator=(future&&); // retrieving the value void get(); // functions to check state bool valid() const; void wait() const; template future_status wait_for(const chrono::duration& rel_time) const; template future_status wait_until(const chrono::time_point& abs_time) const; }; template class shared_future { public: shared_future(); shared_future(const shared_future& rhs); shared_future(future&&); shared_future(shared_future&& rhs); ~shared_future(); shared_future& operator=(const shared_future& rhs); shared_future& operator=(shared_future&& rhs); // retrieving the value const R& get() const; // functions to check state bool valid() const; void wait() const; template future_status wait_for(const chrono::duration& rel_time) const; template future_status wait_until(const chrono::time_point& abs_time) const; }; template class shared_future { public: shared_future(); shared_future(const shared_future& rhs); shared_future(future&&); shared_future(shared_future&& rhs); ~shared_future(); shared_future& operator=(const shared_future& rhs); shared_future& operator=(shared_future&& rhs); // retrieving the value R& get() const; // functions to check state bool valid() const; void wait() const; template future_status wait_for(const chrono::duration& rel_time) const; template future_status wait_until(const chrono::time_point& abs_time) const; }; template <> class shared_future { public: shared_future(); shared_future(const shared_future& rhs); shared_future(future&&); shared_future(shared_future&& rhs); ~shared_future(); shared_future& operator=(const shared_future& rhs); shared_future& operator=(shared_future&& rhs); // retrieving the value void get() const; // functions to check state bool valid() const; void wait() const; template future_status wait_for(const chrono::duration& rel_time) const; template future_status wait_until(const chrono::time_point& abs_time) const; }; template class atomic_future { public: atomic_future(); atomic_future(const atomic_future& rhs); atomic_future(future&&); ~atomic_future(); atomic_future& operator=(const atomic_future& rhs); // retrieving the value const R& get() const; // functions to check state bool valid() const; void wait() const; template future_status wait_for(const chrono::duration& rel_time) const; template future_status wait_until(const chrono::time_point& abs_time) const; }; template class atomic_future { public: atomic_future(); atomic_future(const atomic_future& rhs); atomic_future(future&&); ~atomic_future(); atomic_future& operator=(const atomic_future& rhs); // retrieving the value R& get() const; // functions to check state bool valid() const; void wait() const; template future_status wait_for(const chrono::duration& rel_time) const; template future_status wait_until(const chrono::time_point& abs_time) const; }; template <> class atomic_future { public: atomic_future(); atomic_future(const atomic_future& rhs); atomic_future(future&&); ~atomic_future(); atomic_future& operator=(const atomic_future& rhs); // retrieving the value void get() const; // functions to check state bool valid() const; void wait() const; template future_status wait_for(const chrono::duration& rel_time) const; template future_status wait_until(const chrono::time_point& abs_time) const; }; template future::type> async(F&& f, Args&&... args); template future::type> async(launch policy, F&& f, Args&&... args); template class packaged_task; // undefined template class packaged_task { public: typedef R result_type; // construction and destruction packaged_task(); template explicit packaged_task(F f); template explicit packaged_task(allocator_arg_t, const Allocator& a, F f); explicit packaged_task(R(*f)(ArgTypes...)); template explicit packaged_task(F&& f); template explicit packaged_task(allocator_arg_t, const Allocator& a, F&& f); ~packaged_task(); // no copy packaged_task(packaged_task&) = delete; packaged_task& operator=(packaged_task&) = delete; // move support packaged_task(packaged_task&& other); packaged_task& operator=(packaged_task&& other); void swap(packaged_task& other); explicit operator bool() const; // result retrieval future get_future(); // execution void operator()(ArgTypes... ); void make_ready_at_thread_exit(ArgTypes...); void reset(); }; template void swap(packaged_task&); template struct uses_allocator, Alloc>; } // std */ #include <__config> #include #include #include #include #include <__mutex_base> #include #pragma GCC system_header _LIBCPP_BEGIN_NAMESPACE_STD //enum class future_errc struct future_errc { enum _ { broken_promise, future_already_retrieved, promise_already_satisfied, no_state }; _ __v_; future_errc(_ __v) : __v_(__v) {} operator int() const {return __v_;} }; template <> struct is_error_code_enum : public true_type {}; //enum class launch struct launch { enum _ { any, async, sync }; _ __v_; launch(_ __v) : __v_(__v) {} operator int() const {return __v_;} }; //enum class future_status struct future_status { enum _ { ready, timeout, deferred }; _ __v_; future_status(_ __v) : __v_(__v) {} operator int() const {return __v_;} }; const error_category& future_category(); inline _LIBCPP_INLINE_VISIBILITY error_code make_error_code(future_errc __e) { return error_code(static_cast(__e), future_category()); } inline _LIBCPP_INLINE_VISIBILITY error_condition make_error_condition(future_errc __e) { return error_condition(static_cast(__e), future_category()); } class future_error : public logic_error { error_code __ec_; public: future_error(error_code __ec); const error_code& code() const throw() {return __ec_;} }; class __assoc_sub_state : public __shared_count { protected: exception_ptr __exception_; mutable mutex __mut_; mutable condition_variable __cv_; unsigned __state_; virtual void __on_zero_shared(); public: enum { __constructed = 1, __future_attached = 2, ready = 4, deferred = 8 }; __assoc_sub_state() : __state_(0) {} bool __has_value() const {return (__state_ & __constructed) || (__exception_ != nullptr);} void __set_future_attached() {__state_ |= __future_attached;} bool __has_future_attached() const {return __state_ & __future_attached;} void __make_ready(); bool __is_ready() const {return __state_ & ready;} void set_value(); void set_value_at_thread_exit(); void set_exception(exception_ptr __p); void set_exception_at_thread_exit(exception_ptr __p); void copy(); void wait() const; template future_status wait_for(const chrono::duration<_Rep, _Period>& __rel_time) const; template future_status wait_until(const chrono::time_point<_Clock, _Duration>& __abs_time) const; }; template class __assoc_state : public __assoc_sub_state { typedef __assoc_sub_state base; typedef typename aligned_storage::value>::type _U; protected: _U __value_; virtual void __on_zero_shared(); public: template #ifdef _LIBCPP_MOVE void set_value(_Arg&& __arg); #else void set_value(_Arg& __arg); #endif template #ifdef _LIBCPP_MOVE void set_value_at_thread_exit(_Arg&& __arg); #else void set_value_at_thread_exit(_Arg& __arg); #endif _R move(); typename add_lvalue_reference<_R>::type copy(); }; template void __assoc_state<_R>::__on_zero_shared() { if (this->__state_ & base::__constructed) reinterpret_cast<_R*>(&__value_)->~_R(); delete this; } template template void #ifdef _LIBCPP_MOVE __assoc_state<_R>::set_value(_Arg&& __arg) #else __assoc_state<_R>::set_value(_Arg& __arg) #endif { unique_lock __lk(this->__mut_); if (this->__has_value()) throw future_error(make_error_code(future_errc::promise_already_satisfied)); ::new(&__value_) _R(_STD::forward<_Arg>(__arg)); this->__state_ |= base::__constructed | base::ready; __lk.unlock(); __cv_.notify_all(); } template template void #ifdef _LIBCPP_MOVE __assoc_state<_R>::set_value_at_thread_exit(_Arg&& __arg) #else __assoc_state<_R>::set_value_at_thread_exit(_Arg& __arg) #endif { unique_lock __lk(this->__mut_); if (this->__has_value()) throw future_error(make_error_code(future_errc::promise_already_satisfied)); ::new(&__value_) _R(_STD::forward<_Arg>(__arg)); this->__state_ |= base::__constructed; __thread_local_data->__make_ready_at_thread_exit(this); __lk.unlock(); } template _R __assoc_state<_R>::move() { unique_lock __lk(this->__mut_); while (!this->__is_ready()) this->__cv_.wait(__lk); if (this->__exception_ != nullptr) rethrow_exception(this->__exception_); return _STD::move(*reinterpret_cast<_R*>(&__value_)); } template typename add_lvalue_reference<_R>::type __assoc_state<_R>::copy() { unique_lock __lk(this->__mut_); while (!this->__is_ready()) this->__cv_.wait(__lk); if (this->__exception_ != nullptr) rethrow_exception(this->__exception_); return *reinterpret_cast<_R*>(&__value_); } template class __assoc_state_alloc : public __assoc_state<_R> { typedef __assoc_state<_R> base; _Alloc __alloc_; virtual void __on_zero_shared(); public: explicit __assoc_state_alloc(const _Alloc& __a) : __alloc_(__a) {} }; template void __assoc_state_alloc<_R, _Alloc>::__on_zero_shared() { if (this->__state_ & base::__constructed) reinterpret_cast<_R*>(&this->__value_)->~_R(); typename _Alloc::template rebind<__assoc_state_alloc>::other __a(__alloc_); this->~__assoc_state_alloc(); __a.deallocate(this, 1); } template class __assoc_sub_state_alloc : public __assoc_sub_state { typedef __assoc_sub_state base; _Alloc __alloc_; virtual void __on_zero_shared(); public: explicit __assoc_sub_state_alloc(const _Alloc& __a) : __alloc_(__a) {} }; template void __assoc_sub_state_alloc<_Alloc>::__on_zero_shared() { this->~base(); typename _Alloc::template rebind<__assoc_state_alloc>::other __a(__alloc_); this->~__assoc_sub_state_alloc(); __a.deallocate(this, 1); } template class promise; // future template class future { __assoc_state<_R>* __state_; explicit future(__assoc_state<_R>* __state); template friend class promise; public: future() : __state_(nullptr) {} #ifdef _LIBCPP_MOVE future(future&& __rhs) : __state_(__rhs.__state_) {__rhs.__state_ = nullptr;} future(const future&) = delete; future& operator=(const future&) = delete; future& operator=(future&& __rhs) { future(std::move(__rhs)).swap(*this); return *this; } #else // _LIBCPP_MOVE private: future(const future&); future& operator=(const future&); public: #endif // _LIBCPP_MOVE ~future(); // retrieving the value _R get(); void swap(future& __rhs) {_STD::swap(__state_, __rhs.__state_);} // functions to check state bool valid() const {return __state_ != nullptr;} void wait() const {__state_->wait();} template future_status wait_for(const chrono::duration<_Rep, _Period>& __rel_time) const {return __state_->wait_for(__rel_time);} template future_status wait_until(const chrono::time_point<_Clock, _Duration>& __abs_time) const {return __state_->wait_until(__abs_time);} }; template future<_R>::future(__assoc_state<_R>* __state) : __state_(__state) { if (__state_->__has_future_attached()) throw future_error(make_error_code(future_errc::future_already_retrieved)); __state_->__add_shared(); } template future<_R>::~future() { if (__state_) __state_->__release_shared(); } template _R future<_R>::get() { __assoc_state<_R>* __s = __state_; __state_ = nullptr; return __s->move(); } template class future<_R&> { __assoc_state<_R&>* __state_; explicit future(__assoc_state<_R&>* __state); template friend class promise; public: future() : __state_(nullptr) {} #ifdef _LIBCPP_MOVE future(future&& __rhs) : __state_(__rhs.__state_) {__rhs.__state_ = nullptr;} future(const future&) = delete; future& operator=(const future&) = delete; future& operator=(future&& __rhs) { future(std::move(__rhs)).swap(*this); return *this; } #else // _LIBCPP_MOVE private: future(const future&); future& operator=(const future&); public: #endif // _LIBCPP_MOVE ~future(); // retrieving the value _R& get(); void swap(future& __rhs) {_STD::swap(__state_, __rhs.__state_);} // functions to check state bool valid() const {return __state_ != nullptr;} void wait() const {__state_->wait();} template future_status wait_for(const chrono::duration<_Rep, _Period>& __rel_time) const {return __state_->wait_for(__rel_time);} template future_status wait_until(const chrono::time_point<_Clock, _Duration>& __abs_time) const {return __state_->wait_until(__abs_time);} }; template future<_R&>::future(__assoc_state<_R&>* __state) : __state_(__state) { if (__state_->__has_future_attached()) throw future_error(make_error_code(future_errc::future_already_retrieved)); __state_->__add_shared(); } template future<_R&>::~future() { if (__state_) __state_->__release_shared(); } template _R& future<_R&>::get() { __assoc_state<_R>* __s = __state_; __state_ = nullptr; return __s->copy(); } template <> class future { __assoc_sub_state* __state_; explicit future(__assoc_sub_state* __state); template friend class promise; public: future() : __state_(nullptr) {} #ifdef _LIBCPP_MOVE future(future&& __rhs) : __state_(__rhs.__state_) {__rhs.__state_ = nullptr;} future(const future&) = delete; future& operator=(const future&) = delete; future& operator=(future&& __rhs) { future(std::move(__rhs)).swap(*this); return *this; } #else // _LIBCPP_MOVE private: future(const future&); future& operator=(const future&); public: #endif // _LIBCPP_MOVE ~future(); // retrieving the value void get(); void swap(future& __rhs) {_STD::swap(__state_, __rhs.__state_);} // functions to check state bool valid() const {return __state_ != nullptr;} void wait() const {__state_->wait();} template future_status wait_for(const chrono::duration<_Rep, _Period>& __rel_time) const {return __state_->wait_for(__rel_time);} template future_status wait_until(const chrono::time_point<_Clock, _Duration>& __abs_time) const {return __state_->wait_until(__abs_time);} }; // promise template class promise { __assoc_state<_R>* __state_; public: promise(); template promise(allocator_arg_t, const _Alloc& __a); #ifdef _LIBCPP_MOVE promise(promise&& __rhs) : __state_(__rhs.__state_) {__rhs.__state_ = nullptr;} promise(const promise& __rhs) = delete; #else // _LIBCPP_MOVE private: promise(const promise& __rhs); public: #endif // _LIBCPP_MOVE ~promise(); // assignment #ifdef _LIBCPP_MOVE promise& operator=(promise&& __rhs) { promise(std::move(__rhs)).swap(*this); return *this; } promise& operator=(const promise& __rhs) = delete; #else // _LIBCPP_MOVE private: promise& operator=(const promise& __rhs); public: #endif // _LIBCPP_MOVE void swap(promise& __rhs) {_STD::swap(__state_, __rhs.__state_);} // retrieving the result future<_R> get_future(); // setting the result void set_value(const _R& __r); #ifdef _LIBCPP_MOVE void set_value(_R&& __r); #endif void set_exception(exception_ptr __p); // setting the result with deferred notification void set_value_at_thread_exit(const _R& __r); #ifdef _LIBCPP_MOVE void set_value_at_thread_exit(_R&& __r); #endif void set_exception_at_thread_exit(exception_ptr __p); }; template promise<_R>::promise() : __state_(new __assoc_state<_R>) { } template template promise<_R>::promise(allocator_arg_t, const _Alloc& __a0) { typedef typename _Alloc::template rebind<__assoc_state_alloc<_R, _Alloc> >::other _A2; typedef __allocator_destructor<_A2> _D2; _A2 __a(__a0); unique_ptr<__assoc_state_alloc<_R, _Alloc>, _D2> __hold(__a.allocate(1), _D2(__a, 1)); ::new(__hold.get()) __assoc_state_alloc<_R, _Alloc>(__a0); __state_ = __hold.release(); } template promise<_R>::~promise() { if (__state_) { if (!__state_->__has_value() && __state_->use_count() > 1) __state_->set_exception(make_exception_ptr( future_error(make_error_code(future_errc::broken_promise)) )); __state_->__release_shared(); } } template future<_R> promise<_R>::get_future() { if (__state_ == nullptr) throw future_error(make_error_code(future_errc::no_state)); return future<_R>(__state_); } template void promise<_R>::set_value(const _R& __r) { if (__state_ == nullptr) throw future_error(make_error_code(future_errc::no_state)); __state_->set_value(__r); } #ifdef _LIBCPP_MOVE template void promise<_R>::set_value(_R&& __r) { if (__state_ == nullptr) throw future_error(make_error_code(future_errc::no_state)); __state_->set_value(_STD::move(__r)); } #endif // _LIBCPP_MOVE template void promise<_R>::set_exception(exception_ptr __p) { if (__state_ == nullptr) throw future_error(make_error_code(future_errc::no_state)); __state_->set_exception(__p); } template void promise<_R>::set_value_at_thread_exit(const _R& __r) { if (__state_ == nullptr) throw future_error(make_error_code(future_errc::no_state)); __state_->set_value_at_thread_exit(__r); } #ifdef _LIBCPP_MOVE template void promise<_R>::set_value_at_thread_exit(_R&& __r) { if (__state_ == nullptr) throw future_error(make_error_code(future_errc::no_state)); __state_->set_value_at_thread_exit(_STD::move(__r)); } #endif // _LIBCPP_MOVE template void promise<_R>::set_exception_at_thread_exit(exception_ptr __p) { if (__state_ == nullptr) throw future_error(make_error_code(future_errc::no_state)); __state_->set_exception_at_thread_exit(__p); } // promise template class promise<_R&> { __assoc_state<_R&>* __state_; public: promise(); template promise(allocator_arg_t, const _Allocator& __a); #ifdef _LIBCPP_MOVE promise(promise&& __rhs) : __state_(__rhs.__state_) {__rhs.__state_ = nullptr;} promise(const promise& __rhs) = delete; #else // _LIBCPP_MOVE private: promise(const promise& __rhs); public: #endif // _LIBCPP_MOVE ~promise(); // assignment #ifdef _LIBCPP_MOVE promise& operator=(promise&& __rhs) { promise(std::move(__rhs)).swap(*this); return *this; } promise& operator=(const promise& __rhs) = delete; #else // _LIBCPP_MOVE private: promise& operator=(const promise& __rhs); public: #endif // _LIBCPP_MOVE void swap(promise& __rhs) {_STD::swap(__state_, __rhs.__state_);} // retrieving the result future<_R&> get_future(); // setting the result void set_value(_R& __r); void set_exception(exception_ptr __p); // setting the result with deferred notification void set_value_at_thread_exit(_R&); void set_exception_at_thread_exit(exception_ptr __p); }; template promise<_R&>::promise() : __state_(new __assoc_state<_R&>) { } template template promise<_R&>::promise(allocator_arg_t, const _Alloc& __a0) { typedef typename _Alloc::template rebind<__assoc_state_alloc<_R&, _Alloc> >::other _A2; typedef __allocator_destructor<_A2> _D2; _A2 __a(__a0); unique_ptr<__assoc_state_alloc<_R&, _Alloc>, _D2> __hold(__a.allocate(1), _D2(__a, 1)); ::new(__hold.get()) __assoc_state_alloc<_R&, _Alloc>(__a0); __state_ = __hold.release(); } template promise<_R&>::~promise() { if (__state_) { if (!__state_->__has_value() && __state_->use_count() > 1) __state_->set_exception(make_exception_ptr( future_error(make_error_code(future_errc::broken_promise)) )); __state_->__release_shared(); } } template future<_R&> promise<_R&>::get_future() { if (__state_ == nullptr) throw future_error(make_error_code(future_errc::no_state)); return future<_R&>(__state_); } template void promise<_R&>::set_value(_R& __r) { if (__state_ == nullptr) throw future_error(make_error_code(future_errc::no_state)); __state_->set_value(__r); } template void promise<_R&>::set_exception(exception_ptr __p) { if (__state_ == nullptr) throw future_error(make_error_code(future_errc::no_state)); __state_->set_exception(__p); } template void promise<_R&>::set_value_at_thread_exit(_R& __r) { if (__state_ == nullptr) throw future_error(make_error_code(future_errc::no_state)); __state_->set_value_at_thread_exit(__r); } template void promise<_R&>::set_exception_at_thread_exit(exception_ptr __p) { if (__state_ == nullptr) throw future_error(make_error_code(future_errc::no_state)); __state_->set_exception_at_thread_exit(__p); } // promise template <> class promise { __assoc_sub_state* __state_; public: promise(); template promise(allocator_arg_t, const _Allocator& __a); #ifdef _LIBCPP_MOVE promise(promise&& __rhs) : __state_(__rhs.__state_) {__rhs.__state_ = nullptr;} promise(const promise& __rhs) = delete; #else // _LIBCPP_MOVE private: promise(const promise& __rhs); public: #endif // _LIBCPP_MOVE ~promise(); // assignment #ifdef _LIBCPP_MOVE promise& operator=(promise&& __rhs) { promise(std::move(__rhs)).swap(*this); return *this; } promise& operator=(const promise& __rhs) = delete; #else // _LIBCPP_MOVE private: promise& operator=(const promise& __rhs); public: #endif // _LIBCPP_MOVE void swap(promise& __rhs) {_STD::swap(__state_, __rhs.__state_);} // retrieving the result future get_future(); // setting the result void set_value(); void set_exception(exception_ptr __p); // setting the result with deferred notification void set_value_at_thread_exit(); void set_exception_at_thread_exit(exception_ptr __p); }; template promise::promise(allocator_arg_t, const _Alloc& __a0) { typedef typename _Alloc::template rebind<__assoc_sub_state_alloc<_Alloc> >::other _A2; typedef __allocator_destructor<_A2> _D2; _A2 __a(__a0); unique_ptr<__assoc_sub_state_alloc<_Alloc>, _D2> __hold(__a.allocate(1), _D2(__a, 1)); ::new(__hold.get()) __assoc_sub_state_alloc<_Alloc>(__a0); __state_ = __hold.release(); } template inline _LIBCPP_INLINE_VISIBILITY void swap(promise<_R>& __x, promise<_R>& __y) { __x.swap(__y); } template struct uses_allocator, _Alloc> : public true_type {}; _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP_FUTURE