diff --git a/libcxx/include/__vector/vector.h b/libcxx/include/__vector/vector.h index 27e681aeef22a..a924b7d7e6581 100644 --- a/libcxx/include/__vector/vector.h +++ b/libcxx/include/__vector/vector.h @@ -57,6 +57,7 @@ #include <__type_traits/is_pointer.h> #include <__type_traits/is_replaceable.h> #include <__type_traits/is_same.h> +#include <__type_traits/is_swappable.h> #include <__type_traits/is_trivially_relocatable.h> #include <__type_traits/type_identity.h> #include <__utility/declval.h> @@ -84,25 +85,334 @@ _LIBCPP_PUSH_MACROS _LIBCPP_BEGIN_NAMESPACE_STD +#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR +template +class __vector_layout { +public: + using value_type = _Tp; + using allocator_type = _Allocator; + using __alloc_traits _LIBCPP_NODEBUG = allocator_traits; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = typename __alloc_traits::size_type; + using difference_type = typename __alloc_traits::difference_type; + using pointer = typename __alloc_traits::pointer; + using const_pointer = typename __alloc_traits::const_pointer; + using __split_buffer _LIBCPP_NODEBUG = std::__split_buffer<_Tp, _Allocator&, __split_buffer_size_layout>; + using __sentinel_type _LIBCPP_NODEBUG = size_type; + + __vector_layout() = default; + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __vector_layout(allocator_type const& __a) + _NOEXCEPT_(is_nothrow_copy_constructible::value) + : __alloc_(__a) {} + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __vector_layout(allocator_type&& __a) + _NOEXCEPT_(is_nothrow_move_constructible::value) + : __alloc_(std::move(__a)) {} + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __vector_layout(__vector_layout&& __other) + _NOEXCEPT_(is_nothrow_move_constructible::value) + : __begin_(std::move(__other.__begin_)), + __size_(std::move(__other.__size_)), + __cap_(std::move(__other.__cap_)), + __alloc_(std::move(__other.__alloc_)) { + __other.__begin_ = nullptr; + __other.__size_ = 0; + __other.__cap_ = 0; + } + + // Capacity + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { + return __size_; + } + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type capacity() const _NOEXCEPT { + return __cap_; + } + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool empty() const _NOEXCEPT { + return __size_ == 0; + } + + // Access + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference back() _NOEXCEPT { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "back() called on an empty vector"); + return __begin_[__size_ - 1]; + } + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference back() const _NOEXCEPT { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "back() called on an empty vector"); + return __begin_[__size_ - 1]; + } + + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI allocator_type& __allocator_ref() _NOEXCEPT { + return __alloc_; + } + + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI allocator_type const& + __allocator_ref() const _NOEXCEPT { + return __alloc_; + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void swap(__vector_layout& __x) + _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || __is_nothrow_swappable_v) { + _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR( + __alloc_traits::propagate_on_container_swap::value || __alloc_ == __x.__alloc_, + "vector::swap: Either propagate_on_container_swap must be true" + " or the allocators must compare equal"); + std::swap(__begin_, __x.__begin_); + std::swap(__size_, __x.__size_); + std::swap(__cap_, __x.__cap_); + std::__swap_allocator(__alloc_, __x.__alloc_); + } + + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer __raw_begin() const _NOEXCEPT { + return __begin_; + } + + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __raw_sentinel() const _NOEXCEPT { + return __size_; + } + + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __raw_capacity() const _NOEXCEPT { + return __cap_; + } + + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer __end_pointer() const _NOEXCEPT { + return __begin_ + __size_; + } + + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type + __remaining_capacity() const _NOEXCEPT { + return __cap_ - __size_; + } + + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __is_full() const _NOEXCEPT { + return __size_ == __cap_; + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_valid_range(pointer __begin, pointer __end) _NOEXCEPT { + __begin_ = __begin; + __size_ = __end - __begin_; + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void + __set_valid_range(pointer __begin, size_type __size) _NOEXCEPT { + __begin_ = __begin; + __size_ = __size; + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_sentinel(size_type __size) _NOEXCEPT { + __size_ = __size; + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_sentinel(pointer __pos) _NOEXCEPT { + __size_ = static_cast(__pos - __begin_); + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_capacity(size_type __cap) _NOEXCEPT { __cap_ = __cap; } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_capacity(pointer __pos) _NOEXCEPT { + __cap_ = static_cast(__pos - __begin_); + } + + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __invariants() const { + if (__begin_ == nullptr) { + if (__size_ || __cap_) + return false; + } else { + if (__size_ > __cap_) + return false; + } + return true; + } + +private: + pointer __begin_ = nullptr; + size_type __size_ = 0; + size_type __cap_ = 0; + [[no_unique_address]] allocator_type __alloc_; +}; +#else +template +class __vector_layout { +public: + using value_type = _Tp; + using allocator_type = _Allocator; + using __alloc_traits _LIBCPP_NODEBUG = allocator_traits; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = typename __alloc_traits::size_type; + using difference_type = typename __alloc_traits::difference_type; + using pointer = typename __alloc_traits::pointer; + using const_pointer = typename __alloc_traits::const_pointer; + using __split_buffer _LIBCPP_NODEBUG = std::__split_buffer<_Tp, _Allocator&, __split_buffer_pointer_layout>; + using __sentinel_type _LIBCPP_NODEBUG = pointer; + + // Can't be defaulted due to _LIBCPP_COMPRESSED_PAIR not being an aggregate in C++03 and C++11. + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __vector_layout() + _NOEXCEPT_(is_nothrow_default_constructible::value) + : __cap_(nullptr) {} + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __vector_layout(allocator_type const& __a) + _NOEXCEPT_(is_nothrow_copy_constructible::value) + : __cap_(nullptr), __alloc_(__a) {} + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __vector_layout(allocator_type&& __a) + _NOEXCEPT_(is_nothrow_move_constructible::value) + : __cap_(nullptr), __alloc_(std::move(__a)) {} + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __vector_layout(__vector_layout&& __other) + _NOEXCEPT_(is_nothrow_move_constructible::value) + : __begin_(std::move(__other.__begin_)), + __end_(std::move(__other.__end_)), + __cap_(std::move(__other.__cap_)), + __alloc_(std::move(__other.__alloc_)) { + __other.__begin_ = nullptr; + __other.__end_ = nullptr; + __other.__cap_ = nullptr; + } + + // Capacity + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { + return static_cast(__end_ - __begin_); + } + + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type capacity() const _NOEXCEPT { + return static_cast(__cap_ - __begin_); + } + + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool empty() const _NOEXCEPT { + return __begin_ == __end_; + } + + // Access + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference back() _NOEXCEPT { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "back() called on an empty vector"); + return *(__end_ - 1); + } + + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference back() const _NOEXCEPT { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "back() called on an empty vector"); + return *(__end_ - 1); + } + + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI allocator_type& __allocator_ref() _NOEXCEPT { + return __alloc_; + } + + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI allocator_type const& + __allocator_ref() const _NOEXCEPT { + return __alloc_; + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void swap(__vector_layout& __x) + _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || __is_nothrow_swappable_v) { + _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR( + __alloc_traits::propagate_on_container_swap::value || __alloc_ == __x.__alloc_, + "vector::swap: Either propagate_on_container_swap must be true" + " or the allocators must compare equal"); + std::swap(__begin_, __x.__begin_); + std::swap(__end_, __x.__end_); + std::swap(__cap_, __x.__cap_); + std::__swap_allocator(__alloc_, __x.__alloc_); + } + + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer __raw_begin() const _NOEXCEPT { + return __begin_; + } + + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer __raw_sentinel() const _NOEXCEPT { + return __end_; + } + + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer __raw_capacity() const _NOEXCEPT { + return __cap_; + } + + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer __end_pointer() const _NOEXCEPT { + return __end_; + } + + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type + __remaining_capacity() const _NOEXCEPT { + return __cap_ - __end_; + } + + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __is_full() const _NOEXCEPT { + return __end_ == __cap_; + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_valid_range(pointer __begin, pointer __end) _NOEXCEPT { + __begin_ = __begin; + __end_ = __end; + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void + __set_valid_range(pointer __begin, size_type __size) _NOEXCEPT { + __begin_ = __begin; + __end_ = __begin_ + __size; + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_sentinel(pointer __end) _NOEXCEPT { __end_ = __end; } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_sentinel(size_type __offset) _NOEXCEPT { + __end_ = __begin_ + __offset; + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_capacity(pointer __cap) _NOEXCEPT { __cap_ = __cap; } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_capacity(size_type __offset) _NOEXCEPT { + __cap_ = __begin_ + __offset; + } + + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __invariants() const { + if (__begin_ == nullptr) { + if (__end_ != nullptr || __cap_ != nullptr) + return false; + } else { + if (__begin_ > __end_) + return false; + if (__begin_ == __cap_) + return false; + if (__end_ > __cap_) + return false; + } + return true; + } + +private: + pointer __begin_ = nullptr; + pointer __end_ = nullptr; + _LIBCPP_COMPRESSED_PAIR(pointer, __cap_, allocator_type, __alloc_); +}; +#endif // _LIBCPP_ABI_SIZE_BASED_VECTOR + template */> -class vector { - template - using __split_buffer _LIBCPP_NODEBUG = std::__split_buffer<_Up, _Alloc, __split_buffer_pointer_layout>; +class vector : __vector_layout, _Tp, _Allocator> { + using __base _LIBCPP_NODEBUG = __vector_layout; + using __self _LIBCPP_NODEBUG = vector; + using __base::__allocator_ref; + using __base::__end_pointer; + using __base::__is_full; + using __base::__raw_begin; + using __base::__raw_capacity; + using __base::__raw_sentinel; + using __base::__remaining_capacity; + using __base::__set_capacity; + using __base::__set_sentinel; + using __base::__set_valid_range; + using typename __base::__alloc_traits; + using typename __base::__sentinel_type; + using typename __base::__split_buffer; public: - // - // Types - // - using __self _LIBCPP_NODEBUG = vector; - using value_type = _Tp; - using allocator_type = _Allocator; - using __alloc_traits _LIBCPP_NODEBUG = allocator_traits; - using reference = value_type&; - using const_reference = const value_type&; - using size_type = typename __alloc_traits::size_type; - using difference_type = typename __alloc_traits::difference_type; - using pointer = typename __alloc_traits::pointer; - using const_pointer = typename __alloc_traits::const_pointer; + using value_type = _Tp; + using allocator_type = _Allocator; + using reference = typename __base::reference; + using const_reference = typename __base::const_reference; + using size_type = typename __base::size_type; + using difference_type = typename __base::difference_type; + using pointer = typename __base::pointer; + using const_pointer = typename __base::const_pointer; #ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_VECTOR // Users might provide custom allocators, and prior to C++20 we have no existing way to detect whether the allocator's // pointer type is contiguous (though it has to be by the Standard). Using the wrapper type ensures the iterator is @@ -116,6 +426,12 @@ class vector { using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; + using __base::__invariants; + using __base::back; + using __base::capacity; + using __base::empty; + using __base::size; + // A vector containers the following members which may be trivially relocatable: // - pointer: may be trivially relocatable, so it's checked // - allocator_type: may be trivially relocatable, so it's checked @@ -144,7 +460,7 @@ class vector { #else noexcept #endif - : __alloc_(__a) { + : __base(__a) { } _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit vector(size_type __n) { @@ -158,7 +474,7 @@ class vector { #if _LIBCPP_STD_VER >= 14 _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit vector(size_type __n, const allocator_type& __a) - : __alloc_(__a) { + : __base(__a) { auto __guard = std::__make_exception_guard(__destroy_vector(*this)); if (__n > 0) { __vallocate(__n); @@ -180,7 +496,7 @@ class vector { template <__enable_if_t<__is_allocator<_Allocator>::value, int> = 0> _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI vector(size_type __n, const value_type& __x, const allocator_type& __a) - : __alloc_(__a) { + : __base(__a) { auto __guard = std::__make_exception_guard(__destroy_vector(*this)); if (__n > 0) { __vallocate(__n); @@ -203,7 +519,7 @@ class vector { int> = 0> _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI vector(_InputIterator __first, _InputIterator __last, const allocator_type& __a) - : __alloc_(__a) { + : __base(__a) { __init_with_sentinel(__first, __last); } @@ -224,7 +540,7 @@ class vector { int> = 0> _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI vector(_ForwardIterator __first, _ForwardIterator __last, const allocator_type& __a) - : __alloc_(__a) { + : __base(__a) { size_type __n = static_cast(std::distance(__first, __last)); __init_with_size(__first, __last, __n); } @@ -233,7 +549,7 @@ class vector { template <_ContainerCompatibleRange<_Tp> _Range> _LIBCPP_HIDE_FROM_ABI constexpr vector( from_range_t, _Range&& __range, const allocator_type& __alloc = allocator_type()) - : __alloc_(__alloc) { + : __base(__alloc) { if constexpr (ranges::forward_range<_Range> || ranges::sized_range<_Range>) { auto __n = static_cast(ranges::distance(__range)); __init_with_size(ranges::begin(__range), ranges::end(__range), __n); @@ -250,10 +566,10 @@ class vector { _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI __destroy_vector(vector& __vec) : __vec_(__vec) {} _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void operator()() { - if (__vec_.__begin_ != nullptr) { + if (__vec_.__raw_begin() != nullptr) { __vec_.clear(); __vec_.__annotate_delete(); - __alloc_traits::deallocate(__vec_.__alloc_, __vec_.__begin_, __vec_.capacity()); + __alloc_traits::deallocate(__vec_.__allocator_ref(), __vec_.__raw_begin(), __vec_.capacity()); } } @@ -265,13 +581,13 @@ class vector { _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI ~vector() { __destroy_vector (*this)(); } _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI vector(const vector& __x) - : __alloc_(__alloc_traits::select_on_container_copy_construction(__x.__alloc_)) { - __init_with_size(__x.__begin_, __x.__end_, __x.size()); + : __base(__alloc_traits::select_on_container_copy_construction(__x.__allocator_ref())) { + __init_with_size(__x.__raw_begin(), __x.__end_pointer(), __x.size()); } _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI vector(const vector& __x, const __type_identity_t& __a) - : __alloc_(__a) { - __init_with_size(__x.__begin_, __x.__end_, __x.size()); + : __base(__a) { + __init_with_size(__x.__raw_begin(), __x.__end_pointer(), __x.size()); } _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI vector& operator=(const vector& __x); @@ -282,7 +598,7 @@ class vector { _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI vector(initializer_list __il, const allocator_type& __a) - : __alloc_(__a) { + : __base(__a) { __init_with_size(__il.begin(), __il.end(), __il.size()); } @@ -345,23 +661,23 @@ class vector { #endif [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const _NOEXCEPT { - return this->__alloc_; + return __allocator_ref(); } // // Iterators // [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { - return __make_iter(__add_alignment_assumption(this->__begin_)); + return __make_iter(__add_alignment_assumption(__raw_begin())); } [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { - return __make_iter(__add_alignment_assumption(this->__begin_)); + return __make_iter(__add_alignment_assumption(__raw_begin())); } [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT { - return __make_iter(__add_alignment_assumption(this->__end_)); + return __make_iter(__add_alignment_assumption(__end_pointer())); } [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT { - return __make_iter(__add_alignment_assumption(this->__end_)); + return __make_iter(__add_alignment_assumption(__end_pointer())); } [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reverse_iterator rbegin() _NOEXCEPT { @@ -395,17 +711,8 @@ class vector { // // [vector.capacity], capacity // - [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { - return static_cast(this->__end_ - this->__begin_); - } - [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type capacity() const _NOEXCEPT { - return static_cast(this->__cap_ - this->__begin_); - } - [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool empty() const _NOEXCEPT { - return this->__begin_ == this->__end_; - } [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT { - return std::min(__alloc_traits::max_size(this->__alloc_), numeric_limits::max()); + return std::min(__alloc_traits::max_size(__allocator_ref()), numeric_limits::max()); } _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void reserve(size_type __n); _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void shrink_to_fit() _NOEXCEPT; @@ -415,50 +722,42 @@ class vector { // [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference operator[](size_type __n) _NOEXCEPT { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__n < size(), "vector[] index out of bounds"); - return this->__begin_[__n]; + return __raw_begin()[__n]; } [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference operator[](size_type __n) const _NOEXCEPT { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__n < size(), "vector[] index out of bounds"); - return this->__begin_[__n]; + return __raw_begin()[__n]; } [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference at(size_type __n) { if (__n >= size()) this->__throw_out_of_range(); - return this->__begin_[__n]; + return __raw_begin()[__n]; } [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference at(size_type __n) const { if (__n >= size()) this->__throw_out_of_range(); - return this->__begin_[__n]; + return __raw_begin()[__n]; } [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference front() _NOEXCEPT { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "front() called on an empty vector"); - return *this->__begin_; + return *__raw_begin(); } [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference front() const _NOEXCEPT { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "front() called on an empty vector"); - return *this->__begin_; - } - [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference back() _NOEXCEPT { - _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "back() called on an empty vector"); - return *(this->__end_ - 1); - } - [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference back() const _NOEXCEPT { - _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "back() called on an empty vector"); - return *(this->__end_ - 1); + return *__raw_begin(); } // // [vector.data], data access // [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI value_type* data() _NOEXCEPT { - return std::__to_address(this->__begin_); + return std::__to_address(__raw_begin()); } [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const value_type* data() const _NOEXCEPT { - return std::__to_address(this->__begin_); + return std::__to_address(__raw_begin()); } // @@ -483,7 +782,7 @@ class vector { _LIBCPP_ASSERT_INTERNAL( size() < capacity(), "We assume that we have enough space to insert an element at the end of the vector"); _ConstructTransaction __tx(*this, 1); - __alloc_traits::construct(this->__alloc_, std::__to_address(__tx.__pos_), std::forward<_Args>(__args)...); + __alloc_traits::construct(__allocator_ref(), std::__to_address(__tx.__pos_), std::forward<_Args>(__args)...); ++__tx.__pos_; } @@ -496,7 +795,7 @@ class vector { _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void pop_back() { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "vector::pop_back called on an empty vector"); - this->__destruct_at_end(this->__end_ - 1); + this->__destruct_at_end(__end_pointer() - 1); } _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __position, const_reference __x); @@ -552,41 +851,39 @@ class vector { _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void clear() _NOEXCEPT { size_type __old_size = size(); - __base_destruct_at_end(this->__begin_); + __base_destruct_at_end(__raw_begin()); __annotate_shrink(__old_size); } _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void resize(size_type __sz); _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void resize(size_type __sz, const_reference __x); - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void swap(vector&) + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void swap(vector& __other) #if _LIBCPP_STD_VER >= 14 - _NOEXCEPT; + _NOEXCEPT #else - _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || __is_nothrow_swappable_v); + _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || __is_nothrow_swappable_v) #endif - - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __invariants() const; + { + __base::swap(__other); + } private: - pointer __begin_ = nullptr; - pointer __end_ = nullptr; - _LIBCPP_COMPRESSED_PAIR(pointer, __cap_ = nullptr, allocator_type, __alloc_); - // Allocate space for __n objects // throws length_error if __n > max_size() // throws (probably bad_alloc) if memory run out - // Precondition: __begin_ == __end_ == __cap_ == nullptr + // Precondition: begin() == nullptr + // Precondition: size() == 0 + // Precondition: capacity() == 0 // Precondition: __n > 0 // Postcondition: capacity() >= __n // Postcondition: size() == 0 _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __vallocate(size_type __n) { if (__n > max_size()) this->__throw_length_error(); - auto __allocation = std::__allocate_at_least(this->__alloc_, __n); - __begin_ = __allocation.ptr; - __end_ = __allocation.ptr; - __cap_ = __begin_ + __allocation.count; + auto __allocation = std::__allocate_at_least(__allocator_ref(), __n); + __set_valid_range(__allocation.ptr, static_cast(0)); + __set_capacity(__allocation.count); __annotate_new(0); } @@ -634,7 +931,7 @@ class vector { _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __insert_assign_n_unchecked(_Iterator __first, difference_type __n, pointer __position) { for (pointer __end_position = __position + __n; __position != __end_position; ++__position, (void)++__first) { - __temp_value __tmp(this->__alloc_, *__first); + __temp_value __tmp(__allocator_ref(), *__first); *__position = std::move(__tmp.get()); } } @@ -681,8 +978,8 @@ class vector { // a laxer approach. return std::__make_bounded_iter( std::__wrap_iter(__p), - std::__wrap_iter(this->__begin_), - std::__wrap_iter(this->__cap_)); + std::__wrap_iter(__raw_begin()), + std::__wrap_iter(__raw_capacity())); #else return iterator(__p); #endif // _LIBCPP_ABI_BOUNDED_ITERATORS_IN_VECTOR @@ -693,17 +990,16 @@ class vector { // Bound the iterator according to the capacity, rather than the size. return std::__make_bounded_iter( std::__wrap_iter(__p), - std::__wrap_iter(this->__begin_), - std::__wrap_iter(this->__cap_)); + std::__wrap_iter(__raw_begin()), + std::__wrap_iter(__raw_capacity())); #else return const_iterator(__p); #endif // _LIBCPP_ABI_BOUNDED_ITERATORS_IN_VECTOR } - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void - __swap_out_circular_buffer(__split_buffer& __v); + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __swap_out_circular_buffer(__split_buffer& __v); _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer - __swap_out_circular_buffer(__split_buffer& __v, pointer __p); + __swap_out_circular_buffer(__split_buffer& __v, pointer __p); _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __move_range(pointer __from_s, pointer __from_e, pointer __to); _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __move_assign(vector& __c, true_type) @@ -717,7 +1013,7 @@ class vector { } template - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI inline pointer __emplace_back_slow_path(_Args&&... __args); + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __sentinel_type __emplace_back_slow_path(_Args&&... __args); // The following functions are no-ops outside of AddressSanitizer mode. // We call annotations for every allocator, unless explicitly disabled. @@ -750,14 +1046,14 @@ class vector { struct _ConstructTransaction { _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit _ConstructTransaction(vector& __v, size_type __n) - : __v_(__v), __pos_(__v.__end_), __new_end_(__v.__end_ + __n) { + : __v_(__v), __pos_(__v.__end_pointer()), __new_end_(__pos_ + __n) { __v_.__annotate_increase(__n); } _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI ~_ConstructTransaction() { - __v_.__end_ = __pos_; + __v_.__set_sentinel(__pos_); if (__pos_ != __new_end_) { - __v_.__annotate_shrink(__new_end_ - __v_.__begin_); + __v_.__annotate_shrink(__new_end_ - __v_.__raw_begin()); } } @@ -770,10 +1066,10 @@ class vector { }; _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __base_destruct_at_end(pointer __new_last) _NOEXCEPT { - pointer __soon_to_be_end = this->__end_; + pointer __soon_to_be_end = __end_pointer(); while (__new_last != __soon_to_be_end) - __alloc_traits::destroy(this->__alloc_, std::__to_address(--__soon_to_be_end)); - this->__end_ = __new_last; + __alloc_traits::destroy(__allocator_ref(), std::__to_address(--__soon_to_be_end)); + __set_sentinel(__new_last); } _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __copy_assign_alloc(const vector& __c) { @@ -791,20 +1087,21 @@ class vector { [[__noreturn__]] _LIBCPP_HIDE_FROM_ABI static void __throw_out_of_range() { std::__throw_out_of_range("vector"); } _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __copy_assign_alloc(const vector& __c, true_type) { - if (this->__alloc_ != __c.__alloc_) { + if (__allocator_ref() != __c.__allocator_ref()) { clear(); __annotate_delete(); - __alloc_traits::deallocate(this->__alloc_, this->__begin_, capacity()); - this->__begin_ = this->__end_ = this->__cap_ = nullptr; + __alloc_traits::deallocate(__allocator_ref(), __raw_begin(), capacity()); + __set_valid_range(nullptr, static_cast(0)); + __set_capacity(static_cast<__sentinel_type>(0)); } - this->__alloc_ = __c.__alloc_; + __allocator_ref() = __c.__allocator_ref(); } _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __copy_assign_alloc(const vector&, false_type) {} _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __move_assign_alloc(vector& __c, true_type) _NOEXCEPT_(is_nothrow_move_assignable::value) { - this->__alloc_ = std::move(__c.__alloc_); + __allocator_ref() = std::move(__c.__allocator_ref()); } _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __move_assign_alloc(vector&, false_type) _NOEXCEPT {} @@ -824,19 +1121,17 @@ class vector { return __p; } - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __swap_layouts(__split_buffer<_Tp, allocator_type&>& __sb) { - auto __vector_begin = __begin_; - auto __vector_sentinel = __end_; - auto __vector_cap = __cap_; + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __swap_layouts(__split_buffer& __sb) { + auto __vector_begin = __raw_begin(); + auto __vector_sentinel = __raw_sentinel(); + auto __vector_cap = __raw_capacity(); auto __sb_begin = __sb.begin(); auto __sb_sentinel = __sb.__raw_sentinel(); auto __sb_cap = __sb.__raw_capacity(); - // TODO: replace with __set_valid_range and __set_capacity when vector supports it. - __begin_ = __sb_begin; - __end_ = __sb_sentinel; - __cap_ = __sb_cap; + __set_valid_range(__sb_begin, __sb_sentinel); + __set_capacity(__sb_cap); __sb.__set_valid_range(__vector_begin, __vector_sentinel); __sb.__set_capacity(__vector_cap); @@ -864,47 +1159,53 @@ template vector, _Alloc>; #endif -// __swap_out_circular_buffer relocates the objects in [__begin_, __end_) into the front of __v and swaps the buffers of -// *this and __v. It is assumed that __v provides space for exactly (__end_ - __begin_) objects in the front. This +// __swap_out_circular_buffer relocates the objects in [__raw_begin(), size()) into the front of __v and swaps the +// buffers of *this and __v. It is assumed that __v provides space for exactly size() objects in the front. This // function has a strong exception guarantee. template -_LIBCPP_CONSTEXPR_SINCE_CXX20 void -vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer& __v) { +_LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer& __v) { __annotate_delete(); auto __new_begin = __v.begin() - size(); std::__uninitialized_allocator_relocate( - this->__alloc_, std::__to_address(__begin_), std::__to_address(__end_), std::__to_address(__new_begin)); + __allocator_ref(), + std::__to_address(__raw_begin()), + std::__to_address(__end_pointer()), + std::__to_address(__new_begin)); __v.__set_valid_range(__new_begin, __v.end()); - __end_ = __begin_; // All the objects have been destroyed by relocating them. + __set_sentinel(static_cast(0)); // All the objects have been destroyed by relocating them. + // __v.__size_ += __size_; __swap_layouts(__v); __v.__set_data(__v.begin()); __annotate_new(size()); } -// __swap_out_circular_buffer relocates the objects in [__begin_, __p) into the front of __v, the objects in -// [__p, __end_) into the back of __v and swaps the buffers of *this and __v. It is assumed that __v provides space for -// exactly (__p - __begin_) objects in the front and space for at least (__end_ - __p) objects in the back. This -// function has a strong exception guarantee if __begin_ == __p || __end_ == __p. +// __swap_out_circular_buffer relocates the objects in [__raw_begin(), __p) into the front of __v, the objects in +// [__p, end()) into the back of __v and swaps the buffers of *this and __v. It is assumed that __v provides space for +// exactly (__p - __raw_begin()) objects in the front and space for at least (size() - __p) objects in the back. This +// function has a strong exception guarantee if __raw_begin() == __p || size() == __p. template _LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::pointer -vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer& __v, pointer __p) { +vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer& __v, pointer __p) { __annotate_delete(); pointer __ret = __v.begin(); - // Relocate [__p, __end_) first to avoid having a hole in [__begin_, __end_) - // in case something in [__begin_, __p) throws. + pointer __end = __end_pointer(); + // Relocate [__p, __end) first to avoid having a hole in [__raw_begin(), __end) + // in case something in [__raw_begin(), __p) throws. std::__uninitialized_allocator_relocate( - this->__alloc_, std::__to_address(__p), std::__to_address(__end_), std::__to_address(__v.end())); - auto __relocated_so_far = __end_ - __p; + __allocator_ref(), std::__to_address(__p), std::__to_address(__end), std::__to_address(__v.end())); + auto __relocated_so_far = __end - __p; __v.__set_sentinel(__v.end() + __relocated_so_far); - __end_ = __p; // The objects in [__p, __end_) have been destroyed by relocating them. - auto __new_begin = __v.begin() - (__p - __begin_); + __set_sentinel( + __raw_sentinel() - __relocated_so_far); // The objects in [__p, __end_) have been destroyed by relocating them. + auto __new_begin = __v.begin() - (__p - __raw_begin()); std::__uninitialized_allocator_relocate( - this->__alloc_, std::__to_address(__begin_), std::__to_address(__p), std::__to_address(__new_begin)); - __v.__set_valid_range(__new_begin, __v.end()); - __end_ = __begin_; // All the objects have been destroyed by relocating them. + __allocator_ref(), std::__to_address(__raw_begin()), std::__to_address(__p), std::__to_address(__new_begin)); + __v.__set_valid_range(__new_begin, __v.size() + size()); + __set_sentinel(static_cast(0)); // All the objects have been destroyed by relocating them. + __swap_layouts(__v); __v.__set_data(__v.begin()); __annotate_new(size()); @@ -913,11 +1214,12 @@ vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::__vdeallocate() _NOEXCEPT { - if (this->__begin_ != nullptr) { + if (__raw_begin() != nullptr) { clear(); __annotate_delete(); - __alloc_traits::deallocate(this->__alloc_, this->__begin_, capacity()); - this->__begin_ = this->__end_ = this->__cap_ = nullptr; + __alloc_traits::deallocate(__allocator_ref(), __raw_begin(), capacity()); + __set_valid_range(nullptr, static_cast(0)); + __set_capacity(static_cast(0)); } } @@ -934,7 +1236,7 @@ vector<_Tp, _Allocator>::__recommend(size_type __new_size) const { return std::max(2 * __cap, __new_size); } -// Default constructs __n objects starting at __end_ +// Default constructs __n objects starting at __end_pointer() // throws if construction throws // Precondition: __n > 0 // Precondition: size() + __n <= capacity() @@ -944,11 +1246,11 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::__construct_at_end(s _ConstructTransaction __tx(*this, __n); const_pointer __new_end = __tx.__new_end_; for (pointer __pos = __tx.__pos_; __pos != __new_end; __tx.__pos_ = ++__pos) { - __alloc_traits::construct(this->__alloc_, std::__to_address(__pos)); + __alloc_traits::construct(__allocator_ref(), std::__to_address(__pos)); } } -// Copy constructs __n objects starting at __end_ from __x +// Copy constructs __n objects starting at __end_pointer() from __x // throws if construction throws // Precondition: __n > 0 // Precondition: size() + __n <= capacity() @@ -960,7 +1262,7 @@ vector<_Tp, _Allocator>::__construct_at_end(size_type __n, const_reference __x) _ConstructTransaction __tx(*this, __n); const_pointer __new_end = __tx.__new_end_; for (pointer __pos = __tx.__pos_; __pos != __new_end; __tx.__pos_ = ++__pos) { - __alloc_traits::construct(this->__alloc_, std::__to_address(__pos), __x); + __alloc_traits::construct(__allocator_ref(), std::__to_address(__pos), __x); } } @@ -969,34 +1271,35 @@ template _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::__construct_at_end(_InputIterator __first, _Sentinel __last, size_type __n) { _ConstructTransaction __tx(*this, __n); - __tx.__pos_ = std::__uninitialized_allocator_copy(this->__alloc_, std::move(__first), std::move(__last), __tx.__pos_); + __tx.__pos_ = + std::__uninitialized_allocator_copy(__allocator_ref(), std::move(__first), std::move(__last), __tx.__pos_); } -// Default constructs __n objects starting at __end_ +// Default constructs __n objects starting at __end_pointer() // throws if construction throws // Postcondition: size() == size() + __n // Exception safety: strong. template _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::__append(size_type __n) { - if (static_cast(this->__cap_ - this->__end_) >= __n) + if (__remaining_capacity() >= __n) this->__construct_at_end(__n); else { - __split_buffer __v(__recommend(size() + __n), size(), this->__alloc_); + __split_buffer __v(__recommend(size() + __n), size(), __allocator_ref()); __v.__construct_at_end(__n); __swap_out_circular_buffer(__v); } } -// Default constructs __n objects starting at __end_ +// Default constructs __n objects starting at __end_pointer() // throws if construction throws // Postcondition: size() == size() + __n // Exception safety: strong. template _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::__append(size_type __n, const_reference __x) { - if (static_cast(this->__cap_ - this->__end_) >= __n) + if (__remaining_capacity() >= __n) this->__construct_at_end(__n, __x); else { - __split_buffer __v(__recommend(size() + __n), size(), this->__alloc_); + __split_buffer __v(__recommend(size() + __n), size(), __allocator_ref()); __v.__construct_at_end(__n, __x); __swap_out_circular_buffer(__v); } @@ -1009,22 +1312,22 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI vector<_Tp, _Allocato #else _NOEXCEPT_(is_nothrow_move_constructible::value) #endif - : __alloc_(std::move(__x.__alloc_)) { - this->__begin_ = __x.__begin_; - this->__end_ = __x.__end_; - this->__cap_ = __x.__cap_; - __x.__begin_ = __x.__end_ = __x.__cap_ = nullptr; + : __base(std::move(__x.__allocator_ref())) { + __set_valid_range(__x.__raw_begin(), __x.__raw_sentinel()); + __set_capacity(__x.__raw_capacity()); + __x.__set_valid_range(nullptr, static_cast(0)); + __x.__set_capacity(static_cast(0)); } template _LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI vector<_Tp, _Allocator>::vector(vector&& __x, const __type_identity_t& __a) - : __alloc_(__a) { - if (__a == __x.__alloc_) { - this->__begin_ = __x.__begin_; - this->__end_ = __x.__end_; - this->__cap_ = __x.__cap_; - __x.__begin_ = __x.__end_ = __x.__cap_ = nullptr; + : __base(__a) { + if (__a == __x.__allocator_ref()) { + __set_valid_range(__x.__raw_begin(), __x.__raw_sentinel()); + __set_capacity(__x.__raw_capacity()); + __x.__set_valid_range(nullptr, static_cast(0)); + __x.__set_capacity(static_cast(0)); } else { typedef move_iterator _Ip; __init_with_size(_Ip(__x.begin()), _Ip(__x.end()), __x.size()); @@ -1034,7 +1337,7 @@ vector<_Tp, _Allocator>::vector(vector&& __x, const __type_identity_t _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::__move_assign(vector& __c, false_type) _NOEXCEPT_(__alloc_traits::is_always_equal::value) { - if (this->__alloc_ != __c.__alloc_) { + if (__allocator_ref() != __c.__allocator_ref()) { typedef move_iterator _Ip; assign(_Ip(__c.begin()), _Ip(__c.end())); } else @@ -1046,10 +1349,10 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::__move_assign(vector _NOEXCEPT_(is_nothrow_move_assignable::value) { __vdeallocate(); __move_assign_alloc(__c); // this can throw - this->__begin_ = __c.__begin_; - this->__end_ = __c.__end_; - this->__cap_ = __c.__cap_; - __c.__begin_ = __c.__end_ = __c.__cap_ = nullptr; + __set_valid_range(__c.__raw_begin(), __c.__raw_sentinel()); + __set_capacity(__c.__raw_capacity()); + __c.__set_valid_range(nullptr, static_cast(0)); + __c.__set_capacity(static_cast(0)); } template @@ -1057,7 +1360,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI vector<_Tp, _Allocato vector<_Tp, _Allocator>::operator=(const vector& __x) { if (this != std::addressof(__x)) { __copy_assign_alloc(__x); - assign(__x.__begin_, __x.__end_); + assign(__x.__raw_begin(), __x.__end_pointer()); } return *this; } @@ -1066,10 +1369,11 @@ template template _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void vector<_Tp, _Allocator>::__assign_with_sentinel(_Iterator __first, _Sentinel __last) { - pointer __cur = __begin_; - for (; __first != __last && __cur != __end_; ++__first, (void)++__cur) + pointer __cur = __raw_begin(); + pointer __end = __end_pointer(); + for (; __first != __last && __cur != __end; ++__first, (void)++__cur) *__cur = *__first; - if (__cur != __end_) { + if (__cur != __end) { __destruct_at_end(__cur); } else { for (; __first != __last; ++__first) @@ -1085,15 +1389,15 @@ vector<_Tp, _Allocator>::__assign_with_size(_Iterator __first, _Sentinel __last, if (__new_size <= capacity()) { if (__new_size > size()) { #if _LIBCPP_STD_VER >= 23 - auto __mid = ranges::copy_n(std::move(__first), size(), this->__begin_).in; + auto __mid = ranges::copy_n(std::move(__first), size(), __raw_begin()).in; __construct_at_end(std::move(__mid), std::move(__last), __new_size - size()); #else _Iterator __mid = std::next(__first, size()); - std::copy(__first, __mid, this->__begin_); + std::copy(__first, __mid, __raw_begin()); __construct_at_end(__mid, __last, __new_size - size()); #endif } else { - pointer __m = std::__copy(std::move(__first), __last, this->__begin_).second; + pointer __m = std::__copy(std::move(__first), __last, __raw_begin()).second; this->__destruct_at_end(__m); } } else { @@ -1107,11 +1411,11 @@ template _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::assign(size_type __n, const_reference __u) { if (__n <= capacity()) { size_type __s = size(); - std::fill_n(this->__begin_, std::min(__n, __s), __u); + std::fill_n(__raw_begin(), std::min(__n, __s), __u); if (__n > __s) __construct_at_end(__n - __s, __u); else - this->__destruct_at_end(this->__begin_ + __n); + this->__destruct_at_end(__raw_begin() + __n); } else { __vdeallocate(); __vallocate(__recommend(static_cast(__n))); @@ -1124,7 +1428,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::reserve(size_type __ if (__n > capacity()) { if (__n > max_size()) this->__throw_length_error(); - __split_buffer __v(__n, size(), this->__alloc_); + __split_buffer __v(__n, size(), __allocator_ref()); __swap_out_circular_buffer(__v); } } @@ -1135,7 +1439,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::shrink_to_fit() _NOE #if _LIBCPP_HAS_EXCEPTIONS try { #endif // _LIBCPP_HAS_EXCEPTIONS - __split_buffer __v(size(), size(), this->__alloc_); + __split_buffer __v(size(), size(), __allocator_ref()); // The Standard mandates shrink_to_fit() does not increase the capacity. // With equal capacity keep the existing buffer. This avoids extra work // due to swapping the elements. @@ -1150,15 +1454,15 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::shrink_to_fit() _NOE template template -_LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::pointer +_LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::__sentinel_type vector<_Tp, _Allocator>::__emplace_back_slow_path(_Args&&... __args) { - __split_buffer __v(__recommend(size() + 1), size(), this->__alloc_); + __split_buffer __v(__recommend(size() + 1), size(), __allocator_ref()); // __v.emplace_back(std::forward<_Args>(__args)...); pointer __end = __v.end(); - __alloc_traits::construct(this->__alloc_, std::__to_address(__end), std::forward<_Args>(__args)...); + __alloc_traits::construct(__allocator_ref(), std::__to_address(__end), std::forward<_Args>(__args)...); __v.__set_sentinel(++__end); __swap_out_circular_buffer(__v); - return this->__end_; + return __raw_sentinel(); } // This makes the compiler inline `__else()` if `__cond` is known to be false. Currently LLVM doesn't do that without @@ -1188,18 +1492,18 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 inline void #endif vector<_Tp, _Allocator>::emplace_back(_Args&&... __args) { - pointer __end = this->__end_; + auto __current_sentinel = __raw_sentinel(); std::__if_likely_else( - __end < this->__cap_, + __current_sentinel < __raw_capacity(), [&] { __emplace_back_assume_capacity(std::forward<_Args>(__args)...); - ++__end; + ++__current_sentinel; }, - [&] { __end = __emplace_back_slow_path(std::forward<_Args>(__args)...); }); + [&] { __current_sentinel = __emplace_back_slow_path(std::forward<_Args>(__args)...); }); - this->__end_ = __end; + __set_sentinel(__current_sentinel); #if _LIBCPP_STD_VER >= 17 - return *(__end - 1); + return back(); #endif } @@ -1209,8 +1513,8 @@ vector<_Tp, _Allocator>::erase(const_iterator __position) { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( __position != end(), "vector::erase(iterator) called with a non-dereferenceable iterator"); difference_type __ps = __position - cbegin(); - pointer __p = this->__begin_ + __ps; - this->__destruct_at_end(std::move(__p + 1, this->__end_, __p)); + pointer __p = __raw_begin() + __ps; + this->__destruct_at_end(std::move(__p + 1, __end_pointer(), __p)); return __make_iter(__p); } @@ -1218,9 +1522,9 @@ template _LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::iterator vector<_Tp, _Allocator>::erase(const_iterator __first, const_iterator __last) { _LIBCPP_ASSERT_VALID_INPUT_RANGE(__first <= __last, "vector::erase(first, last) called with invalid range"); - pointer __p = this->__begin_ + (__first - begin()); + pointer __p = __raw_begin() + (__first - begin()); if (__first != __last) { - this->__destruct_at_end(std::move(__p + (__last - __first), this->__end_, __p)); + this->__destruct_at_end(std::move(__p + (__last - __first), __end_pointer(), __p)); } return __make_iter(__p); } @@ -1228,13 +1532,13 @@ vector<_Tp, _Allocator>::erase(const_iterator __first, const_iterator __last) { template _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::__move_range(pointer __from_s, pointer __from_e, pointer __to) { - pointer __old_last = this->__end_; + pointer __old_last = __end_pointer(); difference_type __n = __old_last - __to; { pointer __i = __from_s + __n; _ConstructTransaction __tx(*this, __from_e - __i); for (pointer __pos = __tx.__pos_; __i < __from_e; ++__i, (void)++__pos, __tx.__pos_ = __pos) { - __alloc_traits::construct(this->__alloc_, std::__to_address(__pos), std::move(*__i)); + __alloc_traits::construct(__allocator_ref(), std::__to_address(__pos), std::move(*__i)); } } std::move_backward(__from_s, __from_s + __n, __old_last); @@ -1243,19 +1547,20 @@ vector<_Tp, _Allocator>::__move_range(pointer __from_s, pointer __from_e, pointe template _LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::iterator vector<_Tp, _Allocator>::insert(const_iterator __position, const_reference __x) { - pointer __p = this->__begin_ + (__position - begin()); - if (this->__end_ < this->__cap_) { - if (__p == this->__end_) { + pointer __p = __raw_begin() + (__position - begin()); + if (!__is_full()) { + pointer __end = __end_pointer(); + if (__p == __end) { __emplace_back_assume_capacity(__x); } else { - __move_range(__p, this->__end_, __p + 1); + __move_range(__p, __end, __p + 1); const_pointer __xr = pointer_traits::pointer_to(__x); - if (std::__is_pointer_in_range(std::__to_address(__p), std::__to_address(__end_), std::addressof(__x))) + if (std::__is_pointer_in_range(std::__to_address(__p), std::__to_address(__end), std::addressof(__x))) ++__xr; *__p = *__xr; } } else { - __split_buffer __v(__recommend(size() + 1), __p - this->__begin_, this->__alloc_); + __split_buffer __v(__recommend(size() + 1), __p - __raw_begin(), __allocator_ref()); __v.emplace_back(__x); __p = __swap_out_circular_buffer(__v, __p); } @@ -1265,16 +1570,17 @@ vector<_Tp, _Allocator>::insert(const_iterator __position, const_reference __x) template _LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::iterator vector<_Tp, _Allocator>::insert(const_iterator __position, value_type&& __x) { - pointer __p = this->__begin_ + (__position - begin()); - if (this->__end_ < this->__cap_) { - if (__p == this->__end_) { + pointer __p = __raw_begin() + (__position - begin()); + if (!__is_full()) { + pointer __end = __end_pointer(); + if (__p == __end) { __emplace_back_assume_capacity(std::move(__x)); } else { - __move_range(__p, this->__end_, __p + 1); + __move_range(__p, __end, __p + 1); *__p = std::move(__x); } } else { - __split_buffer __v(__recommend(size() + 1), __p - this->__begin_, this->__alloc_); + __split_buffer __v(__recommend(size() + 1), __p - __raw_begin(), __allocator_ref()); __v.emplace_back(std::move(__x)); __p = __swap_out_circular_buffer(__v, __p); } @@ -1285,17 +1591,18 @@ template template _LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::iterator vector<_Tp, _Allocator>::emplace(const_iterator __position, _Args&&... __args) { - pointer __p = this->__begin_ + (__position - begin()); - if (this->__end_ < this->__cap_) { - if (__p == this->__end_) { + pointer __p = __raw_begin() + (__position - begin()); + if (!__is_full()) { + pointer __end = __end_pointer(); + if (__p == __end) { __emplace_back_assume_capacity(std::forward<_Args>(__args)...); } else { - __temp_value __tmp(this->__alloc_, std::forward<_Args>(__args)...); - __move_range(__p, this->__end_, __p + 1); + __temp_value __tmp(__allocator_ref(), std::forward<_Args>(__args)...); + __move_range(__p, __end, __p + 1); *__p = std::move(__tmp.get()); } } else { - __split_buffer __v(__recommend(size() + 1), __p - this->__begin_, this->__alloc_); + __split_buffer __v(__recommend(size() + 1), __p - __raw_begin(), __allocator_ref()); __v.emplace_back(std::forward<_Args>(__args)...); __p = __swap_out_circular_buffer(__v, __p); } @@ -1305,25 +1612,26 @@ vector<_Tp, _Allocator>::emplace(const_iterator __position, _Args&&... __args) { template _LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::iterator vector<_Tp, _Allocator>::insert(const_iterator __position, size_type __n, const_reference __x) { - pointer __p = this->__begin_ + (__position - begin()); + pointer __p = __raw_begin() + (__position - begin()); if (__n > 0) { - if (__n <= static_cast(this->__cap_ - this->__end_)) { + if (__n <= __remaining_capacity()) { size_type __old_n = __n; - pointer __old_last = this->__end_; - if (__n > static_cast(this->__end_ - __p)) { - size_type __cx = __n - (this->__end_ - __p); + pointer __end = __end_pointer(); + pointer __old_last = __end; + if (__n > static_cast(__end - __p)) { + size_type __cx = __n - (__end - __p); __construct_at_end(__cx, __x); __n -= __cx; } if (__n > 0) { __move_range(__p, __old_last, __p + __old_n); const_pointer __xr = pointer_traits::pointer_to(__x); - if (std::__is_pointer_in_range(std::__to_address(__p), std::__to_address(__end_), std::addressof(__x))) + if (std::__is_pointer_in_range(std::__to_address(__p), std::__to_address(__end), std::addressof(__x))) __xr += __old_n; std::fill_n(__p, __n, *__xr); } } else { - __split_buffer __v(__recommend(size() + __n), __p - this->__begin_, this->__alloc_); + __split_buffer __v(__recommend(size() + __n), __p - __raw_begin(), __allocator_ref()); __v.__construct_at_end(__n, __x); __p = __swap_out_circular_buffer(__v, __p); } @@ -1336,27 +1644,35 @@ template _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI typename vector<_Tp, _Allocator>::iterator vector<_Tp, _Allocator>::__insert_with_sentinel(const_iterator __position, _InputIterator __first, _Sentinel __last) { difference_type __off = __position - begin(); - pointer __p = this->__begin_ + __off; - pointer __old_last = this->__end_; - for (; this->__end_ != this->__cap_ && __first != __last; ++__first) + pointer __p = __raw_begin() + __off; + pointer __old_last = __end_pointer(); + for (; !__is_full() && __first != __last; ++__first) __emplace_back_assume_capacity(*__first); if (__first == __last) - (void)std::rotate(__p, __old_last, this->__end_); + (void)std::rotate(__p, __old_last, __end_pointer()); else { - __split_buffer __v(__alloc_); - auto __guard = std::__make_exception_guard( - _AllocatorDestroyRangeReverse(__alloc_, __old_last, this->__end_)); + __split_buffer __v(__allocator_ref()); + pointer __end = __end_pointer(); + auto __guard = std::__make_exception_guard( + _AllocatorDestroyRangeReverse(__allocator_ref(), __old_last, __end)); __v.__construct_at_end_with_sentinel(std::move(__first), std::move(__last)); - __split_buffer __merged( - __recommend(size() + __v.size()), __off, __alloc_); // has `__off` positions available at the front + __split_buffer __merged( + __recommend(size() + __v.size()), __off, __allocator_ref()); // has `__off` positions available at the front std::__uninitialized_allocator_relocate( - __alloc_, std::__to_address(__old_last), std::__to_address(this->__end_), std::__to_address(__merged.end())); - __guard.__complete(); // Release the guard once objects in [__old_last_, __end_) have been successfully relocated. - __merged.__set_sentinel(__merged.end() + (this->__end_ - __old_last)); - this->__end_ = __old_last; + __allocator_ref(), + std::__to_address(__old_last), + std::__to_address(__end_pointer()), + std::__to_address(__merged.end())); + __guard.__complete(); // Release the guard once objects in [__old_last_, __end_pointer()) have been successfully + // relocated. + __merged.__set_sentinel(__merged.end() + (__end_pointer() - __old_last)); + __set_sentinel(__old_last); std::__uninitialized_allocator_relocate( - __alloc_, std::__to_address(__v.begin()), std::__to_address(__v.end()), std::__to_address(__merged.end())); + __allocator_ref(), + std::__to_address(__v.begin()), + std::__to_address(__v.end()), + std::__to_address(__merged.end())); __merged.__set_sentinel(__merged.size() + __v.size()); __v.__set_sentinel(__v.begin()); __p = __swap_out_circular_buffer(__merged, __p); @@ -1369,16 +1685,17 @@ template _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI typename vector<_Tp, _Allocator>::iterator vector<_Tp, _Allocator>::__insert_with_size( const_iterator __position, _Iterator __first, _Sentinel __last, difference_type __n) { - pointer __p = this->__begin_ + (__position - begin()); + pointer __p = __raw_begin() + (__position - begin()); if (__n > 0) { - if (__n <= this->__cap_ - this->__end_) { - pointer __old_last = this->__end_; - difference_type __dx = this->__end_ - __p; + if (__n <= static_cast(__remaining_capacity())) { + pointer __end = __end_pointer(); + pointer __old_last = __end; + difference_type __dx = __end - __p; if (__n > __dx) { #if _LIBCPP_STD_VER >= 23 if constexpr (!forward_iterator<_Iterator>) { __construct_at_end(std::move(__first), std::move(__last), __n); - std::rotate(__p, __old_last, this->__end_); + std::rotate(__p, __old_last, __end); } else #endif { @@ -1394,7 +1711,7 @@ vector<_Tp, _Allocator>::__insert_with_size( __insert_assign_n_unchecked(std::move(__first), __n, __p); } } else { - __split_buffer __v(__recommend(size() + __n), __p - this->__begin_, this->__alloc_); + __split_buffer __v(__recommend(size() + __n), __p - __raw_begin(), __allocator_ref()); __v.__construct_at_end_with_size(std::move(__first), __n); __p = __swap_out_circular_buffer(__v, __p); } @@ -1408,7 +1725,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::resize(size_type __s if (__cs < __sz) this->__append(__sz - __cs); else if (__cs > __sz) - this->__destruct_at_end(this->__begin_ + __sz); + this->__destruct_at_end(__raw_begin() + __sz); } template @@ -1417,49 +1734,15 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::resize(size_type __s if (__cs < __sz) this->__append(__sz - __cs, __x); else if (__cs > __sz) - this->__destruct_at_end(this->__begin_ + __sz); -} - -template -_LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::swap(vector& __x) -#if _LIBCPP_STD_VER >= 14 - _NOEXCEPT -#else - _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || __is_nothrow_swappable_v) -#endif -{ - _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR( - __alloc_traits::propagate_on_container_swap::value || this->__alloc_ == __x.__alloc_, - "vector::swap: Either propagate_on_container_swap must be true" - " or the allocators must compare equal"); - std::swap(this->__begin_, __x.__begin_); - std::swap(this->__end_, __x.__end_); - std::swap(this->__cap_, __x.__cap_); - std::__swap_allocator(this->__alloc_, __x.__alloc_); -} - -template -_LIBCPP_CONSTEXPR_SINCE_CXX20 bool vector<_Tp, _Allocator>::__invariants() const { - if (this->__begin_ == nullptr) { - if (this->__end_ != nullptr || this->__cap_ != nullptr) - return false; - } else { - if (this->__begin_ > this->__end_) - return false; - if (this->__begin_ == this->__cap_) - return false; - if (this->__end_ > this->__cap_) - return false; - } - return true; + this->__destruct_at_end(__raw_begin() + __sz); } #if _LIBCPP_STD_VER >= 20 -template <> -inline constexpr bool __format::__enable_insertable> = true; +template +inline constexpr bool __format::__enable_insertable> = true; # if _LIBCPP_HAS_WIDE_CHARACTERS -template <> -inline constexpr bool __format::__enable_insertable> = true; +template +inline constexpr bool __format::__enable_insertable> = true; # endif #endif // _LIBCPP_STD_VER >= 20 diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.swap/ranges.swap_ranges.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.swap/ranges.swap_ranges.pass.cpp index 85557ecbbfabc..da42ce56db30a 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.swap/ranges.swap_ranges.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.swap/ranges.swap_ranges.pass.cpp @@ -67,22 +67,6 @@ TEST_CONSTEXPR_CXX20 void test_iterators() { } } -template -constexpr void test_vector_bool() { - { // Test swap_ranges() with aligned bytes - std::vector f(N, false), t(N, true); - std::ranges::swap_ranges(f, t); - assert(std::all_of(f.begin(), f.end(), [](bool b) { return b; })); - assert(std::all_of(t.begin(), t.end(), [](bool b) { return !b; })); - } - { // Test swap_ranges() with unaligned bytes - std::vector f(N, false), t(N + 8, true); - std::ranges::swap_ranges(f.begin(), f.end(), t.begin() + 4, t.end() - 4); - assert(std::all_of(f.begin(), f.end(), [](bool b) { return b; })); - assert(std::all_of(t.begin() + 4, t.end() - 4, [](bool b) { return !b; })); - } -} - constexpr bool test() { { // Validate swapping ranges directly std::array r1 = {1, 2, 3}; @@ -183,15 +167,34 @@ constexpr bool test() { }); }); - { // Test vector::iterator optimization - test_vector_bool<8>(); - test_vector_bool<19>(); - test_vector_bool<32>(); - test_vector_bool<49>(); - test_vector_bool<64>(); - test_vector_bool<199>(); - test_vector_bool<256>(); + return true; +} + +// Test vector::iterator optimization +template +constexpr void test_vector_bool() { + { // Test swap_ranges() with aligned bytes + std::vector f(N, false), t(N, true); + std::ranges::swap_ranges(f, t); + assert(std::all_of(f.begin(), f.end(), [](bool b) { return b; })); + assert(std::all_of(t.begin(), t.end(), [](bool b) { return !b; })); } + { // Test swap_ranges() with unaligned bytes + std::vector f(N, false), t(N + 8, true); + std::ranges::swap_ranges(f.begin(), f.end(), t.begin() + 4, t.end() - 4); + assert(std::all_of(f.begin(), f.end(), [](bool b) { return b; })); + assert(std::all_of(t.begin() + 4, t.end() - 4, [](bool b) { return !b; })); + } +} + +constexpr bool test_vector_bool() { + test_vector_bool<8>(); + test_vector_bool<19>(); + test_vector_bool<32>(); + test_vector_bool<49>(); + test_vector_bool<64>(); + test_vector_bool<199>(); + test_vector_bool<256>(); return true; } @@ -201,5 +204,8 @@ int main(int, char**) { test(); static_assert(test()); + test_vector_bool(); + static_assert(test_vector_bool()); + return 0; } diff --git a/libcxx/utils/gdb/libcxx/printers.py b/libcxx/utils/gdb/libcxx/printers.py index 1c8ef6d7feb97..1bfdd718e36bc 100644 --- a/libcxx/utils/gdb/libcxx/printers.py +++ b/libcxx/utils/gdb/libcxx/printers.py @@ -13,6 +13,7 @@ from __future__ import print_function import re +import sys import gdb import gdb.printing @@ -351,17 +352,28 @@ def __init__(self, val): """Set val, length, capacity, and iterator for bool and normal vectors.""" self.val = val self.typename = _remove_generics(_prettify_typename(val.type)) - begin = self.val["__begin_"] if self.val.type.template_argument(0).code == gdb.TYPE_CODE_BOOL: + begin = self.val["__begin_"] self.typename += "" self.length = self.val["__size_"] bits_per_word = self.val["__bits_per_word"] self.capacity = self.val["__cap_"] * bits_per_word self.iterator = self._VectorBoolIterator(begin, self.length, bits_per_word) else: - end = self.val["__end_"] + for i in val.type.fields(): + if i.is_base_class: + base = val[i] + break + + begin = base["__begin_"] + end = base["__end_"] self.length = end - begin - self.capacity = self.val["__cap_"] - begin + for i in base.type.fields(): + if i.name == "__cap_": + self.capacity = base["__cap_"] - begin + elif i.name == None: + self.capacity = base[i]["__cap_"] - begin + break self.iterator = self._VectorIterator(begin, end) def to_string(self):