diff --git a/include/future b/include/future index a8b02a6d..abfb77d0 100644 --- a/include/future +++ b/include/future @@ -576,6 +576,28 @@ public: wait_until(const chrono::time_point<_Clock, _Duration>& __abs_time) const; }; +template +future_status +__assoc_sub_state::wait_until(const chrono::time_point<_Clock, _Duration>& __abs_time) const +{ + unique_lock __lk(__mut_); + while (!(__state_ & (ready | deferred)) && _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; +} + +template +inline _LIBCPP_INLINE_VISIBILITY +future_status +__assoc_sub_state::wait_for(const chrono::duration<_Rep, _Period>& __rel_time) const +{ + return wait_until(chrono::monotonic_clock::now() + __rel_time); +} + template class __assoc_state : public __assoc_sub_state @@ -675,6 +697,69 @@ __assoc_state<_R>::copy() return *reinterpret_cast<_R*>(&__value_); } +template +class __assoc_state<_R&> + : public __assoc_sub_state +{ + typedef __assoc_sub_state base; + typedef _R* _U; +protected: + _U __value_; + + virtual void __on_zero_shared(); +public: + + void set_value(_R& __arg); + void set_value_at_thread_exit(_R& __arg); + + _R& copy(); +}; + +template +void +__assoc_state<_R&>::__on_zero_shared() +{ + delete this; +} + +template +void +__assoc_state<_R&>::set_value(_R& __arg) +{ + unique_lock __lk(this->__mut_); + if (this->__has_value()) + throw future_error(make_error_code(future_errc::promise_already_satisfied)); + __value_ = &__arg; + this->__state_ |= base::__constructed | base::ready; + __lk.unlock(); + __cv_.notify_all(); +} + +template +void +__assoc_state<_R&>::set_value_at_thread_exit(_R& __arg) +{ + unique_lock __lk(this->__mut_); + if (this->__has_value()) + throw future_error(make_error_code(future_errc::promise_already_satisfied)); + __value_ = &__arg; + this->__state_ |= base::__constructed; + __thread_local_data->__make_ready_at_thread_exit(this); + __lk.unlock(); +} + +template +_R& +__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 *__value_; +} + template class __assoc_state_alloc : public __assoc_state<_R> @@ -699,6 +784,28 @@ __assoc_state_alloc<_R, _Alloc>::__on_zero_shared() __a.deallocate(this, 1); } +template +class __assoc_state_alloc<_R&, _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() +{ + 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 @@ -717,7 +824,7 @@ void __assoc_sub_state_alloc<_Alloc>::__on_zero_shared() { this->~base(); - typename _Alloc::template rebind<__assoc_state_alloc>::other __a(__alloc_); + typename _Alloc::template rebind<__assoc_sub_state_alloc>::other __a(__alloc_); this->~__assoc_sub_state_alloc(); __a.deallocate(this, 1); } @@ -865,7 +972,7 @@ template _R& future<_R&>::get() { - __assoc_state<_R>* __s = __state_; + __assoc_state<_R&>* __s = __state_; __state_ = nullptr; return __s->copy(); } diff --git a/test/thread/futures/futures.promise/alloc_ctor.pass.cpp b/test/thread/futures/futures.promise/alloc_ctor.pass.cpp new file mode 100644 index 00000000..da7353cf --- /dev/null +++ b/test/thread/futures/futures.promise/alloc_ctor.pass.cpp @@ -0,0 +1,49 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// class promise + +// template +// promise(allocator_arg_t, const Allocator& a); + +#include +#include + +#include "../test_allocator.h" + +int main() +{ + assert(test_alloc_base::count == 0); + { + std::promise p(std::allocator_arg, test_allocator()); + assert(test_alloc_base::count == 1); + std::future f = p.get_future(); + assert(test_alloc_base::count == 1); + assert(f.valid()); + } + assert(test_alloc_base::count == 0); + { + std::promise p(std::allocator_arg, test_allocator()); + assert(test_alloc_base::count == 1); + std::future f = p.get_future(); + assert(test_alloc_base::count == 1); + assert(f.valid()); + } + assert(test_alloc_base::count == 0); + { + std::promise p(std::allocator_arg, test_allocator()); + assert(test_alloc_base::count == 1); + std::future f = p.get_future(); + assert(test_alloc_base::count == 1); + assert(f.valid()); + } + assert(test_alloc_base::count == 0); +} diff --git a/test/thread/futures/futures.promise/copy_assign.fail.cpp b/test/thread/futures/futures.promise/copy_assign.fail.cpp new file mode 100644 index 00000000..04aefe80 --- /dev/null +++ b/test/thread/futures/futures.promise/copy_assign.fail.cpp @@ -0,0 +1,87 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// class promise + +// promise& operator=(const promise& rhs) = delete; + +#include +#include + +#include "../test_allocator.h" + +int main() +{ + assert(test_alloc_base::count == 0); + { + std::promise p0(std::allocator_arg, test_allocator()); + std::promise p(std::allocator_arg, test_allocator()); + assert(test_alloc_base::count == 2); + p = p0; + assert(test_alloc_base::count == 1); + std::future f = p.get_future(); + assert(test_alloc_base::count == 1); + assert(f.valid()); + try + { + f = p0.get_future(); + assert(false); + } + catch (const std::future_error& e) + { + assert(e.code() == make_error_code(std::future_errc::no_state)); + } + assert(test_alloc_base::count == 1); + } + assert(test_alloc_base::count == 0); + { + std::promise p0(std::allocator_arg, test_allocator()); + std::promise p(std::allocator_arg, test_allocator()); + assert(test_alloc_base::count == 2); + p = p0; + assert(test_alloc_base::count == 1); + std::future f = p.get_future(); + assert(test_alloc_base::count == 1); + assert(f.valid()); + try + { + f = p0.get_future(); + assert(false); + } + catch (const std::future_error& e) + { + assert(e.code() == make_error_code(std::future_errc::no_state)); + } + assert(test_alloc_base::count == 1); + } + assert(test_alloc_base::count == 0); + { + std::promise p0(std::allocator_arg, test_allocator()); + std::promise p(std::allocator_arg, test_allocator()); + assert(test_alloc_base::count == 2); + p = p0; + assert(test_alloc_base::count == 1); + std::future f = p.get_future(); + assert(test_alloc_base::count == 1); + assert(f.valid()); + try + { + f = p0.get_future(); + assert(false); + } + catch (const std::future_error& e) + { + assert(e.code() == make_error_code(std::future_errc::no_state)); + } + assert(test_alloc_base::count == 1); + } + assert(test_alloc_base::count == 0); +} diff --git a/test/thread/futures/futures.promise/copy_ctor.fail.cpp b/test/thread/futures/futures.promise/copy_ctor.fail.cpp new file mode 100644 index 00000000..d295ad3b --- /dev/null +++ b/test/thread/futures/futures.promise/copy_ctor.fail.cpp @@ -0,0 +1,81 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// class promise + +// promise(const promise&) = delete; + +#include +#include + +#include "../test_allocator.h" + +int main() +{ + assert(test_alloc_base::count == 0); + { + std::promise p0(std::allocator_arg, test_allocator()); + std::promise p(p0); + assert(test_alloc_base::count == 1); + std::future f = p.get_future(); + assert(test_alloc_base::count == 1); + assert(f.valid()); + try + { + f = p0.get_future(); + assert(false); + } + catch (const std::future_error& e) + { + assert(e.code() == make_error_code(std::future_errc::no_state)); + } + assert(test_alloc_base::count == 1); + } + assert(test_alloc_base::count == 0); + { + std::promise p0(std::allocator_arg, test_allocator()); + std::promise p(p0); + assert(test_alloc_base::count == 1); + std::future f = p.get_future(); + assert(test_alloc_base::count == 1); + assert(f.valid()); + try + { + f = p0.get_future(); + assert(false); + } + catch (const std::future_error& e) + { + assert(e.code() == make_error_code(std::future_errc::no_state)); + } + assert(test_alloc_base::count == 1); + } + assert(test_alloc_base::count == 0); + { + std::promise p0(std::allocator_arg, test_allocator()); + std::promise p(p0); + assert(test_alloc_base::count == 1); + std::future f = p.get_future(); + assert(test_alloc_base::count == 1); + assert(f.valid()); + try + { + f = p0.get_future(); + assert(false); + } + catch (const std::future_error& e) + { + assert(e.code() == make_error_code(std::future_errc::no_state)); + } + assert(test_alloc_base::count == 1); + } + assert(test_alloc_base::count == 0); +} diff --git a/test/thread/futures/futures.promise/default.pass.cpp b/test/thread/futures/futures.promise/default.pass.cpp new file mode 100644 index 00000000..53b0dd12 --- /dev/null +++ b/test/thread/futures/futures.promise/default.pass.cpp @@ -0,0 +1,36 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// class promise + +// promise(); + +#include +#include + +int main() +{ + { + std::promise p; + std::future f = p.get_future(); + assert(f.valid()); + } + { + std::promise p; + std::future f = p.get_future(); + assert(f.valid()); + } + { + std::promise p; + std::future f = p.get_future(); + assert(f.valid()); + } +} diff --git a/test/thread/futures/futures.promise/dtor.pass.cpp b/test/thread/futures/futures.promise/dtor.pass.cpp new file mode 100644 index 00000000..95601eb3 --- /dev/null +++ b/test/thread/futures/futures.promise/dtor.pass.cpp @@ -0,0 +1,106 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// class promise + +// ~promise(); + +#include +#include + +int main() +{ + { + typedef int T; + std::future f; + { + std::promise p; + f = p.get_future(); + p.set_value(3); + } + assert(f.get() == 3); + } + { + typedef int T; + std::future f; + { + std::promise p; + f = p.get_future(); + } + try + { + T i = f.get(); + assert(false); + } + catch (const std::future_error& e) + { + assert(e.code() == make_error_code(std::future_errc::broken_promise)); + } + } + + { + typedef int& T; + int i = 4; + std::future f; + { + std::promise p; + f = p.get_future(); + p.set_value(i); + } + assert(&f.get() == &i); + } + { + typedef int& T; + std::future f; + { + std::promise p; + f = p.get_future(); + } + try + { + T i = f.get(); + assert(false); + } + catch (const std::future_error& e) + { + assert(e.code() == make_error_code(std::future_errc::broken_promise)); + } + } + + { + typedef void T; + std::future f; + { + std::promise p; + f = p.get_future(); + p.set_value(); + } + f.get(); + assert(true); + } + { + typedef void T; + std::future f; + { + std::promise p; + f = p.get_future(); + } + try + { + f.get(); + assert(false); + } + catch (const std::future_error& e) + { + assert(e.code() == make_error_code(std::future_errc::broken_promise)); + } + } +} diff --git a/test/thread/futures/futures.promise/move_assign.pass.cpp b/test/thread/futures/futures.promise/move_assign.pass.cpp new file mode 100644 index 00000000..4d2283f9 --- /dev/null +++ b/test/thread/futures/futures.promise/move_assign.pass.cpp @@ -0,0 +1,89 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// class promise + +// promise& operator=(promise&& rhs); + +#include +#include + +#include "../test_allocator.h" + +int main() +{ +#ifdef _LIBCPP_MOVE + assert(test_alloc_base::count == 0); + { + std::promise p0(std::allocator_arg, test_allocator()); + std::promise p(std::allocator_arg, test_allocator()); + assert(test_alloc_base::count == 2); + p = std::move(p0); + assert(test_alloc_base::count == 1); + std::future f = p.get_future(); + assert(test_alloc_base::count == 1); + assert(f.valid()); + try + { + f = p0.get_future(); + assert(false); + } + catch (const std::future_error& e) + { + assert(e.code() == make_error_code(std::future_errc::no_state)); + } + assert(test_alloc_base::count == 1); + } + assert(test_alloc_base::count == 0); + { + std::promise p0(std::allocator_arg, test_allocator()); + std::promise p(std::allocator_arg, test_allocator()); + assert(test_alloc_base::count == 2); + p = std::move(p0); + assert(test_alloc_base::count == 1); + std::future f = p.get_future(); + assert(test_alloc_base::count == 1); + assert(f.valid()); + try + { + f = p0.get_future(); + assert(false); + } + catch (const std::future_error& e) + { + assert(e.code() == make_error_code(std::future_errc::no_state)); + } + assert(test_alloc_base::count == 1); + } + assert(test_alloc_base::count == 0); + { + std::promise p0(std::allocator_arg, test_allocator()); + std::promise p(std::allocator_arg, test_allocator()); + assert(test_alloc_base::count == 2); + p = std::move(p0); + assert(test_alloc_base::count == 1); + std::future f = p.get_future(); + assert(test_alloc_base::count == 1); + assert(f.valid()); + try + { + f = p0.get_future(); + assert(false); + } + catch (const std::future_error& e) + { + assert(e.code() == make_error_code(std::future_errc::no_state)); + } + assert(test_alloc_base::count == 1); + } + assert(test_alloc_base::count == 0); +#endif // _LIBCPP_MOVE +} diff --git a/test/thread/futures/futures.promise/move_ctor.pass.cpp b/test/thread/futures/futures.promise/move_ctor.pass.cpp new file mode 100644 index 00000000..caaaeebb --- /dev/null +++ b/test/thread/futures/futures.promise/move_ctor.pass.cpp @@ -0,0 +1,83 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// class promise + +// promise(promise&& rhs); + +#include +#include + +#include "../test_allocator.h" + +int main() +{ +#ifdef _LIBCPP_MOVE + assert(test_alloc_base::count == 0); + { + std::promise p0(std::allocator_arg, test_allocator()); + std::promise p(std::move(p0)); + assert(test_alloc_base::count == 1); + std::future f = p.get_future(); + assert(test_alloc_base::count == 1); + assert(f.valid()); + try + { + f = p0.get_future(); + assert(false); + } + catch (const std::future_error& e) + { + assert(e.code() == make_error_code(std::future_errc::no_state)); + } + assert(test_alloc_base::count == 1); + } + assert(test_alloc_base::count == 0); + { + std::promise p0(std::allocator_arg, test_allocator()); + std::promise p(std::move(p0)); + assert(test_alloc_base::count == 1); + std::future f = p.get_future(); + assert(test_alloc_base::count == 1); + assert(f.valid()); + try + { + f = p0.get_future(); + assert(false); + } + catch (const std::future_error& e) + { + assert(e.code() == make_error_code(std::future_errc::no_state)); + } + assert(test_alloc_base::count == 1); + } + assert(test_alloc_base::count == 0); + { + std::promise p0(std::allocator_arg, test_allocator()); + std::promise p(std::move(p0)); + assert(test_alloc_base::count == 1); + std::future f = p.get_future(); + assert(test_alloc_base::count == 1); + assert(f.valid()); + try + { + f = p0.get_future(); + assert(false); + } + catch (const std::future_error& e) + { + assert(e.code() == make_error_code(std::future_errc::no_state)); + } + assert(test_alloc_base::count == 1); + } + assert(test_alloc_base::count == 0); +#endif // _LIBCPP_MOVE +} diff --git a/test/thread/futures/futures.promise/set_exception.pass.cpp b/test/thread/futures/futures.promise/set_exception.pass.cpp new file mode 100644 index 00000000..97c4351d --- /dev/null +++ b/test/thread/futures/futures.promise/set_exception.pass.cpp @@ -0,0 +1,45 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// class promise + +// void set_exception(exception_ptr p); + +#include +#include + +int main() +{ + { + typedef int T; + std::promise p; + std::future f = p.get_future(); + p.set_exception(std::make_exception_ptr(3)); + try + { + f.get(); + assert(false); + } + catch (int i) + { + assert(i == 3); + } + try + { + p.set_exception(std::make_exception_ptr(3)); + assert(false); + } + catch (const std::future_error& e) + { + assert(e.code() == make_error_code(std::future_errc::promise_already_satisfied)); + } + } +} diff --git a/test/thread/futures/futures.promise/set_exception_at_thread_exit.pass.cpp b/test/thread/futures/futures.promise/set_exception_at_thread_exit.pass.cpp new file mode 100644 index 00000000..ce1f758d --- /dev/null +++ b/test/thread/futures/futures.promise/set_exception_at_thread_exit.pass.cpp @@ -0,0 +1,42 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// class promise + +// void promise::set_exception_at_thread_exit(exception_ptr p); + +#include +#include + +void func(std::promise& p) +{ + const int i = 5; + p.set_exception_at_thread_exit(std::make_exception_ptr(3)); +} + +int main() +{ + { + typedef int T; + std::promise p; + std::future f = p.get_future(); + std::thread(func, std::move(p)).detach(); + try + { + f.get(); + assert(false); + } + catch (int i) + { + assert(i == 3); + } + } +} diff --git a/test/thread/futures/futures.promise/set_lvalue.pass.cpp b/test/thread/futures/futures.promise/set_lvalue.pass.cpp new file mode 100644 index 00000000..4ebd8dd2 --- /dev/null +++ b/test/thread/futures/futures.promise/set_lvalue.pass.cpp @@ -0,0 +1,41 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// class promise + +// void promise::set_value(R& r); + +#include +#include + +int main() +{ + { + typedef int& T; + int i = 3; + std::promise p; + std::future f = p.get_future(); + p.set_value(i); + assert(f.get() == 3); + ++i; + f = p.get_future(); + assert(f.get() == 4); + try + { + p.set_value(i); + assert(false); + } + catch (const std::future_error& e) + { + assert(e.code() == make_error_code(std::future_errc::promise_already_satisfied)); + } + } +} diff --git a/test/thread/futures/futures.promise/set_lvalue_at_thread_exit.pass.cpp b/test/thread/futures/futures.promise/set_lvalue_at_thread_exit.pass.cpp new file mode 100644 index 00000000..78bf44f1 --- /dev/null +++ b/test/thread/futures/futures.promise/set_lvalue_at_thread_exit.pass.cpp @@ -0,0 +1,36 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// class promise + +// void promise::set_value_at_thread_exit(R& r); + +#include +#include +#include + +int i = 0; + +void func(std::promise& p) +{ + p.set_value_at_thread_exit(i); + i = 4; +} + +int main() +{ + { + std::promise p; + std::future f = p.get_future(); + std::thread(func, std::move(p)).detach(); + assert(f.get() == 4); + } +} diff --git a/test/thread/futures/futures.promise/set_rvalue.pass.cpp b/test/thread/futures/futures.promise/set_rvalue.pass.cpp new file mode 100644 index 00000000..50c587bc --- /dev/null +++ b/test/thread/futures/futures.promise/set_rvalue.pass.cpp @@ -0,0 +1,67 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// class promise + +// void promise::set_value(R&& r); + +#include +#include +#include + +#ifdef _LIBCPP_MOVE + +struct A +{ + A() {} + A(const A&) = delete; + A(A&&) {throw 9;} +}; + +#endif // _LIBCPP_MOVE + +int main() +{ +#ifdef _LIBCPP_MOVE + { + typedef std::unique_ptr T; + T i(new int(3)); + std::promise p; + std::future f = p.get_future(); + p.set_value(std::move(i)); + assert(*f.get() == 3); + try + { + p.set_value(std::move(i)); + assert(false); + } + catch (const std::future_error& e) + { + assert(e.code() == make_error_code(std::future_errc::promise_already_satisfied)); + } + } + { + typedef A T; + T i; + std::promise p; + std::future f = p.get_future(); + try + { + p.set_value(std::move(i)); + assert(false); + } + catch (int j) + { + assert(j == 9); + } + } +#endif // _LIBCPP_MOVE +} diff --git a/test/thread/futures/futures.promise/set_rvalue_at_thread_exit.pass.cpp b/test/thread/futures/futures.promise/set_rvalue_at_thread_exit.pass.cpp new file mode 100644 index 00000000..6a996de0 --- /dev/null +++ b/test/thread/futures/futures.promise/set_rvalue_at_thread_exit.pass.cpp @@ -0,0 +1,39 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// class promise + +// void promise::set_value_at_thread_exit(R&& r); + +#include +#include +#include + +#ifdef _LIBCPP_MOVE + +void func(std::promise>& p) +{ + p.set_value_at_thread_exit(std::unique_ptr(new int(5))); +} + +#endif // _LIBCPP_MOVE + +int main() +{ +#ifdef _LIBCPP_MOVE + { + std::promise> p; + std::future> f = p.get_future(); + std::thread(func, std::move(p)).detach(); + assert(*f.get() == 5); + } +#endif // _LIBCPP_MOVE +} diff --git a/test/thread/futures/futures.promise/set_value_at_thread_exit_const.pass.cpp b/test/thread/futures/futures.promise/set_value_at_thread_exit_const.pass.cpp new file mode 100644 index 00000000..e2f600ad --- /dev/null +++ b/test/thread/futures/futures.promise/set_value_at_thread_exit_const.pass.cpp @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// class promise + +// void promise::set_value_at_thread_exit(const R& r); + +#include +#include + +void func(std::promise& p) +{ + const int i = 5; + p.set_value_at_thread_exit(i); +} + +int main() +{ + { + std::promise p; + std::future f = p.get_future(); + std::thread(func, std::move(p)).detach(); + assert(f.get() == 5); + } +} diff --git a/test/thread/futures/futures.promise/set_value_at_thread_exit_void.pass.cpp b/test/thread/futures/futures.promise/set_value_at_thread_exit_void.pass.cpp new file mode 100644 index 00000000..57c48f53 --- /dev/null +++ b/test/thread/futures/futures.promise/set_value_at_thread_exit_void.pass.cpp @@ -0,0 +1,37 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// class promise + +// void promise::set_value_at_thread_exit(); + +#include +#include +#include + +int i = 0; + +void func(std::promise& p) +{ + p.set_value_at_thread_exit(); + i = 1; +} + +int main() +{ + { + std::promise p; + std::future f = p.get_future(); + std::thread(func, std::move(p)).detach(); + f.get(); + assert(i == 1); + } +} diff --git a/test/thread/futures/futures.promise/set_value_const.pass.cpp b/test/thread/futures/futures.promise/set_value_const.pass.cpp new file mode 100644 index 00000000..29d0a6c1 --- /dev/null +++ b/test/thread/futures/futures.promise/set_value_const.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. +// +//===----------------------------------------------------------------------===// + +// + +// class promise + +// void promise::set_value(const R& r); + +#include +#include + +struct A +{ + A() {} + A(const A&) {throw 10;} +}; + +int main() +{ + { + typedef int T; + T i = 3; + std::promise p; + std::future f = p.get_future(); + p.set_value(i); + ++i; + assert(f.get() == 3); + --i; + try + { + p.set_value(i); + assert(false); + } + catch (const std::future_error& e) + { + assert(e.code() == make_error_code(std::future_errc::promise_already_satisfied)); + } + } + { + typedef A T; + T i; + std::promise p; + std::future f = p.get_future(); + try + { + p.set_value(i); + assert(false); + } + catch (int j) + { + assert(j == 10); + } + } +} diff --git a/test/thread/futures/futures.promise/set_value_void.pass.cpp b/test/thread/futures/futures.promise/set_value_void.pass.cpp new file mode 100644 index 00000000..eeaad30f --- /dev/null +++ b/test/thread/futures/futures.promise/set_value_void.pass.cpp @@ -0,0 +1,37 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// class promise + +// void promise::set_value(); + +#include +#include + +int main() +{ + { + typedef void T; + std::promise p; + std::future f = p.get_future(); + p.set_value(); + f.get(); + try + { + p.set_value(); + assert(false); + } + catch (const std::future_error& e) + { + assert(e.code() == make_error_code(std::future_errc::promise_already_satisfied)); + } + } +} diff --git a/test/thread/futures/futures.promise/swap.pass.cpp b/test/thread/futures/futures.promise/swap.pass.cpp new file mode 100644 index 00000000..4a7f148d --- /dev/null +++ b/test/thread/futures/futures.promise/swap.pass.cpp @@ -0,0 +1,82 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// class promise + +// void swap(promise& other); + +// template void swap(promise& x, promise& y); + +#include +#include + +#include "../test_allocator.h" + +int main() +{ + assert(test_alloc_base::count == 0); + { + std::promise p0(std::allocator_arg, test_allocator()); + std::promise p(std::allocator_arg, test_allocator()); + assert(test_alloc_base::count == 2); + p.swap(p0); + assert(test_alloc_base::count == 2); + std::future f = p.get_future(); + assert(test_alloc_base::count == 2); + assert(f.valid()); + f = p0.get_future(); + assert(f.valid()); + assert(test_alloc_base::count == 2); + } + assert(test_alloc_base::count == 0); + { + std::promise p0(std::allocator_arg, test_allocator()); + std::promise p(std::allocator_arg, test_allocator()); + assert(test_alloc_base::count == 2); + swap(p, p0); + assert(test_alloc_base::count == 2); + std::future f = p.get_future(); + assert(test_alloc_base::count == 2); + assert(f.valid()); + f = p0.get_future(); + assert(f.valid()); + assert(test_alloc_base::count == 2); + } + assert(test_alloc_base::count == 0); + { + std::promise p0(std::allocator_arg, test_allocator()); + std::promise p; + assert(test_alloc_base::count == 1); + p.swap(p0); + assert(test_alloc_base::count == 1); + std::future f = p.get_future(); + assert(test_alloc_base::count == 1); + assert(f.valid()); + f = p0.get_future(); + assert(f.valid()); + assert(test_alloc_base::count == 1); + } + assert(test_alloc_base::count == 0); + { + std::promise p0(std::allocator_arg, test_allocator()); + std::promise p; + assert(test_alloc_base::count == 1); + swap(p, p0); + assert(test_alloc_base::count == 1); + std::future f = p.get_future(); + assert(test_alloc_base::count == 1); + assert(f.valid()); + f = p0.get_future(); + assert(f.valid()); + assert(test_alloc_base::count == 1); + } + assert(test_alloc_base::count == 0); +} diff --git a/test/thread/futures/futures.promise/uses_allocator.pass.cpp b/test/thread/futures/futures.promise/uses_allocator.pass.cpp new file mode 100644 index 00000000..0d549ed7 --- /dev/null +++ b/test/thread/futures/futures.promise/uses_allocator.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. +// +//===----------------------------------------------------------------------===// + +// + +// class promise + +// template +// struct uses_allocator, Alloc> +// : true_type { }; + +#include +#include "../test_allocator.h" + +int main() +{ + static_assert((std::uses_allocator, test_allocator >::value), ""); + static_assert((std::uses_allocator, test_allocator >::value), ""); + static_assert((std::uses_allocator, test_allocator >::value), ""); +} diff --git a/test/thread/futures/test_allocator.h b/test/thread/futures/test_allocator.h new file mode 100644 index 00000000..94a80e2d --- /dev/null +++ b/test/thread/futures/test_allocator.h @@ -0,0 +1,143 @@ +#ifndef TEST_ALLOCATOR_H +#define TEST_ALLOCATOR_H + +#include +#include +#include +#include +#include + +class test_alloc_base +{ +public: + static int count; +public: + static int throw_after; +}; + +int test_alloc_base::count = 0; +int test_alloc_base::throw_after = INT_MAX; + +template +class test_allocator + : public test_alloc_base +{ + int data_; + + template friend class test_allocator; +public: + + typedef unsigned size_type; + typedef int difference_type; + typedef T value_type; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef typename std::add_lvalue_reference::type reference; + typedef typename std::add_lvalue_reference::type const_reference; + + template struct rebind {typedef test_allocator other;}; + + test_allocator() throw() : data_(-1) {} + explicit test_allocator(int i) throw() : data_(i) {} + test_allocator(const test_allocator& a) throw() + : data_(a.data_) {} + template test_allocator(const test_allocator& a) throw() + : data_(a.data_) {} + ~test_allocator() throw() {data_ = 0;} + pointer address(reference x) const {return &x;} + const_pointer address(const_reference x) const {return &x;} + pointer allocate(size_type n, const void* = 0) + { + if (count >= throw_after) + throw std::bad_alloc(); + ++count; + return (pointer)std::malloc(n * sizeof(T)); + } + void deallocate(pointer p, size_type n) + {--count; std::free(p);} + size_type max_size() const throw() + {return UINT_MAX / sizeof(T);} + void construct(pointer p, const T& val) + {::new(p) T(val);} +#ifdef _LIBCPP_MOVE + void construct(pointer p, T&& val) + {::new(p) T(std::move(val));} +#endif // _LIBCPP_MOVE + void destroy(pointer p) {p->~T();} + + friend bool operator==(const test_allocator& x, const test_allocator& y) + {return x.data_ == y.data_;} + friend bool operator!=(const test_allocator& x, const test_allocator& y) + {return !(x == y);} +}; + +template <> +class test_allocator + : public test_alloc_base +{ + int data_; + + template friend class test_allocator; +public: + + typedef unsigned size_type; + typedef int difference_type; + typedef void value_type; + typedef value_type* pointer; + typedef const value_type* const_pointer; + + template struct rebind {typedef test_allocator other;}; + + test_allocator() throw() : data_(-1) {} + explicit test_allocator(int i) throw() : data_(i) {} + test_allocator(const test_allocator& a) throw() + : data_(a.data_) {} + template test_allocator(const test_allocator& a) throw() + : data_(a.data_) {} + ~test_allocator() throw() {data_ = 0;} + + friend bool operator==(const test_allocator& x, const test_allocator& y) + {return x.data_ == y.data_;} + friend bool operator!=(const test_allocator& x, const test_allocator& y) + {return !(x == y);} +}; + +template +class other_allocator +{ + int data_; + + template friend class other_allocator; + +public: + typedef T value_type; + + other_allocator() : data_(-1) {} + explicit other_allocator(int i) : data_(i) {} + template other_allocator(const other_allocator& a) + : data_(a.data_) {} + T* allocate(std::size_t n) + {return (T*)std::malloc(n * sizeof(T));} + void deallocate(T* p, std::size_t n) + {std::free(p);} + + other_allocator select_on_container_copy_construction() const + {return other_allocator(-2);} + + friend bool operator==(const other_allocator& x, const other_allocator& y) + {return x.data_ == y.data_;} + friend bool operator!=(const other_allocator& x, const other_allocator& y) + {return !(x == y);} + + typedef std::true_type propagate_on_container_copy_assignment; + typedef std::true_type propagate_on_container_move_assignment; + typedef std::true_type propagate_on_container_swap; + +#ifdef _LIBCPP_HAS_NO_ADVANCED_SFINAE + std::size_t max_size() const + {return UINT_MAX / sizeof(T);} +#endif // _LIBCPP_HAS_NO_ADVANCED_SFINAE + +}; + +#endif // TEST_ALLOCATOR_H