Quuxplusone updated this revision to Diff 155473. Quuxplusone added a comment.
Move the functions from `<memory>` to `<vector>`, since that's their only caller. Uniform treatment of the pointer/iterator parameters; discover that the difference between "copy_forward" and "copy_range_forward" was that the former did moves and the latter did copies. Rename accordingly. Repository: rCXX libc++ https://reviews.llvm.org/D49317 Files: include/memory include/vector test/libcxx/containers/sequences/vector/specialized_allocator_traits.pass.cpp
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 + +// <vector> + +// 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 <vector> + +template <class T> +class A1 +{ +public: + using value_type = T; + + A1() = default; + + template <class U> + A1(const A1<U>&) {} + + T *allocate(std::size_t n) + { + return (T *)std::malloc(n * sizeof (T)); + } + + void deallocate(T* p, std::size_t) + { + std::free(p); + } +}; + +template<class T> +struct std::allocator_traits<A1<T>> { + using allocator_type = A1<T>; + 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<class U> using rebind_alloc = A1<U>; + template<class U> using rebind_traits = std::allocator_traits<A1<U>>; + + static T *allocate(A1<T>& a, size_t n) { + return a.allocate(n); + } + + static void deallocate(A1<T>& a, T *p, size_t n) { + return a.deallocate(p, n); + } + + template<class U, class... Args> + static void construct(A1<T>&, U *p, Args&&... args) { + ::new ((void*)p) U(std::forward<Args>(args)...); + } + + template<class U> + static void destroy(A1<T>&, U *p) { + p->~U(); + } + + static A1<T> select_on_container_copy_construction(const A1<T>& a) { + return a.select_on_container_copy_construction(); + } + + static size_type max_size(const A1<T>&) { + return size_t(-1); + } +}; + +int main() +{ + std::vector<int, A1<int>> 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); +} Index: include/vector =================================================================== --- include/vector +++ include/vector @@ -291,6 +291,84 @@ _LIBCPP_BEGIN_NAMESPACE_STD +template <class _Alloc, class _Iter, class _Ptr, class _CopyViaMemcpy> +_LIBCPP_INLINE_VISIBILITY +inline void +__copy_construct_forward(_Alloc& __a, _Iter __begin1, _Iter __end1, + _Ptr& __begin2, _CopyViaMemcpy) +{ + using _Alloc_traits = allocator_traits<_Alloc>; + for (; __begin1 != __end1; ++__begin1, (void)++__begin2) + _Alloc_traits::construct(__a, _VSTD::__to_raw_pointer(__begin2), *__begin1); +} + +template <class _Alloc, class _Iter, class _Ptr> +_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 <class _Alloc, class _Ptr> +_LIBCPP_INLINE_VISIBILITY +inline void +__move_construct_forward(_Alloc& __a, _Ptr __begin1, _Ptr __end1, + _Ptr& __begin2, false_type) +{ + using _Alloc_traits = allocator_traits<_Alloc>; + for (; __begin1 != __end1; ++__begin1, ++__begin2) + _Alloc_traits::construct(__a, _VSTD::__to_raw_pointer(__begin2), _VSTD::move_if_noexcept(*__begin1)); +} + +template <class _Alloc, class _Ptr> +_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 <class _Alloc, class _Ptr> +_LIBCPP_INLINE_VISIBILITY +inline void +__move_construct_backward(_Alloc& __a, _Ptr __begin1, _Ptr __end1, + _Ptr& __end2, false_type) +{ + using _Alloc_traits = allocator_traits<_Alloc>; + while (__end1 != __begin1) { + _Alloc_traits::construct(__a, _VSTD::__to_raw_pointer(__end2-1), _VSTD::move_if_noexcept(*--__end1)); + --__end2; + } +} + +template <class _Alloc, class _Ptr> +_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 <bool> class __vector_base_common { @@ -460,13 +538,20 @@ } } +template<class _Tp, class _Allocator> +struct __vector_copy_via_memcpy : integral_constant<bool, + (is_same<_Allocator, allocator<_Tp> >::value || !__has_construct<_Allocator, _Tp*, _Tp>::value) && + is_trivially_move_constructible<_Tp>::value +> {}; + template <class _Tp, class _Allocator /* = allocator<_Tp> */> class _LIBCPP_TEMPLATE_VIS vector : private __vector_base<_Tp, _Allocator> { 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<value_type, allocator_type&>& __v) { + typedef typename __vector_copy_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<value_type, allocator_type&>& __v, pointer __p) { + typedef typename __vector_copy_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<bool, + __vector_copy_via_memcpy<_Tp, _Allocator>::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: include/memory =================================================================== --- include/memory +++ include/memory @@ -1606,98 +1606,6 @@ __has_select_on_container_copy_construction<const allocator_type>(), __a);} - template <class _Ptr> - _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 <class _Tp> - _LIBCPP_INLINE_VISIBILITY - static - typename enable_if - < - (is_same<allocator_type, allocator<_Tp> >::value - || !__has_construct<allocator_type, _Tp*, _Tp>::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 <class _Iter, class _Ptr> - _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 <class _Tp> - _LIBCPP_INLINE_VISIBILITY - static - typename enable_if - < - (is_same<allocator_type, allocator<_Tp> >::value - || !__has_construct<allocator_type, _Tp*, _Tp>::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 <class _Ptr> - _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 <class _Tp> - _LIBCPP_INLINE_VISIBILITY - static - typename enable_if - < - (is_same<allocator_type, allocator<_Tp> >::value - || !__has_construct<allocator_type, _Tp*, _Tp>::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
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits