diff options
Diffstat (limited to 'libcxx')
21 files changed, 1834 insertions, 25 deletions
diff --git a/libcxx/include/future b/libcxx/include/future index abfb77d020f..b75014ac123 100644 --- a/libcxx/include/future +++ b/libcxx/include/future @@ -399,11 +399,6 @@ public: // construction and destruction packaged_task(); template <class F> - explicit packaged_task(F f); - template <class F, class Allocator> - explicit packaged_task(allocator_arg_t, const Allocator& a, F f); - explicit packaged_task(R(*f)(ArgTypes...)); - template <class F> explicit packaged_task(F&& f); template <class F, class Allocator> explicit packaged_task(allocator_arg_t, const Allocator& a, F&& f); @@ -538,7 +533,7 @@ protected: unsigned __state_; virtual void __on_zero_shared(); - + void __sub_wait(unique_lock<mutex>& __lk); public: enum { @@ -556,6 +551,8 @@ public: void __set_future_attached() {__state_ |= __future_attached;} bool __has_future_attached() const {return __state_ & __future_attached;} + void __set_deferred() {__state_ |= deferred;} + void __make_ready(); bool __is_ready() const {return __state_ & ready;} @@ -567,13 +564,15 @@ public: void copy(); - void wait() const; + void wait(); template <class _Rep, class _Period> future_status wait_for(const chrono::duration<_Rep, _Period>& __rel_time) const; template <class _Clock, class _Duration> future_status wait_until(const chrono::time_point<_Clock, _Duration>& __abs_time) const; + + virtual void __execute(); }; template <class _Clock, class _Duration> @@ -581,12 +580,12 @@ future_status __assoc_sub_state::wait_until(const chrono::time_point<_Clock, _Duration>& __abs_time) const { unique_lock<mutex> __lk(__mut_); - while (!(__state_ & (ready | deferred)) && _Clock::now() < __abs_time) + if (__state_ & deferred) + return future_status::deferred; + while (!(__state_ & ready) && _Clock::now() < __abs_time) __cv_.wait_until(__lk, __abs_time); if (__state_ & ready) return future_status::ready; - if (__state_ & deferred) - return future_status::deferred; return future_status::timeout; } @@ -678,8 +677,7 @@ _R __assoc_state<_R>::move() { unique_lock<mutex> __lk(this->__mut_); - while (!this->__is_ready()) - this->__cv_.wait(__lk); + this->__sub_wait(__lk); if (this->__exception_ != nullptr) rethrow_exception(this->__exception_); return _STD::move(*reinterpret_cast<_R*>(&__value_)); @@ -690,8 +688,7 @@ typename add_lvalue_reference<_R>::type __assoc_state<_R>::copy() { unique_lock<mutex> __lk(this->__mut_); - while (!this->__is_ready()) - this->__cv_.wait(__lk); + this->__sub_wait(__lk); if (this->__exception_ != nullptr) rethrow_exception(this->__exception_); return *reinterpret_cast<_R*>(&__value_); @@ -753,8 +750,7 @@ _R& __assoc_state<_R&>::copy() { unique_lock<mutex> __lk(this->__mut_); - while (!this->__is_ready()) - this->__cv_.wait(__lk); + this->__sub_wait(__lk); if (this->__exception_ != nullptr) rethrow_exception(this->__exception_); return *__value_; @@ -829,10 +825,113 @@ __assoc_sub_state_alloc<_Alloc>::__on_zero_shared() __a.deallocate(this, 1); } +template <class _R, class _F> +class __deferred_assoc_state + : public __assoc_state<_R> +{ + typedef __assoc_state<_R> base; + + _F __func_; + +public: +#ifdef _LIBCPP_MOVE + explicit __deferred_assoc_state(_F&& __f); +#endif + + virtual void __execute(); +}; + +#ifdef _LIBCPP_MOVE + +template <class _R, class _F> +inline _LIBCPP_INLINE_VISIBILITY +__deferred_assoc_state<_R, _F>::__deferred_assoc_state(_F&& __f) + : __func_(_STD::forward<_F>(__f)) +{ + this->__set_deferred(); +} + +#endif // _LIBCPP_MOVE + +template <class _R, class _F> +void +__deferred_assoc_state<_R, _F>::__execute() +{ +#ifndef _LIBCPP_NO_EXCEPTIONS + try + { +#endif // _LIBCPP_NO_EXCEPTIONS + this->set_value(__func_()); +#ifndef _LIBCPP_NO_EXCEPTIONS + } + catch (...) + { + this->set_exception(current_exception()); + } +#endif // _LIBCPP_NO_EXCEPTIONS +} + +template <class _F> +class __deferred_assoc_state<void, _F> + : public __assoc_sub_state +{ + typedef __assoc_sub_state base; + + _F __func_; + +public: +#ifdef _LIBCPP_MOVE + explicit __deferred_assoc_state(_F&& __f); +#endif + + virtual void __execute(); +}; + +#ifdef _LIBCPP_MOVE + +template <class _F> +inline _LIBCPP_INLINE_VISIBILITY +__deferred_assoc_state<void, _F>::__deferred_assoc_state(_F&& __f) + : __func_(_STD::forward<_F>(__f)) +{ + this->__set_deferred(); +} + +#endif // _LIBCPP_MOVE + +template <class _F> +void +__deferred_assoc_state<void, _F>::__execute() +{ +#ifndef _LIBCPP_NO_EXCEPTIONS + try + { +#endif // _LIBCPP_NO_EXCEPTIONS + __func_(); + this->set_value(); +#ifndef _LIBCPP_NO_EXCEPTIONS + } + catch (...) + { + this->set_exception(current_exception()); + } +#endif // _LIBCPP_NO_EXCEPTIONS +} + template <class> class promise; // future +template <class _R> class future; + +template <class _R, class _F> +future<_R> +#ifdef _LIBCPP_MOVE +__make_deferred_assoc_state(_F&& __f); +#else +__make_deferred_assoc_state(_F __f); +#endif + template <class _R> class future { @@ -841,6 +940,14 @@ class future explicit future(__assoc_state<_R>* __state); template <class> friend class promise; + + template <class _R1, class _F> +#ifdef _LIBCPP_MOVE + friend future<_R1> __make_deferred_assoc_state(_F&& __f); +#else + friend future<_R1> __make_deferred_assoc_state(_F __f); +#endif + public: future() : __state_(nullptr) {} #ifdef _LIBCPP_MOVE @@ -887,8 +994,14 @@ future<_R>::future(__assoc_state<_R>* __state) if (__state_->__has_future_attached()) throw future_error(make_error_code(future_errc::future_already_retrieved)); __state_->__add_shared(); + __state_->__set_future_attached(); } +struct __release_shared_count +{ + void operator()(__shared_count* p) {p->__release_shared();} +}; + template <class _R> future<_R>::~future() { @@ -900,6 +1013,7 @@ template <class _R> _R future<_R>::get() { + unique_ptr<__shared_count, __release_shared_count> __(__state_); __assoc_state<_R>* __s = __state_; __state_ = nullptr; return __s->move(); @@ -913,6 +1027,14 @@ class future<_R&> explicit future(__assoc_state<_R&>* __state); template <class> friend class promise; + + template <class _R1, class _F> +#ifdef _LIBCPP_MOVE + friend future<_R1> __make_deferred_assoc_state(_F&& __f); +#else + friend future<_R1> __make_deferred_assoc_state(_F __f); +#endif + public: future() : __state_(nullptr) {} #ifdef _LIBCPP_MOVE @@ -959,6 +1081,7 @@ future<_R&>::future(__assoc_state<_R&>* __state) if (__state_->__has_future_attached()) throw future_error(make_error_code(future_errc::future_already_retrieved)); __state_->__add_shared(); + __state_->__set_future_attached(); } template <class _R> @@ -972,6 +1095,7 @@ template <class _R> _R& future<_R&>::get() { + unique_ptr<__shared_count, __release_shared_count> __(__state_); __assoc_state<_R&>* __s = __state_; __state_ = nullptr; return __s->copy(); @@ -985,6 +1109,14 @@ class future<void> explicit future(__assoc_sub_state* __state); template <class> friend class promise; + + template <class _R1, class _F> +#ifdef _LIBCPP_MOVE + friend future<_R1> __make_deferred_assoc_state(_F&& __f); +#else + friend future<_R1> __make_deferred_assoc_state(_F __f); +#endif + public: future() : __state_(nullptr) {} #ifdef _LIBCPP_MOVE @@ -1026,10 +1158,16 @@ public: // promise<R> +template <class> class packaged_task; + template <class _R> class promise { __assoc_state<_R>* __state_; + + explicit promise(nullptr_t) : __state_(nullptr) {} + + template <class> friend class packaged_task; public: promise(); template <class _Alloc> @@ -1186,6 +1324,11 @@ template <class _R> class promise<_R&> { __assoc_state<_R&>* __state_; + + explicit promise(nullptr_t) : __state_(nullptr) {} + + template <class> friend class packaged_task; + public: promise(); template <class _Allocator> @@ -1310,6 +1453,11 @@ template <> class promise<void> { __assoc_sub_state* __state_; + + explicit promise(nullptr_t) : __state_(nullptr) {} + + template <class> friend class packaged_task; + public: promise(); template <class _Allocator> @@ -1374,6 +1522,534 @@ swap(promise<_R>& __x, promise<_R>& __y) template <class _R, class _Alloc> struct uses_allocator<promise<_R>, _Alloc> : public true_type {}; +#ifndef _LIBCPP_HAS_NO_VARIADICS + +// packaged_task + +template<class _Fp> class __packaged_task_base; + +template<class _R, class ..._ArgTypes> +class __packaged_task_base<_R(_ArgTypes...)> +{ + __packaged_task_base(const __packaged_task_base&); + __packaged_task_base& operator=(const __packaged_task_base&); +public: + __packaged_task_base() {} + virtual ~__packaged_task_base() {} + virtual void __move_to(__packaged_task_base*) = 0; + virtual void destroy() = 0; + virtual void destroy_deallocate() = 0; + virtual _R operator()(_ArgTypes&& ...) = 0; +}; + +template<class _FD, class _Alloc, class _FB> class __packaged_task_func; + +template<class _F, class _Alloc, class _R, class ..._ArgTypes> +class __packaged_task_func<_F, _Alloc, _R(_ArgTypes...)> + : public __packaged_task_base<_R(_ArgTypes...)> +{ + __compressed_pair<_F, _Alloc> __f_; +public: + explicit __packaged_task_func(const _F& __f) : __f_(__f) {} + explicit __packaged_task_func(_F&& __f) : __f_(_STD::move(__f)) {} + __packaged_task_func(const _F& __f, const _Alloc& __a) + : __f_(__f, __a) {} + __packaged_task_func(_F&& __f, const _Alloc& __a) + : __f_(_STD::move(__f), __a) {} + virtual void __move_to(__packaged_task_base<_R(_ArgTypes...)>*); + virtual void destroy(); + virtual void destroy_deallocate(); + virtual _R operator()(_ArgTypes&& ... __args); +}; + +template<class _F, class _Alloc, class _R, class ..._ArgTypes> +void +__packaged_task_func<_F, _Alloc, _R(_ArgTypes...)>::__move_to( + __packaged_task_base<_R(_ArgTypes...)>* __p) +{ + ::new (__p) __packaged_task_func(_STD::move(__f_.first()), _STD::move(__f_.second())); +} + +template<class _F, class _Alloc, class _R, class ..._ArgTypes> +void +__packaged_task_func<_F, _Alloc, _R(_ArgTypes...)>::destroy() +{ + __f_.~__compressed_pair<_F, _Alloc>(); +} + +template<class _F, class _Alloc, class _R, class ..._ArgTypes> +void +__packaged_task_func<_F, _Alloc, _R(_ArgTypes...)>::destroy_deallocate() +{ + typedef typename _Alloc::template rebind<__packaged_task_func>::other _A; + _A __a(__f_.second()); + __f_.~__compressed_pair<_F, _Alloc>(); + __a.deallocate(this, 1); +} + +template<class _F, class _Alloc, class _R, class ..._ArgTypes> +_R +__packaged_task_func<_F, _Alloc, _R(_ArgTypes...)>::operator()(_ArgTypes&& ... __arg) +{ + return __invoke(__f_.first(), _STD::forward<_ArgTypes>(__arg)...); +} + +template <class> class __packaged_task_function; + +template<class _R, class ..._ArgTypes> +class __packaged_task_function<_R(_ArgTypes...)> +{ + typedef __packaged_task_base<_R(_ArgTypes...)> __base; + aligned_storage<3*sizeof(void*)>::type __buf_; + __base* __f_; + +public: + typedef _R result_type; + + // construct/copy/destroy: + __packaged_task_function() : __f_(nullptr) {} + template<class _F> + __packaged_task_function(_F&& __f); + template<class _F, class _Alloc> + __packaged_task_function(allocator_arg_t, const _Alloc& __a, _F&& __f); + + __packaged_task_function(__packaged_task_function&&); + __packaged_task_function& operator=(__packaged_task_function&&); + + __packaged_task_function(const __packaged_task_function&) = delete; + __packaged_task_function& operator=(const __packaged_task_function&) = delete; + + ~__packaged_task_function(); + + void swap(__packaged_task_function&); + + _R operator()(_ArgTypes...) const; +}; + +template<class _R, class ..._ArgTypes> +__packaged_task_function<_R(_ArgTypes...)>::__packaged_task_function(__packaged_task_function&& __f) +{ + if (__f.__f_ == nullptr) + __f_ = nullptr; + else if (__f.__f_ == (__base*)&__f.__buf_) + { + __f_ = (__base*)&__buf_; + __f.__f_->__move_to(__f_); + } + else + { + __f_ = __f.__f_; + __f.__f_ = nullptr; + } +} + +template<class _R, class ..._ArgTypes> +template <class _F> +__packaged_task_function<_R(_ArgTypes...)>::__packaged_task_function(_F&& __f) + : __f_(nullptr) +{ + typedef typename remove_reference<_F>::type _FR; + typedef __packaged_task_func<_FR, allocator<_FR>, _R(_ArgTypes...)> _FF; + if (sizeof(_FF) <= sizeof(__buf_)) + { + __f_ = (__base*)&__buf_; + ::new (__f_) _FF(_STD::forward<_F>(__f)); + } + else + { + typedef allocator<_FF> _A; + _A __a; + typedef __allocator_destructor<_A> _D; + unique_ptr<__base, _D> __hold(__a.allocate(1), _D(__a, 1)); + ::new (__hold.get()) _FF(_STD::forward<_F>(__f), allocator<_FR>(__a)); + __f_ = __hold.release(); + } +} + +template<class _R, class ..._ArgTypes> +template <class _F, class _Alloc> +__packaged_task_function<_R(_ArgTypes...)>::__packaged_task_function( + allocator_arg_t, const _Alloc& __a0, _F&& __f) + : __f_(nullptr) +{ + typedef allocator_traits<_Alloc> __alloc_traits; + typedef typename remove_reference<_F>::type _FR; + typedef __packaged_task_func<_FR, _Alloc, _R(_ArgTypes...)> _FF; + if (sizeof(_FF) <= sizeof(__buf_)) + { + __f_ = (__base*)&__buf_; + ::new (__f_) _FF(_STD::forward<_F>(__f)); + } + else + { + typedef typename __alloc_traits::template +#ifndef _LIBCPP_HAS_NO_TEMPLATE_ALIASES + rebind_alloc<_FF> +#else + rebind_alloc<_FF>::other +#endif + _A; + _A __a(__a0); + typedef __allocator_destructor<_A> _D; + unique_ptr<__base, _D> __hold(__a.allocate(1), _D(__a, 1)); + ::new (__hold.get()) _FF(_STD::forward<_F>(__f), _Alloc(__a)); + __f_ = __hold.release(); + } +} + +template<class _R, class ..._ArgTypes> +__packaged_task_function<_R(_ArgTypes...)>& +__packaged_task_function<_R(_ArgTypes...)>::operator=(__packaged_task_function&& __f) +{ + if (__f_ == (__base*)&__buf_) + __f_->destroy(); + else if (__f_) + __f_->destroy_deallocate(); + __f_ = nullptr; + if (__f.__f_ == nullptr) + __f_ = nullptr; + else if (__f.__f_ == (__base*)&__f.__buf_) + { + __f_ = (__base*)&__buf_; + __f.__f_->__move_to(__f_); + } + else + { + __f_ = __f.__f_; + __f.__f_ = nullptr; + } +} + +template<class _R, class ..._ArgTypes> +__packaged_task_function<_R(_ArgTypes...)>::~__packaged_task_function() +{ + if (__f_ == (__base*)&__buf_) + __f_->destroy(); + else if (__f_) + __f_->destroy_deallocate(); +} + +template<class _R, class ..._ArgTypes> +void +__packaged_task_function<_R(_ArgTypes...)>::swap(__packaged_task_function& __f) +{ + if (__f_ == (__base*)&__buf_ && __f.__f_ == (__base*)&__f.__buf_) + { + typename aligned_storage<sizeof(__buf_)>::type __tempbuf; + __base* __t = (__base*)&__tempbuf; + __f_->__move_to(__t); + __f_->destroy(); + __f_ = nullptr; + __f.__f_->__move_to((__base*)&__buf_); + __f.__f_->destroy(); + __f.__f_ = nullptr; + __f_ = (__base*)&__buf_; + __t->__move_to((__base*)&__f.__buf_); + __t->destroy(); + __f.__f_ = (__base*)&__f.__buf_; + } + else if (__f_ == (__base*)&__buf_) + { + __f_->__move_to((__base*)&__f.__buf_); + __f_->destroy(); + __f_ = __f.__f_; + __f.__f_ = (__base*)&__f.__buf_; + } + else if (__f.__f_ == (__base*)&__f.__buf_) + { + __f.__f_->__move_to((__base*)&__buf_); + __f.__f_->destroy(); + __f.__f_ = __f_; + __f_ = (__base*)&__buf_; + } + else + _STD::swap(__f_, __f.__f_); +} + +template<class _R, class ..._ArgTypes> +inline _LIBCPP_INLINE_VISIBILITY +_R +__packaged_task_function<_R(_ArgTypes...)>::operator()(_ArgTypes... __arg) const +{ + return (*__f_)(_STD::forward<_ArgTypes>(__arg)...); +} + +template<class _R, class ..._ArgTypes> +class packaged_task<_R(_ArgTypes...)> +{ +public: + typedef _R result_type; + +private: + __packaged_task_function<result_type(_ArgTypes...)> __f_; + promise<result_type> __p_; + +public: + // construction and destruction + packaged_task() : __p_(nullptr) {} + template <class _F> + explicit packaged_task(_F&& __f) : __f_(_STD::forward<_F>(__f)) {} + template <class _F, class _Allocator> + explicit packaged_task(allocator_arg_t, const _Allocator& __a, _F&& __f) + : __f_(allocator_arg, __a, _STD::forward<_F>(__f)), + __p_(allocator_arg, __a) {} + // ~packaged_task() = default; + + // no copy + packaged_task(packaged_task&) = delete; + packaged_task& operator=(packaged_task&) = delete; + + // move support + packaged_task(packaged_task&& __other) + : __f_(_STD::move(__other.__f_)), __p_(_STD::move(__other.__p_)) {} + packaged_task& operator=(packaged_task&& __other) + { + __f_ = _STD::move(__other.__f_); + __p_ = _STD::move(__other.__p_); + return *this; + } + void swap(packaged_task& __other) + { + __f_.swap(__other.__f_); + __p_.swap(__other.__p_); + } + + //explicit + operator bool() const {return __p_.__state_ != nullptr;} + + // result retrieval + future<result_type> get_future() {return __p_.get_future();} + + // execution + void operator()(_ArgTypes... __args); + void make_ready_at_thread_exit(_ArgTypes... __args); + + void reset(); +}; + +template<class _R, class ..._ArgTypes> +void +packaged_task<_R(_ArgTypes...)>::operator()(_ArgTypes... __args) +{ +#ifndef _LIBCPP_NO_EXCEPTIONS + if (__p_.__state_ == nullptr) + throw future_error(make_error_code(future_errc::no_state)); + if (__p_.__state_->__has_value()) + throw future_error(make_error_code(future_errc::promise_already_satisfied)); + try + { +#endif // _LIBCPP_NO_EXCEPTIONS + __p_.set_value(__f_(_STD::forward<_ArgTypes>(__args)...)); +#ifndef _LIBCPP_NO_EXCEPTIONS + } + catch (...) + { + __p_.set_exception(current_exception()); + } +#endif // _LIBCPP_NO_EXCEPTIONS +} + +template<class _R, class ..._ArgTypes> +void +packaged_task<_R(_ArgTypes...)>::make_ready_at_thread_exit(_ArgTypes... __args) +{ +#ifndef _LIBCPP_NO_EXCEPTIONS + if (__p_.__state_ == nullptr) + throw future_error(make_error_code(future_errc::no_state)); + if (__p_.__state_->__has_value()) + throw future_error(make_error_code(future_errc::promise_already_satisfied)); + try + { +#endif // _LIBCPP_NO_EXCEPTIONS + __p_.set_value_at_thread_exit(__f_(_STD::forward<_ArgTypes>(__args)...)); +#ifndef _LIBCPP_NO_EXCEPTIONS + } + catch (...) + { + __p_.set_exception_at_thread_exit(current_exception()); + } +#endif // _LIBCPP_NO_EXCEPTIONS +} + +template<class _R, class ..._ArgTypes> +void +packaged_task<_R(_ArgTypes...)>::reset() +{ +#ifndef _LIBCPP_NO_EXCEPTIONS + if (!(*this)) + throw future_error(make_error_code(future_errc::no_state)); +#endif // _LIBCPP_NO_EXCEPTIONS + __p_ = promise<result_type>(); +} + +template<class ..._ArgTypes> +class packaged_task<void(_ArgTypes...)> +{ +public: + typedef void result_type; + +private: + __packaged_task_function<result_type(_ArgTypes...)> __f_; + promise<result_type> __p_; + +public: + // construction and destruction + packaged_task() : __p_(nullptr) {} + template <class _F> + explicit packaged_task(_F&& __f) : __f_(_STD::forward<_F>(__f)) {} + template <class _F, class _Allocator> + explicit packaged_task(allocator_arg_t, const _Allocator& __a, _F&& __f) + : __f_(allocator_arg, __a, _STD::forward<_F>(__f)), + __p_(allocator_arg, __a) {} + // ~packaged_task() = default; + + // no copy + packaged_task(packaged_task&) = delete; + packaged_task& operator=(packaged_task&) = delete; + + // move support + packaged_task(packaged_task&& __other) + : __f_(_STD::move(__other.__f_)), __p_(_STD::move(__other.__p_)) {} + packaged_task& operator=(packaged_task&& __other) + { + __f_ = _STD::move(__other.__f_); + __p_ = _STD::move(__other.__p_); + return *this; + } + void swap(packaged_task& __other) + { + __f_.swap(__other.__f_); + __p_.swap(__other.__p_); + } + + //explicit + operator bool() const {return __p_.__state_ != nullptr;} + + // result retrieval + future<result_type> get_future() {return __p_.get_future();} + + // execution + void operator()(_ArgTypes... __args); + void make_ready_at_thread_exit(_ArgTypes... __args); + + void reset(); +}; + +template<class ..._ArgTypes> +void +packaged_task<void(_ArgTypes...)>::operator()(_ArgTypes... __args) +{ +#ifndef _LIBCPP_NO_EXCEPTIONS + if (__p_.__state_ == nullptr) + throw future_error(make_error_code(future_errc::no_state)); + if (__p_.__state_->__has_value()) + throw future_error(make_error_code(future_errc::promise_already_satisfied)); + try + { +#endif // _LIBCPP_NO_EXCEPTIONS + __f_(_STD::forward<_ArgTypes>(__args)...); + __p_.set_value(); +#ifndef _LIBCPP_NO_EXCEPTIONS + } + catch (...) + { + __p_.set_exception(current_exception()); + } +#endif // _LIBCPP_NO_EXCEPTIONS +} + +template<class ..._ArgTypes> +void +packaged_task<void(_ArgTypes...)>::make_ready_at_thread_exit(_ArgTypes... __args) +{ +#ifndef _LIBCPP_NO_EXCEPTIONS + if (__p_.__state_ == nullptr) + throw future_error(make_error_code(future_errc::no_state)); + if (__p_.__state_->__has_value()) + throw future_error(make_error_code(future_errc::promise_already_satisfied)); + try + { +#endif // _LIBCPP_NO_EXCEPTIONS + __f_(_STD::forward<_ArgTypes>(__args)...); + __p_.set_value_at_thread_exit(); +#ifndef _LIBCPP_NO_EXCEPTIONS + } + catch (...) + { + __p_.set_exception_at_thread_exit(current_exception()); + } +#endif // _LIBCPP_NO_EXCEPTIONS +} + +template<class ..._ArgTypes> +void +packaged_task<void(_ArgTypes...)>::reset() +{ +#ifndef _LIBCPP_NO_EXCEPTIONS + if (!(*this)) + throw future_error(make_error_code(future_errc::no_state)); +#endif // _LIBCPP_NO_EXCEPTIONS + __p_ = promise<result_type>(); +} + +template <class _Callable> +inline _LIBCPP_INLINE_VISIBILITY +void +swap(packaged_task<_Callable>& __x, packaged_task<_Callable>& __y) +{ + __x.swap(__y); +} + +template <class _Callable, class _Alloc> +struct uses_allocator<packaged_task<_Callable>, _Alloc> : public true_type {}; + +template <class _R, class _F> +future<_R> +#ifdef _LIBCPP_MOVE +__make_deferred_assoc_state(_F&& __f) +#else +__make_deferred_assoc_state(_F __f) +#endif +{ + unique_ptr<__deferred_assoc_state<_R, _F>, __release_shared_count> + __h(new __deferred_assoc_state<_R, _F>(_STD::forward<_F>(__f))); + return future<_R>(__h.get()); +} + +template <class _F, class... _Args> +future<typename result_of<_F(_Args...)>::type> +async(launch __policy, _F&& __f, _Args&&... __args) +{ + typedef typename result_of<_F(_Args...)>::type _R; + future<_R> __r; + if (__policy == launch::sync) + __r = _STD::__make_deferred_assoc_state<_R>(bind(_STD::forward<_F>(__f), + _STD::forward<_Args>(__args)...)); + else + { + packaged_task<_R()> __pk(bind(_STD::forward<_F>(__f), + _STD::forward<_Args>(__args)...)); + __r = __pk.get_future(); + thread(_STD::move(__pk)).detach(); + } + return __r; +} + +template <class _F, class... _Args> +inline _LIBCPP_INLINE_VISIBILITY +typename enable_if +< + !is_same<typename decay<_F>::type, launch>::value, + future<typename result_of<_F(_Args...)>::type> +>::type +async(_F&& __f, _Args&&... __args) +{ + return async(launch::any, _STD::forward<_F>(__f), + _STD::forward<_Args>(__args)...); +} + +#endif // _LIBCPP_HAS_NO_VARIADICS + _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP_FUTURE diff --git a/libcxx/src/future.cpp b/libcxx/src/future.cpp index 82b9b60ee4e..a0082767122 100644 --- a/libcxx/src/future.cpp +++ b/libcxx/src/future.cpp @@ -124,18 +124,39 @@ void __assoc_sub_state::copy() { unique_lock<mutex> __lk(__mut_); - while (!__is_ready()) - __cv_.wait(__lk); + __sub_wait(__lk); if (__exception_ != nullptr) rethrow_exception(__exception_); } void -__assoc_sub_state::wait() const +__assoc_sub_state::wait() { unique_lock<mutex> __lk(__mut_); - while (!__is_ready()) - __cv_.wait(__lk); + __sub_wait(__lk); +} + +void +__assoc_sub_state::__sub_wait(unique_lock<mutex>& __lk) +{ + if (!__is_ready()) + { + if (__state_ & deferred) + { + __state_ &= ~deferred; + __lk.unlock(); + __execute(); + } + else + while (!__is_ready()) + __cv_.wait(__lk); + } +} + +void +__assoc_sub_state::__execute() +{ + throw future_error(make_error_code(future_errc::no_state)); } future<void>::future(__assoc_sub_state* __state) @@ -144,6 +165,7 @@ future<void>::future(__assoc_sub_state* __state) if (__state_->__has_future_attached()) throw future_error(make_error_code(future_errc::future_already_retrieved)); __state_->__add_shared(); + __state_->__set_future_attached(); } future<void>::~future() @@ -155,9 +177,10 @@ future<void>::~future() void future<void>::get() { + unique_ptr<__shared_count, __release_shared_count> __(__state_); __assoc_sub_state* __s = __state_; __state_ = nullptr; - return __s->copy(); + __s->copy(); } promise<void>::promise() diff --git a/libcxx/test/thread/futures/futures.async/async.pass.cpp b/libcxx/test/thread/futures/futures.async/async.pass.cpp new file mode 100644 index 00000000000..f160ad35aa0 --- /dev/null +++ b/libcxx/test/thread/futures/futures.async/async.pass.cpp @@ -0,0 +1,177 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// <future> + +// template <class F, class... Args> +// future<typename result_of<F(Args...)>::type> +// async(F&& f, Args&&... args); + +// template <class F, class... Args> +// future<typename result_of<F(Args...)>::type> +// async(launch policy, F&& f, Args&&... args); + +#include <future> +#include <memory> +#include <cassert> + +typedef std::chrono::high_resolution_clock Clock; +typedef std::chrono::milliseconds ms; + +int f0() +{ + std::this_thread::sleep_for(ms(200)); + return 3; +} + +int i = 0; + +int& f1() +{ + std::this_thread::sleep_for(ms(200)); + return i; +} + +void f2() +{ + std::this_thread::sleep_for(ms(200)); +} + +std::unique_ptr<int> f3(int i) +{ + std::this_thread::sleep_for(ms(200)); + return std::unique_ptr<int>(new int(i)); +} + +std::unique_ptr<int> f4(std::unique_ptr<int>&& p) +{ + std::this_thread::sleep_for(ms(200)); + return std::move(p); +} + +int main() +{ + { + std::future<int> f = std::async(f0); + std::this_thread::sleep_for(ms(300)); + Clock::time_point t0 = Clock::now(); + assert(f.get() == 3); + Clock::time_point t1 = Clock::now(); + assert(t1-t0 < ms(100)); + } + { + std::future<int> f = std::async(std::launch::async, f0); + std::this_thread::sleep_for(ms(300)); + Clock::time_point t0 = Clock::now(); + assert(f.get() == 3); + Clock::time_point t1 = Clock::now(); + assert(t1-t0 < ms(100)); + } + { + std::future<int> f = std::async(std::launch::any, f0); + std::this_thread::sleep_for(ms(300)); + Clock::time_point t0 = Clock::now(); + assert(f.get() == 3); + Clock::time_point t1 = Clock::now(); + assert(t1-t0 < ms(100)); + } + { + std::future<int> f = std::async(std::launch::sync, f0); + std::this_thread::sleep_for(ms(300)); + Clock::time_point t0 = Clock::now(); + assert(f.get() == 3); + Clock::time_point t1 = Clock::now(); + assert(t1-t0 > ms(100)); + } + + { + std::future<int&> f = std::async(f1); + std::this_thread::sleep_for(ms(300)); + Clock::time_point t0 = Clock::now(); + assert(&f.get() == &i); + Clock::time_point t1 = Clock::now(); + assert(t1-t0 < ms(100)); + } + { + std::future<int&> f = std::async(std::launch::async, f1); + std::this_thread::sleep_for(ms(300)); + Clock::time_point t0 = Clock::now(); + assert(&f.get() == &i); + Clock::time_point t1 = Clock::now(); + assert(t1-t0 < ms(100)); + } + { + std::future<int&> f = std::async(std::launch::any, f1); + std::this_thread::sleep_for(ms(300)); + Clock::time_point t0 = Clock::now(); + assert(&f.get() == &i); + Clock::time_point t1 = Clock::now(); + assert(t1-t0 < ms(100)); + } + { + std::future<int&> f = std::async(std::launch::sync, f1); + std::this_thread::sleep_for(ms(300)); + Clock::time_point t0 = Clock::now(); + assert(&f.get() == &i); + Clock::time_point t1 = Clock::now(); + assert(t1-t0 > ms(100)); + } + + { + std::future<void> f = std::async(f2); + std::this_thread::sleep_for(ms(300)); + Clock::time_point t0 = Clock::now(); + f.get(); + Clock::time_point t1 = Clock::now(); + assert(t1-t0 < ms(100)); + } + { + std::future<void> f = std::async(std::launch::async, f2); + std::this_thread::sleep_for(ms(300)); + Clock::time_point t0 = Clock::now(); + f.get(); + Clock::time_point t1 = Clock::now(); + assert(t1-t0 < ms(100)); + } + { + std::future<void> f = std::async(std::launch::any, f2); + std::this_thread::sleep_for(ms(300)); + Clock::time_point t0 = Clock::now(); + f.get(); + Clock::time_point t1 = Clock::now(); + assert(t1-t0 < ms(100)); + } + { + std::future<void> f = std::async(std::launch::sync, f2); + std::this_thread::sleep_for(ms(300)); + Clock::time_point t0 = Clock::now(); + f.get(); + Clock::time_point t1 = Clock::now(); + assert(t1-t0 > ms(100)); + } + + { + std::future<std::unique_ptr<int>> f = std::async(f3, 3); + std::this_thread::sleep_for(ms(300)); + Clock::time_point t0 = Clock::now(); + assert(*f.get() == 3); + Clock::time_point t1 = Clock::now(); + assert(t1-t0 < ms(100)); + } + + { + std::future<std::unique_ptr<int>> f = + std::async(f4, std::unique_ptr<int>(new int(3))); + std::this_thread::sleep_for(ms(300)); + Clock::time_point t0 = Clock::now(); + assert(*f.get() == 3); + Clock::time_point t1 = Clock::now(); + assert(t1-t0 < ms(100)); + } +} diff --git a/libcxx/test/thread/futures/futures.promise/get_future.pass.cpp b/libcxx/test/thread/futures/futures.promise/get_future.pass.cpp new file mode 100644 index 00000000000..daa2c061fc0 --- /dev/null +++ b/libcxx/test/thread/futures/futures.promise/get_future.pass.cpp @@ -0,0 +1,53 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// <future> + +// class promise<R> + +// future<R> get_future(); + +#include <future> +#include <cassert> + +int main() +{ + { + std::promise<double> p; + std::future<double> f = p.get_future(); + p.set_value(105.5); + assert(f.get() == 105.5); + } + { + std::promise<double> p; + std::future<double> f = p.get_future(); + try + { + f = p.get_future(); + assert(false); + } + catch (const std::future_error& e) + { + assert(e.code() == make_error_code(std::future_errc::future_already_retrieved)); + } + } + { + std::promise<double> p; + std::promise<double> p0 = std::move(p); + try + { + std::future<double> f = p.get_future(); + assert(false); + } + catch (const std::future_error& e) + { + assert(e.code() == make_error_code(std::future_errc::no_state)); + } + } +} diff --git a/libcxx/test/thread/futures/futures.promise/set_lvalue.pass.cpp b/libcxx/test/thread/futures/futures.promise/set_lvalue.pass.cpp index 4ebd8dd25df..8144fa68a7a 100644 --- a/libcxx/test/thread/futures/futures.promise/set_lvalue.pass.cpp +++ b/libcxx/test/thread/futures/futures.promise/set_lvalue.pass.cpp @@ -24,10 +24,10 @@ int main() std::promise<T> p; std::future<T> f = p.get_future(); p.set_value(i); - assert(f.get() == 3); + int& j = f.get(); + assert(j == 3); ++i; - f = p.get_future(); - assert(f.get() == 4); + assert(j == 4); try { p.set_value(i); diff --git a/libcxx/test/thread/futures/futures.tas/futures.task.members/assign_copy.fail.cpp b/libcxx/test/thread/futures/futures.tas/futures.task.members/assign_copy.fail.cpp new file mode 100644 index 00000000000..ea6c4fad8f6 --- /dev/null +++ b/libcxx/test/thread/futures/futures.tas/futures.task.members/assign_copy.fail.cpp @@ -0,0 +1,48 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// <future> + +// class packaged_task<R(ArgTypes...)> + +// packaged_task& operator=(packaged_task&) = delete; + +#include <future> +#include <cassert> + +class A +{ + long data_; + +public: + explicit A(long i) : data_(i) {} + + long operator()(long i, long j) const {return data_ + i + j;} +}; + +int main() +{ + { + std::packaged_task<double(int, char)> p0(A(5)); + std::packaged_task<double(int, char)> p; + p = p0; + assert(!p0); + assert(p); + std::future<double> f = p.get_future(); + p(3, 'a'); + assert(f.get() == 105.0); + } + { + std::packaged_task<double(int, char)> p0; + std::packaged_task<double(int, char)> p; + p = p0; + assert(!p0); + assert(!p); + } +} diff --git a/libcxx/test/thread/futures/futures.tas/futures.task.members/assign_move.pass.cpp b/libcxx/test/thread/futures/futures.tas/futures.task.members/assign_move.pass.cpp new file mode 100644 index 00000000000..c33349d3287 --- /dev/null +++ b/libcxx/test/thread/futures/futures.tas/futures.task.members/assign_move.pass.cpp @@ -0,0 +1,48 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// <future> + +// class packaged_task<R(ArgTypes...)> + +// packaged_task& operator=(packaged_task&& other); + +#include <future> +#include <cassert> + +class A +{ + long data_; + +public: + explicit A(long i) : data_(i) {} + + long operator()(long i, long j) const {return data_ + i + j;} +}; + +int main() +{ + { + std::packaged_task<double(int, char)> p0(A(5)); + std::packaged_task<double(int, char)> p; + p = std::move(p0); + assert(!p0); + assert(p); + std::future<double> f = p.get_future(); + p(3, 'a'); + assert(f.get() == 105.0); + } + { + std::packaged_task<double(int, char)> p0; + std::packaged_task<double(int, char)> p; + p = std::move(p0); + assert(!p0); + assert(!p); + } +} diff --git a/libcxx/test/thread/futures/futures.tas/futures.task.members/ctor_copy.fail.cpp b/libcxx/test/thread/futures/futures.tas/futures.task.members/ctor_copy.fail.cpp new file mode 100644 index 00000000000..b2bcce531cb --- /dev/null +++ b/libcxx/test/thread/futures/futures.tas/futures.task.members/ctor_copy.fail.cpp @@ -0,0 +1,46 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// <future> + +// class packaged_task<R(ArgTypes...)> + +// packaged_task(packaged_task&) = delete; + +#include <future> +#include <cassert> + +class A +{ + long data_; + +public: + explicit A(long i) : data_(i) {} + + long operator()(long i, long j) const {return data_ + i + j;} +}; + +int main() +{ + { + std::packaged_task<double(int, char)> p0(A(5)); + std::packaged_task<double(int, char)> p(p0); + assert(!p0); + assert(p); + std::future<double> f = p.get_future(); + p(3, 'a'); + assert(f.get() == 105.0); + } + { + std::packaged_task<double(int, char)> p0; + std::packaged_task<double(int, char)> p(p0); + assert(!p0); + assert(!p); + } +} diff --git a/libcxx/test/thread/futures/futures.tas/futures.task.members/ctor_default.pass.cpp b/libcxx/test/thread/futures/futures.tas/futures.task.members/ctor_default.pass.cpp new file mode 100644 index 00000000000..4e5fece73ac --- /dev/null +++ b/libcxx/test/thread/futures/futures.tas/futures.task.members/ctor_default.pass.cpp @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// <future> + +// class packaged_task<R(ArgTypes...)> + +// packaged_task(); + +#include <future> +#include <cassert> + +struct A {}; + +int main() +{ + std::packaged_task<A(int, char)> p; + assert(!p); +} diff --git a/libcxx/test/thread/futures/futures.tas/futures.task.members/ctor_func.pass.cpp b/libcxx/test/thread/futures/futures.tas/futures.task.members/ctor_func.pass.cpp new file mode 100644 index 00000000000..de6032153fc --- /dev/null +++ b/libcxx/test/thread/futures/futures.tas/futures.task.members/ctor_func.pass.cpp @@ -0,0 +1,61 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// <future> + +// class packaged_task<R(ArgTypes...)> + +// template <class F> +// explicit packaged_task(F&& f); + +#include <future> +#include <cassert> + +class A +{ + long data_; + +public: + static int n_moves; + static int n_copies; + + explicit A(long i) : data_(i) {} + A(A&& a) : data_(a.data_) {++n_moves; a.data_ = -1;} + A(const A& a) : data_(a.data_) {++n_copies;} + + long operator()(long i, long j) const {return data_ + i + j;} +}; + +int A::n_moves = 0; +int A::n_copies = 0; + +int main() +{ + { + std::packaged_task<double(int, char)> p(A(5)); + assert(p); + std::future<double> f = p.get_future(); + p(3, 'a'); + assert(f.get() == 105.0); + assert(A::n_copies == 0); + assert(A::n_moves > 0); + } + A::n_copies == 0; + A::n_copies = 0; + { + A a(5); + std::packaged_task<double(int, char)> p(a); + assert(p); + std::future<double> f = p.get_future(); + p(3, 'a'); + assert(f.get() == 105.0); + assert(A::n_copies > 0); + assert(A::n_moves > 0); + } +} diff --git a/libcxx/test/thread/futures/futures.tas/futures.task.members/ctor_func_alloc.pass.cpp b/libcxx/test/thread/futures/futures.tas/futures.task.members/ctor_func_alloc.pass.cpp new file mode 100644 index 00000000000..e38446f14dc --- /dev/null +++ b/libcxx/test/thread/futures/futures.tas/futures.task.members/ctor_func_alloc.pass.cpp @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// <future> + +// class packaged_task<R(ArgTypes...)> + +// template <class F, class Allocator> +// explicit packaged_task(allocator_arg_t, const Allocator& a, F&& f); + +#include <future> +#include <cassert> + +#include "../../test_allocator.h" + +class A +{ + long data_; + +public: + static int n_moves; + static int n_copies; + + explicit A(long i) : data_(i) {} + A(A&& a) : data_(a.data_) {++n_moves; a.data_ = -1;} + A(const A& a) : data_(a.data_) {++n_copies;} + + long operator()(long i, long j) const {return data_ + i + j;} +}; + +int A::n_moves = 0; +int A::n_copies = 0; + +int main() +{ + { + std::packaged_task<double(int, char)> p(std::allocator_arg, + test_allocator<A>(), A(5)); + assert(test_alloc_base::count > 0); + assert(p); + std::future<double> f = p.get_future(); + p(3, 'a'); + assert(f.get() == 105.0); + assert(A::n_copies == 0); + assert(A::n_moves > 0); + } + assert(test_alloc_base::count == 0); + A::n_copies == 0; + A::n_copies = 0; + { + A a(5); + std::packaged_task<double(int, char)> p(std::allocator_arg, + test_allocator<A>(), a); + assert(test_alloc_base::count > 0); + assert(p); + std::future<double> f = p.get_future(); + p(3, 'a'); + assert(f.get() == 105.0); + assert(A::n_copies > 0); + assert(A::n_moves > 0); + } + assert(test_alloc_base::count == 0); +} diff --git a/libcxx/test/thread/futures/futures.tas/futures.task.members/ctor_move.pass.cpp b/libcxx/test/thread/futures/futures.tas/futures.task.members/ctor_move.pass.cpp new file mode 100644 index 00000000000..2bc5061d62b --- /dev/null +++ b/libcxx/test/thread/futures/futures.tas/futures.task.members/ctor_move.pass.cpp @@ -0,0 +1,46 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// <future> + +// class packaged_task<R(ArgTypes...)> + +// packaged_task(packaged_task&& other); + +#include <future> +#include <cassert> + +class A +{ + long data_; + +public: + explicit A(long i) : data_(i) {} + + long operator()(long i, long j) const {return data_ + i + j;} +}; + +int main() +{ + { + std::packaged_task<double(int, char)> p0(A(5)); + std::packaged_task<double(int, char)> p = std::move(p0); + assert(!p0); + assert(p); + std::future<double> f = p.get_future(); + p(3, 'a'); + assert(f.get() == 105.0); + } + { + std::packaged_task<double(int, char)> p0; + std::packaged_task<double(int, char)> p = std::move(p0); + assert(!p0); + assert(!p); + } +} diff --git a/libcxx/test/thread/futures/futures.tas/futures.task.members/dtor.pass.cpp b/libcxx/test/thread/futures/futures.tas/futures.task.members/dtor.pass.cpp new file mode 100644 index 00000000000..0f719173c4d --- /dev/null +++ b/libcxx/test/thread/futures/futures.tas/futures.task.members/dtor.pass.cpp @@ -0,0 +1,60 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// <future> + +// class packaged_task<R(ArgTypes...)> + +// ~packaged_task(); + +#include <future> +#include <cassert> + +class A +{ + long data_; + +public: + explicit A(long i) : data_(i) {} + + long operator()(long i, long j) const {return data_ + i + j;} +}; + +void func(std::packaged_task<double(int, char)>& p) +{ +} + +void func2(std::packaged_task<double(int, char)>& p) +{ + p(3, 'a'); +} + +int main() +{ + { + std::packaged_task<double(int, char)> p(A(5)); + std::future<double> f = p.get_future(); + std::thread(func, std::move(p)).detach(); + try + { + double i = f.get(); + assert(false); + } + catch (const std::future_error& e) + { + assert(e.code() == make_error_code(std::future_errc::broken_promise)); + } + } + { + std::packaged_task<double(int, char)> p(A(5)); + std::future<double> f = p.get_future(); + std::thread(func2, std::move(p)).detach(); + assert(f.get() == 105.0); + } +} diff --git a/libcxx/test/thread/futures/futures.tas/futures.task.members/get_future.pass.cpp b/libcxx/test/thread/futures/futures.tas/futures.task.members/get_future.pass.cpp new file mode 100644 index 00000000000..369028e938a --- /dev/null +++ b/libcxx/test/thread/futures/futures.tas/futures.task.members/get_future.pass.cpp @@ -0,0 +1,62 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// <future> + +// class packaged_task<R(ArgTypes...)> + +// future<R> get_future(); + +#include <future> +#include <cassert> + +class A +{ + long data_; + +public: + explicit A(long i) : data_(i) {} + + long operator()(long i, long j) const {return data_ + i + j;} +}; + +int main() +{ + { + std::packaged_task<double(int, char)> p(A(5)); + std::future<double> f = p.get_future(); + p(3, 'a'); + assert(f.get() == 105.0); + } + { + std::packaged_task<double(int, char)> p(A(5)); + std::future<double> f = p.get_future(); + try + { + f = p.get_future(); + assert(false); + } + catch (const std::future_error& e) + { + assert(e.code() == make_error_code(std::future_errc::future_already_retrieved)); + } + } + { + std::packaged_task<double(int, char)> p; + try + { + std::future<double> f = p.get_future(); + assert(false); + } + catch (const std::future_error& e) + { + assert(e.code() == make_error_code(std::future_errc::no_state)); + } + } +} diff --git a/libcxx/test/thread/futures/futures.tas/futures.task.members/make_ready_at_thread_exit.pass.cpp b/libcxx/test/thread/futures/futures.tas/futures.task.members/make_ready_at_thread_exit.pass.cpp new file mode 100644 index 00000000000..11c0f91b54e --- /dev/null +++ b/libcxx/test/thread/futures/futures.tas/futures.task.members/make_ready_at_thread_exit.pass.cpp @@ -0,0 +1,104 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// <future> + +// class packaged_task<R(ArgTypes...)> + +// void make_ready_at_thread_exit(ArgTypes... args); + +#include <future> +#include <cassert> + +class A +{ + long data_; + +public: + explicit A(long i) : data_(i) {} + + long operator()(long i, long j) const + { + if (j == 'z') + throw A(6); + return data_ + i + j; + } +}; + +void func0(std::packaged_task<double(int, char)>& p) +{ + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + p.make_ready_at_thread_exit(3, 'a'); +} + +void func1(std::packaged_task<double(int, char)>& p) +{ + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + p.make_ready_at_thread_exit(3, 'z'); +} + +void func2(std::packaged_task<double(int, char)>& p) +{ + p.make_ready_at_thread_exit(3, 'a'); + try + { + p.make_ready_at_thread_exit(3, 'c'); + } + catch (const std::future_error& e) + { + assert(e.code() == make_error_code(std::future_errc::promise_already_satisfied)); + } +} + +void func3(std::packaged_task<double(int, char)>& p) +{ + try + { + p.make_ready_at_thread_exit(3, 'a'); + } + catch (const std::future_error& e) + { + assert(e.code() == make_error_code(std::future_errc::no_state)); + } +} + +int main() +{ + { + std::packaged_task<double(int, char)> p(A(5)); + std::future<double> f = p.get_future(); + std::thread(func0, std::move(p)).detach(); + assert(f.get() == 105.0); + } + { + std::packaged_task<double(int, char)> p(A(5)); + std::future<double> f = p.get_future(); + std::thread(func1, std::move(p)).detach(); + try + { + f.get(); + assert(false); + } + catch (const A& e) + { + assert(e(3, 'a') == 106); + } + } + { + std::packaged_task<double(int, char)> p(A(5)); + std::future<double> f = p.get_future(); + std::thread(func2, std::move(p)).detach(); + assert(f.get() == 105.0); + } + { + std::packaged_task<double(int, char)> p; + std::thread t(func3, std::move(p)); + t.join(); + } +} diff --git a/libcxx/test/thread/futures/futures.tas/futures.task.members/operator.pass.cpp b/libcxx/test/thread/futures/futures.tas/futures.task.members/operator.pass.cpp new file mode 100644 index 00000000000..fff8467d950 --- /dev/null +++ b/libcxx/test/thread/futures/futures.tas/futures.task.members/operator.pass.cpp @@ -0,0 +1,105 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// <future> + +// class packaged_task<R(ArgTypes...)> + +// void operator()(ArgTypes... args); + +#include <future> +#include <cassert> + +class A +{ + long data_; + +public: + explicit A(long i) : data_(i) {} + + long operator()(long i, long j) const + { + if (j == 'z') + throw A(6); + return data_ + i + j; + } +}; + +void func0(std::packaged_task<double(int, char)>& p) +{ + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + p(3, 'a'); +} + +void func1(std::packaged_task<double(int, char)>& p) +{ + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + p(3, 'z'); +} + +void func2(std::packaged_task<double(int, char)>& p) +{ + p(3, 'a'); + try + { + p(3, 'c'); + } + catch (const std::future_error& e) + { + assert(e.code() == make_error_code(std::future_errc::promise_already_satisfied)); + } +} + +void func3(std::packaged_task<double(int, char)>& p) +{ + try + { + p(3, 'a'); + } + catch (const std::future_error& e) + { + assert(e.code() == make_error_code(std::future_errc::no_state)); + } +} + +int main() +{ + { + std::packaged_task<double(int, char)> p(A(5)); + std::future<double> f = p.get_future(); + std::thread(func0, std::move(p)).detach(); + assert(f.get() == 105.0); + } + { + std::packaged_task<double(int, char)> p(A(5)); + std::future<double> f = p.get_future(); + std::thread(func1, std::move(p)).detach(); + try + { + f.get(); + assert(false); + } + catch (const A& e) + { + assert(e(3, 'a') == 106); + } + } + { + std::packaged_task<double(int, char)> p(A(5)); + std::future<double> f = p.get_future(); + std::thread t(func2, std::move(p)); + assert(f.get() == 105.0); + t.join(); + } + { + std::packaged_task<double(int, char)> p; + std::thread t(func3, std::move(p)); + t.join(); + } +} diff --git a/libcxx/test/thread/futures/futures.tas/futures.task.members/reset.pass.cpp b/libcxx/test/thread/futures/futures.tas/futures.task.members/reset.pass.cpp new file mode 100644 index 00000000000..db9cfbf285f --- /dev/null +++ b/libcxx/test/thread/futures/futures.tas/futures.task.members/reset.pass.cpp @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// <future> + +// class packaged_task<R(ArgTypes...)> + +// void reset(); + +#include <future> +#include <cassert> + +class A +{ + long data_; + +public: + explicit A(long i) : data_(i) {} + + long operator()(long i, long j) const + { + if (j == 'z') + throw A(6); + return data_ + i + j; + } +}; + +int main() +{ + { + std::packaged_task<double(int, char)> p(A(5)); + std::future<double> f = p.get_future(); + p(3, 'a'); + assert(f.get() == 105.0); + p.reset(); + p(4, 'a'); + f = p.get_future(); + assert(f.get() == 106.0); + } + { + std::packaged_task<double(int, char)> p; + try + { + p.reset(); + assert(false); + } + catch (const std::future_error& e) + { + assert(e.code() == make_error_code(std::future_errc::no_state)); + } + } +} diff --git a/libcxx/test/thread/futures/futures.tas/futures.task.members/swap.pass.cpp b/libcxx/test/thread/futures/futures.tas/futures.task.members/swap.pass.cpp new file mode 100644 index 00000000000..c5bd7f59fb8 --- /dev/null +++ b/libcxx/test/thread/futures/futures.tas/futures.task.members/swap.pass.cpp @@ -0,0 +1,48 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// <future> + +// class packaged_task<R(ArgTypes...)> + +// void swap(packaged_task& other); + +#include <future> +#include <cassert> + +class A +{ + long data_; + +public: + explicit A(long i) : data_(i) {} + + long operator()(long i, long j) const {return data_ + i + j;} +}; + +int main() +{ + { + std::packaged_task<double(int, char)> p0(A(5)); + std::packaged_task<double(int, char)> p; + p.swap(p0); + assert(!p0); + assert(p); + std::future<double> f = p.get_future(); + p(3, 'a'); + assert(f.get() == 105.0); + } + { + std::packaged_task<double(int, char)> p0; + std::packaged_task<double(int, char)> p; + p.swap(p0); + assert(!p0); + assert(!p); + } +} diff --git a/libcxx/test/thread/futures/futures.tas/futures.task.nonmembers/swap.pass.cpp b/libcxx/test/thread/futures/futures.tas/futures.task.nonmembers/swap.pass.cpp new file mode 100644 index 00000000000..f6916a5af37 --- /dev/null +++ b/libcxx/test/thread/futures/futures.tas/futures.task.nonmembers/swap.pass.cpp @@ -0,0 +1,50 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// <future> + +// class packaged_task<R(ArgTypes...)> + +// template <class R, class... ArgTypes> +// void +// swap(packaged_task<R(ArgTypes...)>& x, packaged_task<R(ArgTypes...)>& y); + +#include <future> +#include <cassert> + +class A +{ + long data_; + +public: + explicit A(long i) : data_(i) {} + + long operator()(long i, long j) const {return data_ + i + j;} +}; + +int main() +{ + { + std::packaged_task<double(int, char)> p0(A(5)); + std::packaged_task<double(int, char)> p; + swap(p, p0); + assert(!p0); + assert(p); + std::future<double> f = p.get_future(); + p(3, 'a'); + assert(f.get() == 105.0); + } + { + std::packaged_task<double(int, char)> p0; + std::packaged_task<double(int, char)> p; + swap(p, p0); + assert(!p0); + assert(!p); + } +} diff --git a/libcxx/test/thread/futures/futures.tas/futures.task.nonmembers/uses_allocator.pass.cpp b/libcxx/test/thread/futures/futures.tas/futures.task.nonmembers/uses_allocator.pass.cpp new file mode 100644 index 00000000000..3203bf27952 --- /dev/null +++ b/libcxx/test/thread/futures/futures.tas/futures.task.nonmembers/uses_allocator.pass.cpp @@ -0,0 +1,24 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// <future> + +// class packaged_task<R(ArgTypes...)> + +// template <class Callable, class Alloc> +// struct uses_allocator<packaged_task<Callable>, Alloc> +// : true_type { }; + +#include <future> +#include "../../test_allocator.h" + +int main() +{ + static_assert((std::uses_allocator<std::packaged_task<double(int, char)>, test_allocator<int> >::value), ""); +} diff --git a/libcxx/test/thread/futures/futures.tas/types.pass.cpp b/libcxx/test/thread/futures/futures.tas/types.pass.cpp new file mode 100644 index 00000000000..a8569dcd8c5 --- /dev/null +++ b/libcxx/test/thread/futures/futures.tas/types.pass.cpp @@ -0,0 +1,26 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// <future> + +// template<class R, class... ArgTypes> +// class packaged_task<R(ArgTypes...)> +// { +// public: +// typedef R result_type; + +#include <future> +#include <type_traits> + +struct A {}; + +int main() +{ + static_assert((std::is_same<std::packaged_task<A(int, char)>::result_type, A>::value), ""); +} |