From 83fb578e4e6f0a8c095f6e4ed0ccd7439a41c7cc Mon Sep 17 00:00:00 2001 From: Eric Fiselier Date: Thu, 23 Oct 2014 06:24:45 +0000 Subject: [PATCH] Add support for "fancy" pointers to promise and packaged_task. Summary: This patch is very closely related to D4859. Please see http://reviews.llvm.org/D4859 for more information. This patch adds support for "fancy" pointers and allocators to promise and packaged_task. The changes made to support this are exactly the same as in D4859. Test Plan: "fancy" pointer tests were added to each constructor affected by the change. Reviewers: danalbert, mclow.lists Reviewed By: mclow.lists Subscribers: cfe-commits Differential Revision: http://reviews.llvm.org/D4862 llvm-svn: 220471 --- libcxx/include/future | 68 ++++++++++++---------- .../futures/futures.promise/alloc_ctor.pass.cpp | 33 +++++++++++ .../futures.task.members/ctor_func_alloc.pass.cpp | 27 +++++++++ 3 files changed, 98 insertions(+), 30 deletions(-) diff --git a/libcxx/include/future b/libcxx/include/future index 83513fa..6fe6f8d 100644 --- a/libcxx/include/future +++ b/libcxx/include/future @@ -783,9 +783,12 @@ __assoc_state_alloc<_Rp, _Alloc>::__on_zero_shared() _NOEXCEPT { if (this->__state_ & base::__constructed) reinterpret_cast<_Rp*>(_VSTD::addressof(this->__value_))->~_Rp(); - typename _Alloc::template rebind<__assoc_state_alloc>::other __a(__alloc_); + typedef typename __allocator_traits_rebind<_Alloc, __assoc_state_alloc>::type _A; + typedef allocator_traits<_A> _ATraits; + typedef pointer_traits _PTraits; + _A __a(__alloc_); this->~__assoc_state_alloc(); - __a.deallocate(this, 1); + __a.deallocate(_PTraits::pointer_to(*this), 1); } template @@ -806,9 +809,12 @@ template void __assoc_state_alloc<_Rp&, _Alloc>::__on_zero_shared() _NOEXCEPT { - typename _Alloc::template rebind<__assoc_state_alloc>::other __a(__alloc_); + typedef typename __allocator_traits_rebind<_Alloc, __assoc_state_alloc>::type _A; + typedef allocator_traits<_A> _ATraits; + typedef pointer_traits _PTraits; + _A __a(__alloc_); this->~__assoc_state_alloc(); - __a.deallocate(this, 1); + __a.deallocate(_PTraits::pointer_to(*this), 1); } template @@ -829,9 +835,12 @@ template void __assoc_sub_state_alloc<_Alloc>::__on_zero_shared() _NOEXCEPT { - typename _Alloc::template rebind<__assoc_sub_state_alloc>::other __a(__alloc_); + typedef typename __allocator_traits_rebind<_Alloc, __assoc_sub_state_alloc>::type _A; + typedef allocator_traits<_A> _ATraits; + typedef pointer_traits _PTraits; + _A __a(__alloc_); this->~__assoc_sub_state_alloc(); - __a.deallocate(this, 1); + __a.deallocate(_PTraits::pointer_to(*this), 1); } template @@ -1414,12 +1423,13 @@ template template promise<_Rp>::promise(allocator_arg_t, const _Alloc& __a0) { - typedef typename _Alloc::template rebind<__assoc_state_alloc<_Rp, _Alloc> >::other _A2; + typedef __assoc_state_alloc<_Rp, _Alloc> _State; + typedef typename __allocator_traits_rebind<_Alloc, _State>::type _A2; typedef __allocator_destructor<_A2> _D2; _A2 __a(__a0); - unique_ptr<__assoc_state_alloc<_Rp, _Alloc>, _D2> __hold(__a.allocate(1), _D2(__a, 1)); - ::new(__hold.get()) __assoc_state_alloc<_Rp, _Alloc>(__a0); - __state_ = __hold.release(); + unique_ptr<_State, _D2> __hold(__a.allocate(1), _D2(__a, 1)); + ::new(static_cast(_VSTD::addressof(*__hold.get()))) _State(__a0); + __state_ = _VSTD::addressof(*__hold.release()); } template @@ -1587,12 +1597,13 @@ template template promise<_Rp&>::promise(allocator_arg_t, const _Alloc& __a0) { - typedef typename _Alloc::template rebind<__assoc_state_alloc<_Rp&, _Alloc> >::other _A2; + typedef __assoc_state_alloc<_Rp&, _Alloc> _State; + typedef typename __allocator_traits_rebind<_Alloc, _State>::type _A2; typedef __allocator_destructor<_A2> _D2; _A2 __a(__a0); - unique_ptr<__assoc_state_alloc<_Rp&, _Alloc>, _D2> __hold(__a.allocate(1), _D2(__a, 1)); - ::new(__hold.get()) __assoc_state_alloc<_Rp&, _Alloc>(__a0); - __state_ = __hold.release(); + unique_ptr<_State, _D2> __hold(__a.allocate(1), _D2(__a, 1)); + ::new(static_cast(_VSTD::addressof(*__hold.get()))) _State(__a0); + __state_ = _VSTD::addressof(*__hold.release()); } template @@ -1723,12 +1734,13 @@ public: template promise::promise(allocator_arg_t, const _Alloc& __a0) { - typedef typename _Alloc::template rebind<__assoc_sub_state_alloc<_Alloc> >::other _A2; + typedef __assoc_sub_state_alloc<_Alloc> _State; + typedef typename __allocator_traits_rebind<_Alloc, _State>::type _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(); + unique_ptr<_State, _D2> __hold(__a.allocate(1), _D2(__a, 1)); + ::new(static_cast(_VSTD::addressof(*__hold.get()))) _State(__a0); + __state_ = _VSTD::addressof(*__hold.release()); } template @@ -1808,10 +1820,12 @@ template void __packaged_task_func<_Fp, _Alloc, _Rp(_ArgTypes...)>::destroy_deallocate() { - typedef typename _Alloc::template rebind<__packaged_task_func>::other _Ap; + typedef typename __allocator_traits_rebind<_Alloc, __packaged_task_func>::type _Ap; + typedef allocator_traits<_Ap> _ATraits; + typedef pointer_traits _PTraits; _Ap __a(__f_.second()); __f_.~__compressed_pair<_Fp, _Alloc>(); - __a.deallocate(this, 1); + __a.deallocate(_PTraits::pointer_to(*this), 1); } template @@ -1900,7 +1914,6 @@ __packaged_task_function<_Rp(_ArgTypes...)>::__packaged_task_function( allocator_arg_t, const _Alloc& __a0, _Fp&& __f) : __f_(nullptr) { - typedef allocator_traits<_Alloc> __alloc_traits; typedef typename remove_reference::type>::type _FR; typedef __packaged_task_func<_FR, _Alloc, _Rp(_ArgTypes...)> _FF; if (sizeof(_FF) <= sizeof(__buf_)) @@ -1910,18 +1923,13 @@ __packaged_task_function<_Rp(_ArgTypes...)>::__packaged_task_function( } else { - typedef typename __alloc_traits::template -#ifndef _LIBCPP_HAS_NO_TEMPLATE_ALIASES - rebind_alloc<_FF> -#else - rebind_alloc<_FF>::other -#endif - _Ap; + typedef typename __allocator_traits_rebind<_Alloc, _FF>::type _Ap; _Ap __a(__a0); typedef __allocator_destructor<_Ap> _Dp; unique_ptr<__base, _Dp> __hold(__a.allocate(1), _Dp(__a, 1)); - ::new (__hold.get()) _FF(_VSTD::forward<_Fp>(__f), _Alloc(__a)); - __f_ = __hold.release(); + ::new (static_cast(_VSTD::addressof(*__hold.get()))) + _FF(_VSTD::forward<_Fp>(__f), _Alloc(__a)); + __f_ = _VSTD::addressof(*__hold.release()); } } diff --git a/libcxx/test/thread/futures/futures.promise/alloc_ctor.pass.cpp b/libcxx/test/thread/futures/futures.promise/alloc_ctor.pass.cpp index 3b47350..70a4e00 100644 --- a/libcxx/test/thread/futures/futures.promise/alloc_ctor.pass.cpp +++ b/libcxx/test/thread/futures/futures.promise/alloc_ctor.pass.cpp @@ -20,6 +20,7 @@ #include #include "../test_allocator.h" +#include "min_allocator.h" int main() { @@ -48,4 +49,36 @@ int main() assert(f.valid()); } assert(test_alloc_base::count == 0); + // Test with a minimal allocator + { + std::promise p(std::allocator_arg, bare_allocator()); + std::future f = p.get_future(); + assert(f.valid()); + } + { + std::promise p(std::allocator_arg, bare_allocator()); + std::future f = p.get_future(); + assert(f.valid()); + } + { + std::promise p(std::allocator_arg, bare_allocator()); + std::future f = p.get_future(); + assert(f.valid()); + } + // Test with a minimal allocator that returns class-type pointers + { + std::promise p(std::allocator_arg, min_allocator()); + std::future f = p.get_future(); + assert(f.valid()); + } + { + std::promise p(std::allocator_arg, min_allocator()); + std::future f = p.get_future(); + assert(f.valid()); + } + { + std::promise p(std::allocator_arg, min_allocator()); + std::future f = p.get_future(); + assert(f.valid()); + } } 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 index 347c5cd..3aac2b2 100644 --- 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 @@ -20,6 +20,7 @@ #include #include "../../test_allocator.h" +#include "min_allocator.h" class A { @@ -94,4 +95,30 @@ int main() assert(f.get() == 4); } assert(test_alloc_base::count == 0); + A::n_copies = 0; + A::n_moves = 0; + { + std::packaged_task p(std::allocator_arg, + bare_allocator(), A(5)); + assert(p.valid()); + std::future 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_moves = 0; + { + std::packaged_task p(std::allocator_arg, + min_allocator(), A(5)); + assert(p.valid()); + std::future 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_moves = 0; } -- 2.7.4