Index: include/memory =================================================================== --- include/memory +++ include/memory @@ -3510,6 +3510,20 @@ #endif } +template +struct __shared_ptr_array_block +{ + typename std::aligned_storage< + sizeof(_CntrlBlk), + alignment_of<_CntrlBlk>::value + >::type __cntrl_buff[sizeof(_CntrlBlk)]; + + typename std::aligned_storage< + sizeof(_Tp), + alignment_of<_CntrlBlk>::value + >::type __value_buff[sizeof(_Tp)]; +}; + template class _LIBCPP_TEMPLATE_VIS weak_ptr; class _LIBCPP_TYPE_VIS __shared_count @@ -3607,15 +3621,22 @@ : public __shared_weak_count { __compressed_pair<__compressed_pair<_Tp, _Dp>, _Alloc> __data_; + size_t __size; + public: _LIBCPP_INLINE_VISIBILITY - __shared_ptr_pointer(_Tp __p, _Dp __d, _Alloc __a) - : __data_(__compressed_pair<_Tp, _Dp>(__p, _VSTD::move(__d)), _VSTD::move(__a)) {} + __shared_ptr_pointer(_Tp __p, _Dp __d, _Alloc __a, + size_t __size = sizeof(__shared_ptr_pointer)) + : __data_(__compressed_pair<_Tp, _Dp>(__p, _VSTD::move(__d)), _VSTD::move(__a)), + __size(__size) {} #ifndef _LIBCPP_NO_RTTI virtual const void* __get_deleter(const type_info&) const _NOEXCEPT; #endif + _LIBCPP_INLINE_VISIBILITY + _Tp get() _NOEXCEPT {return __data_.first().first();} + private: virtual void __on_zero_shared() _NOEXCEPT; virtual void __on_zero_shared_weak() _NOEXCEPT; @@ -3644,13 +3665,13 @@ void __shared_ptr_pointer<_Tp, _Dp, _Alloc>::__on_zero_shared_weak() _NOEXCEPT { - typedef typename __allocator_traits_rebind<_Alloc, __shared_ptr_pointer>::type _Al; + typedef typename __allocator_traits_rebind<_Alloc, char>::type _Al; typedef allocator_traits<_Al> _ATraits; typedef pointer_traits _PTraits; _Al __a(__data_.second()); __data_.second().~_Alloc(); - __a.deallocate(_PTraits::pointer_to(*this), 1); + __a.deallocate(_PTraits::pointer_to(*reinterpret_cast(this)), __size); } template @@ -3753,6 +3774,18 @@ : is_convertible<_Tp*, _Up*> {}; #endif // _LIBCPP_STD_VER > 14 +template ::value> +struct __shared_ptr_default_allocator +{ + typedef allocator<_Yp> type; +}; + +template +struct __shared_ptr_default_allocator<_Yp, true> +{ + typedef allocator<__shared_ptr_dummy_rebind_allocator_type> type; +}; + template class _LIBCPP_TEMPLATE_VIS shared_ptr { @@ -3987,18 +4020,6 @@ } private: - template ::value> - struct __shared_ptr_default_allocator - { - typedef allocator<_Yp> type; - }; - - template - struct __shared_ptr_default_allocator<_Yp, true> - { - typedef allocator<__shared_ptr_dummy_rebind_allocator_type> type; - }; - template _LIBCPP_INLINE_VISIBILITY typename enable_if 17 + +// bounded array types + +template +inline _LIBCPP_INLINE_VISIBILITY +typename enable_if +< + is_bounded_array<_Tp>::value, + shared_ptr<_Tp> +>::type +make_shared() +{ + typedef allocator<_Tp> _Alloc; + typedef remove_extent_t<_Tp> _ET; + typedef default_delete<_ET[]> _D1; + typedef __shared_ptr_pointer<_ET*, _D1, _Alloc> _CntrlBlk; + typedef allocator<_CntrlBlk> _A2; + typedef __allocator_destructor<_A2> _D2; + + _A2 __a2; + unique_ptr<_CntrlBlk, _D2> __hold2(__a2.allocate(1), _D2(__a2, 1)); + ::new(__hold2.get()) + _CntrlBlk(new _Tp, _D1(), __a2); + + return shared_ptr<_Tp>::__create_with_cntrl_block(__hold2.get()->get(), + __hold2.release()); +} + +template +inline _LIBCPP_INLINE_VISIBILITY +typename enable_if +< + is_bounded_array<_Tp>::value, + shared_ptr<_Tp> +>::type +allocate_shared(const _Alloc& __a) +{ + typedef remove_extent_t<_Tp> _ET; + typedef default_delete<_ET[]> _D1; + typedef __shared_ptr_pointer<_ET*, _D1, _Alloc> _CntrlBlk; + typedef typename __allocator_traits_rebind<_Alloc, _CntrlBlk>::type _A2; + typedef __allocator_destructor<_A2> _D2; + + _A2 __a2(__a); + unique_ptr<_CntrlBlk, _D2> __hold2(__a2.allocate(1), _D2(__a2, 1)); + ::new(static_cast(_VSTD::addressof(*__hold2.get()))) + _CntrlBlk(new _Tp, _D1(), __a); + + return shared_ptr<_Tp>::__create_with_cntrl_block(__hold2.get()->get(), + _VSTD::addressof(*__hold2.release())); +} + +template +inline _LIBCPP_INLINE_VISIBILITY +typename enable_if +< + is_bounded_array<_Tp>::value, + shared_ptr<_Tp> +>::type +make_shared(_Up __element) +{ + shared_ptr<_Tp> __ptr = make_shared<_Tp>(); + for (size_t __i = 0; __i < extent_v<_Tp>; ++__i) + __ptr[__i] = __element; + return __ptr; +} + +template +inline _LIBCPP_INLINE_VISIBILITY +typename enable_if +< + is_bounded_array<_Tp>::value, + shared_ptr<_Tp> +>::type +allocate_shared(const _Alloc& __a, _Up __element) +{ + shared_ptr<_Tp> __ptr = allocate_shared<_Tp>(__a); + for (size_t __i = 0; __i < extent_v<_Tp>; ++__i) + __ptr[__i] = __element; + return __ptr; +} + +// unbounded array types + +template> +struct __destroy_n +{ + size_t __size; + + __destroy_n(size_t __size) : __size(__size) {} + + void operator()(_Tp* __ptr) + { + for (size_t __i = 0; __i < __size; ++__i) + __ptr++->~_Tp(); + } +}; + +template +struct __destroy_n<_Tp, true> +{ + size_t __size; + + __destroy_n(size_t __size) : __size(__size) {} + + template + void operator()(remove_extent_t<_Tp>(*__ptr)[_Sz]) + { + using _ET = remove_extent_t<_Tp>; + for (size_t __i = 0; __i < __size; ++__i) + { + __destroy_n<_ET> __d { _Sz }; + __d(*__ptr++); + } + } +}; + +template +void __fill_ptr(_Tp* __ptr, size_t __size, _Up __element) +{ + for (size_t __i = 0; __i < __size; ++__i) + ::new(static_cast(__ptr + __i)) _Tp(__element); +} + +template +void __fill_ptr(_Tp* __ptr, size_t __size, false_type) +{ + for (size_t __i = 0; __i < __size; ++__i) + ::new(static_cast(__ptr + __i)) _Tp{}; +} + +template +inline _LIBCPP_INLINE_VISIBILITY +typename enable_if +< + is_unbounded_array<_Tp>::value, + shared_ptr<_Tp> +>::type +make_shared(size_t __size, _Up __element = false_type()) +{ + typedef remove_extent_t<_Tp> _ET; + typedef __destroy_n<_ET> _D1; + typedef typename __shared_ptr_default_allocator<_ET>::type _Alloc; + typedef __shared_ptr_pointer<_ET*, _D1, _Alloc> _CntrlBlk; + typedef allocator _A2; + typedef __allocator_destructor<_A2> _D2; + typedef __shared_ptr_array_block<_CntrlBlk, _ET> _ArrBlk; + + _A2 __a2; + size_t __alloc_size = sizeof(_ET) * __size + sizeof(_CntrlBlk); + unique_ptr<_CntrlBlk, _D2> __hold2(__a2.allocate(__alloc_size), _D2(__a2, 1)); + + _ArrBlk* __arr_block = reinterpret_cast<_ArrBlk*>(__hold2.get()); + _CntrlBlk* __cntrl_ptr = reinterpret_cast<_CntrlBlk*>(__arr_block->__cntrl_buff); + _ET* __arr_ptr = reinterpret_cast<_ET*>(__arr_block->__value_buff); + + ::new(static_cast(__cntrl_ptr)) + _CntrlBlk(__arr_ptr, _D1(__size), _Alloc(), __alloc_size); + __fill_ptr(__arr_ptr, __size, __element); + + __hold2.release(); + return shared_ptr<_Tp>::__create_with_cntrl_block(__arr_ptr, + __cntrl_ptr); +} + +template +inline _LIBCPP_INLINE_VISIBILITY +typename enable_if +< + is_unbounded_array<_Tp>::value, + shared_ptr<_Tp> +>::type +allocate_shared(const _Alloc& __a, size_t __size, + _Up __element = false_type()) +{ + typedef remove_extent_t<_Tp> _ET; + typedef __destroy_n<_ET> _D1; + typedef __shared_ptr_pointer<_ET*, _D1, _Alloc> _CntrlBlk; + typedef typename __allocator_traits_rebind<_Alloc, char>::type _A2; + typedef __allocator_destructor<_A2> _D2; + typedef __shared_ptr_array_block<_CntrlBlk, _ET> _ArrBlk; + + _A2 __a2(__a); + size_t __alloc_size = sizeof(_ET) * __size + sizeof(_CntrlBlk); + unique_ptr<_CntrlBlk, _D2> __hold2(__a2.allocate(__alloc_size), _D2(__a2, 1)); + + _ArrBlk* __arr_block = reinterpret_cast<_ArrBlk*>(__hold2.get()); + _CntrlBlk* __cntrl_ptr = reinterpret_cast<_CntrlBlk*>(__arr_block->__cntrl_buff); + _ET* __arr_ptr = reinterpret_cast<_ET*>(__arr_block->__value_buff); + + ::new(static_cast(__cntrl_ptr)) + _CntrlBlk(__arr_ptr, _D1(__size), __a, __alloc_size); + __fill_ptr(__arr_ptr, __size, __element); + + __hold2.release(); + return shared_ptr<_Tp>::__create_with_cntrl_block(__arr_ptr, + __cntrl_ptr); +} + +// support initializer list + +template +inline _LIBCPP_INLINE_VISIBILITY +typename enable_if +< + is_bounded_array<_Tp>::value, + shared_ptr<_Tp> +>::type +make_shared(initializer_list<_Up> __element) +{ + shared_ptr<_Tp> __ptr = make_shared<_Tp>(); + for (size_t __i = 0; __i < extent_v<_Tp>; ++__i) + memcpy(__ptr[__i], __element.begin(), __element.size() // std::copy cannot be used here because cannot be included + * sizeof(typename remove_all_extents<_Tp>::type)); + return __ptr; +} + +template +inline _LIBCPP_INLINE_VISIBILITY +typename enable_if +< + is_bounded_array<_Tp>::value, + shared_ptr<_Tp> +>::type +allocate_shared(const _Alloc& __a, initializer_list<_Up> __element) +{ + shared_ptr<_Tp> __ptr = allocate_shared<_Tp>(__a); + for (size_t __i = 0; __i < extent_v<_Tp>; ++__i) + memcpy(__ptr[__i], __element.begin(), __element.size() + * sizeof(typename remove_all_extents<_Tp>::type)); + return __ptr; +} + +template +inline _LIBCPP_INLINE_VISIBILITY +typename enable_if +< + is_unbounded_array<_Tp>::value, + shared_ptr<_Tp> +>::type +make_shared(size_t __size, initializer_list<_Up> __element) +{ + shared_ptr<_Tp> __ptr = make_shared<_Tp>(__size); + for (size_t __i = 0; __i < __size; ++__i) + memcpy(__ptr[__i], __element.begin(), __element.size() + * sizeof(typename remove_all_extents<_Tp>::type)); + return __ptr; +} + +template +inline _LIBCPP_INLINE_VISIBILITY +typename enable_if +< + is_unbounded_array<_Tp>::value, + shared_ptr<_Tp> +>::type +allocate_shared(const _Alloc& __a, size_t __size, initializer_list<_Up> __element) +{ + shared_ptr<_Tp> __ptr = allocate_shared<_Tp>(__a, __size); + for (size_t __i = 0; __i < __size; ++__i) + memcpy(__ptr[__i], __element.begin(), __element.size() + * sizeof(typename remove_all_extents<_Tp>::type)); + return __ptr; +} + + +#endif // _LIBCPP_STD_VER > 17 + #else // _LIBCPP_HAS_NO_VARIADICS template Index: test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/create_array.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/create_array.pass.cpp @@ -0,0 +1,151 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17 + +// + +// shared_ptr + +// template shared_ptr make_shared(size_t N); // T is U[] +// template +// shared_ptr allocate_shared(const A& a, size_t N); // T is U[] + +// template shared_ptr make_shared(); // T is U[N] +// template +// shared_ptr allocate_shared(const A& a); // T is U[N] + +// template +// shared_ptr make_shared(size_t N, const remove_extent_t& u); // T is U[] +// template +// shared_ptr allocate_shared(const A& a, size_t N, +// const remove_extent_t& u); // T is U[] + +// template shared_ptr +// make_shared(const remove_extent_t& u); // T is U[N] +// template +// shared_ptr allocate_shared(const A& a, +// const remove_extent_t& u); // T is U[N] + +#include + +struct A +{ + static int count; + + A() {++count;} + A(const A&) {++count;} + ~A() {--count;} +}; + +int A::count = 0; + + +struct B { + std::max_align_t val; +}; + +void test_aligned(void *ptr, size_t align) +{ + assert(reinterpret_cast(ptr) % align == 0); +} + +int main() +{ + { + using T = A[]; + + { + std::shared_ptr ptr0 = std::make_shared(8); + assert(A::count == 8); + } + assert(A::count == 0); + + { + std::shared_ptr ptr1 = std::allocate_shared(std::allocator(), 8); + assert(A::count == 8); + } + assert(A::count == 0); + } + + { + using T = A[8]; + + { + std::shared_ptr ptr0 = std::make_shared(); + assert(A::count == 8); + } + assert(A::count == 0); + + { + std::shared_ptr ptr1 = std::allocate_shared(std::allocator()); + assert(A::count == 8); + } + assert(A::count == 0); + } + + { + using T = int[]; + std::shared_ptr ptr0 = std::make_shared(8, 42); + std::shared_ptr ptr1 = std::allocate_shared(std::allocator(), 8, 42); + + for (unsigned i = 0; i < 8; ++i) + { + assert(ptr0[i] == 42); + assert(ptr1[i] == 42); + } + } + + { + using T = int[8]; + std::shared_ptr ptr0 = std::make_shared(42); + std::shared_ptr ptr1 = std::allocate_shared(std::allocator(), 42); + + for (unsigned i = 0; i < 8; ++i) + { + assert(ptr0[i] == 42); + assert(ptr1[i] == 42); + } + } + + { + using T = int[][2]; + std::shared_ptr ptr0 = std::make_shared(8, {4, 2}); + std::shared_ptr ptr1 = std::allocate_shared(std::allocator(), 8, {4, 2}); + + for (unsigned i = 0; i < 8; ++i) + { + assert(ptr0[i][0] == 4); + assert(ptr1[i][0] == 4); + assert(ptr0[i][1] == 2); + assert(ptr1[i][1] == 2); + } + } + + { + using T = int[8][2]; + std::shared_ptr ptr0 = std::make_shared({4, 2}); + std::shared_ptr ptr1 = std::allocate_shared(std::allocator(), {4, 2}); + + for (unsigned i = 0; i < 8; ++i) + { + assert(ptr0[i][0] == 4); + assert(ptr1[i][0] == 4); + assert(ptr0[i][1] == 2); + assert(ptr1[i][1] == 2); + } + } + + // make sure alignment works + { + using T = B[8]; + + std::shared_ptr ptr = std::make_shared(); + test_aligned(ptr.get(), alignof(B)); + } +} Index: www/cxx2a_status.html =================================================================== --- www/cxx2a_status.html +++ www/cxx2a_status.html @@ -54,7 +54,7 @@ 3346LWGTerminology for Container Element Requirements - Rev 1KonaComplete3.4 --> P0463R1LWGEndian just EndianTorontoComplete7.0 - P0674R1LWGExtending make_shared to Support ArraysToronto + P0674R1LWGExtending make_shared to Support ArraysTorontoComplete P0020R6LWGFloating Point AtomicAlbuquerque