Index: include/memory =================================================================== --- include/memory +++ include/memory @@ -1606,98 +1606,6 @@ __has_select_on_container_copy_construction(), __a);} - template - _LIBCPP_INLINE_VISIBILITY - static - void - __construct_forward(allocator_type& __a, _Ptr __begin1, _Ptr __end1, _Ptr& __begin2) - { - for (; __begin1 != __end1; ++__begin1, ++__begin2) - construct(__a, _VSTD::__to_raw_pointer(__begin2), _VSTD::move_if_noexcept(*__begin1)); - } - - template - _LIBCPP_INLINE_VISIBILITY - static - typename enable_if - < - (is_same >::value - || !__has_construct::value) && - is_trivially_move_constructible<_Tp>::value, - void - >::type - __construct_forward(allocator_type&, _Tp* __begin1, _Tp* __end1, _Tp*& __begin2) - { - ptrdiff_t _Np = __end1 - __begin1; - if (_Np > 0) - { - _VSTD::memcpy(__begin2, __begin1, _Np * sizeof(_Tp)); - __begin2 += _Np; - } - } - - template - _LIBCPP_INLINE_VISIBILITY - static - void - __construct_range_forward(allocator_type& __a, _Iter __begin1, _Iter __end1, _Ptr& __begin2) - { - for (; __begin1 != __end1; ++__begin1, (void) ++__begin2) - construct(__a, _VSTD::__to_raw_pointer(__begin2), *__begin1); - } - - template - _LIBCPP_INLINE_VISIBILITY - static - typename enable_if - < - (is_same >::value - || !__has_construct::value) && - is_trivially_move_constructible<_Tp>::value, - void - >::type - __construct_range_forward(allocator_type&, _Tp* __begin1, _Tp* __end1, _Tp*& __begin2) - { - typedef typename remove_const<_Tp>::type _Vp; - ptrdiff_t _Np = __end1 - __begin1; - if (_Np > 0) - { - _VSTD::memcpy(const_cast<_Vp*>(__begin2), __begin1, _Np * sizeof(_Tp)); - __begin2 += _Np; - } - } - - template - _LIBCPP_INLINE_VISIBILITY - static - void - __construct_backward(allocator_type& __a, _Ptr __begin1, _Ptr __end1, _Ptr& __end2) - { - while (__end1 != __begin1) - { - construct(__a, _VSTD::__to_raw_pointer(__end2-1), _VSTD::move_if_noexcept(*--__end1)); - --__end2; - } - } - - template - _LIBCPP_INLINE_VISIBILITY - static - typename enable_if - < - (is_same >::value - || !__has_construct::value) && - is_trivially_move_constructible<_Tp>::value, - void - >::type - __construct_backward(allocator_type&, _Tp* __begin1, _Tp* __end1, _Tp*& __end2) - { - ptrdiff_t _Np = __end1 - __begin1; - __end2 -= _Np; - if (_Np > 0) - _VSTD::memcpy(__end2, __begin1, _Np * sizeof(_Tp)); - } - private: _LIBCPP_INLINE_VISIBILITY Index: include/vector =================================================================== --- include/vector +++ include/vector @@ -291,6 +291,84 @@ _LIBCPP_BEGIN_NAMESPACE_STD +template +_LIBCPP_INLINE_VISIBILITY +inline void +__copy_construct_forward(_Alloc& __a, _Iter __begin1, _Iter __end1, + _Ptr& __begin2, false_type) +{ + typedef allocator_traits<_Alloc> _Alloc_traits; + for (; __begin1 != __end1; ++__begin1, (void)++__begin2) + _Alloc_traits::construct(__a, _VSTD::__to_raw_pointer(__begin2), *__begin1); +} + +template +_LIBCPP_INLINE_VISIBILITY +inline void +__copy_construct_forward(_Alloc&, _Iter __begin1, _Iter __end1, + _Ptr& __begin2, true_type) +{ + typedef typename iterator_traits<_Iter>::value_type _Tp; + typedef typename remove_const<_Tp>::type _Vp; + ptrdiff_t _Np = __end1 - __begin1; + if (_Np > 0) { + _VSTD::memcpy(const_cast<_Vp*>(_VSTD::__to_raw_pointer(__begin2)), _VSTD::__to_raw_pointer(__begin1), _Np * sizeof(_Tp)); + __begin2 += _Np; + } +} + +template +_LIBCPP_INLINE_VISIBILITY +inline void +__move_construct_forward(_Alloc& __a, _Ptr __begin1, _Ptr __end1, + _Ptr& __begin2, false_type) +{ + typedef allocator_traits<_Alloc> _Alloc_traits; + for (; __begin1 != __end1; ++__begin1, ++__begin2) + _Alloc_traits::construct(__a, _VSTD::__to_raw_pointer(__begin2), _VSTD::move_if_noexcept(*__begin1)); +} + +template +_LIBCPP_INLINE_VISIBILITY +inline void +__move_construct_forward(_Alloc&, _Ptr __begin1, _Ptr __end1, + _Ptr& __begin2, true_type) +{ + typedef typename iterator_traits<_Ptr>::value_type _Tp; + ptrdiff_t _Np = __end1 - __begin1; + if (_Np > 0) { + _VSTD::memcpy(_VSTD::__to_raw_pointer(__begin2), _VSTD::__to_raw_pointer(__begin1), _Np * sizeof(_Tp)); + __begin2 += _Np; + } +} + +template +_LIBCPP_INLINE_VISIBILITY +inline void +__move_construct_backward(_Alloc& __a, _Ptr __begin1, _Ptr __end1, + _Ptr& __end2, false_type) +{ + typedef allocator_traits<_Alloc> _Alloc_traits; + while (__end1 != __begin1) { + _Alloc_traits::construct(__a, _VSTD::__to_raw_pointer(__end2-1), _VSTD::move_if_noexcept(*--__end1)); + --__end2; + } +} + +template +_LIBCPP_INLINE_VISIBILITY +inline void +__move_construct_backward(_Alloc&, _Ptr __begin1, _Ptr __end1, + _Ptr& __end2, true_type) +{ + typedef typename iterator_traits<_Ptr>::value_type _Tp; + ptrdiff_t _Np = __end1 - __begin1; + if (_Np > 0) { + __end2 -= _Np; + _VSTD::memcpy(_VSTD::__to_raw_pointer(__end2), _VSTD::__to_raw_pointer(__begin1), _Np * sizeof(_Tp)); + } +} + template class __vector_base_common { @@ -460,6 +538,12 @@ } } +template +struct __vector_should_construct_via_memcpy : integral_constant >::value || !__has_construct<_Allocator, _Tp*, _Tp>::value) && + is_trivially_move_constructible<_Tp>::value +> {}; + template */> class _LIBCPP_TEMPLATE_VIS vector : private __vector_base<_Tp, _Allocator> @@ -467,6 +551,7 @@ private: typedef __vector_base<_Tp, _Allocator> __base; typedef allocator<_Tp> __default_allocator_type; + public: typedef vector __self; typedef _Tp value_type; @@ -927,8 +1012,9 @@ void vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer& __v) { + typedef typename __vector_should_construct_via_memcpy<_Tp, _Allocator>::type __copy_via_memcpy; __annotate_delete(); - __alloc_traits::__construct_backward(this->__alloc(), this->__begin_, this->__end_, __v.__begin_); + _VSTD::__move_construct_backward(this->__alloc(), this->__begin_, this->__end_, __v.__begin_, __copy_via_memcpy()); _VSTD::swap(this->__begin_, __v.__begin_); _VSTD::swap(this->__end_, __v.__end_); _VSTD::swap(this->__end_cap(), __v.__end_cap()); @@ -941,10 +1027,11 @@ typename vector<_Tp, _Allocator>::pointer vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer& __v, pointer __p) { + typedef typename __vector_should_construct_via_memcpy<_Tp, _Allocator>::type __copy_via_memcpy; __annotate_delete(); pointer __r = __v.__begin_; - __alloc_traits::__construct_backward(this->__alloc(), this->__begin_, __p, __v.__begin_); - __alloc_traits::__construct_forward(this->__alloc(), __p, this->__end_, __v.__end_); + _VSTD::__move_construct_backward(this->__alloc(), this->__begin_, __p, __v.__begin_, __copy_via_memcpy()); + _VSTD::__move_construct_forward(this->__alloc(), __p, this->__end_, __v.__end_, __copy_via_memcpy()); _VSTD::swap(this->__begin_, __v.__begin_); _VSTD::swap(this->__end_, __v.__end_); _VSTD::swap(this->__end_cap(), __v.__end_cap()); @@ -1058,9 +1145,15 @@ >::type vector<_Tp, _Allocator>::__construct_at_end(_ForwardIterator __first, _ForwardIterator __last, size_type __n) { + typedef integral_constant::value && + (is_same<_ForwardIterator, _Tp*>::value || + is_same<_ForwardIterator, const _Tp*>::value || + is_same<_ForwardIterator, pointer>::value) + > __copy_via_memcpy; allocator_type& __a = this->__alloc(); __RAII_IncreaseAnnotator __annotator(*this, __n); - __alloc_traits::__construct_range_forward(__a, __first, __last, this->__end_); + _VSTD::__copy_construct_forward(__a, __first, __last, this->__end_, __copy_via_memcpy()); __annotator.__done(); } Index: test/libcxx/containers/sequences/vector/specialized_allocator_traits.pass.cpp =================================================================== --- /dev/null +++ test/libcxx/containers/sequences/vector/specialized_allocator_traits.pass.cpp @@ -0,0 +1,100 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// Test that vector does not use non-standard members of std::allocator_traits. +// Specializing std::allocator_traits is arguably non-conforming, but libc++'s +// support for specialized std::allocator_traits is a feature, not a bug. +// Breaking (and subsequently deleting) this unit test should be done as a +// conscious decision. + +#include + +template +class A1 +{ +public: + using value_type = T; + + A1() = default; + + template + A1(const A1&) {} + + T *allocate(std::size_t n) + { + return (T *)std::malloc(n * sizeof (T)); + } + + void deallocate(T* p, std::size_t) + { + std::free(p); + } +}; + +template +struct std::allocator_traits> { + using allocator_type = A1; + using value_type = T; + using pointer = T*; + using const_pointer = const T*; + using void_pointer = void*; + using const_void_pointer = const void*; + using difference_type = std::ptrdiff_t; + using size_type = std::size_t; + using propagate_on_container_copy_assignment = std::true_type; + using propagate_on_container_move_assignment = std::true_type; + using propagate_on_container_swap = std::true_type; + using is_always_equal = std::true_type; + + template using rebind_alloc = A1; + template using rebind_traits = std::allocator_traits>; + + static T *allocate(A1& a, size_t n) { + return a.allocate(n); + } + + static void deallocate(A1& a, T *p, size_t n) { + return a.deallocate(p, n); + } + + template + static void construct(A1&, U *p, Args&&... args) { + ::new ((void*)p) U(std::forward(args)...); + } + + template + static void destroy(A1&, U *p) { + p->~U(); + } + + static A1 select_on_container_copy_construction(const A1& a) { + return a.select_on_container_copy_construction(); + } + + static size_type max_size(const A1&) { + return size_t(-1); + } +}; + +int main() +{ + std::vector> v = {1, 2, 3}; + v.resize(10); + v.insert(v.begin() + 4, 4); + assert(v[0] == 1); + assert(v[1] == 2); + assert(v[2] == 3); + assert(v[3] == 0); + assert(v[4] == 4); + assert(v[5] == 0); +}