diff --git a/libcxx/include/__split_buffer b/libcxx/include/__split_buffer index 21e58f4abc6b3..04bbfd6c67670 100644 --- a/libcxx/include/__split_buffer +++ b/libcxx/include/__split_buffer @@ -13,10 +13,12 @@ #include <__algorithm/max.h> #include <__algorithm/move.h> #include <__algorithm/move_backward.h> +#include <__assert> #include <__config> #include <__iterator/distance.h> #include <__iterator/iterator_traits.h> #include <__iterator/move_iterator.h> +#include <__memory/addressof.h> #include <__memory/allocate_at_least.h> #include <__memory/allocator.h> #include <__memory/allocator_traits.h> @@ -45,13 +47,149 @@ _LIBCPP_PUSH_MACROS _LIBCPP_BEGIN_NAMESPACE_STD -// __split_buffer allocates a contiguous chunk of memory and stores objects in the range [__begin_, __end_). -// It has uninitialized memory in the ranges [__first_, __begin_) and [__end_, __cap_). That allows -// it to grow both in the front and back without having to move the data. +template +class __split_buffer_pointer_layout { +protected: + using value_type = _Tp; + using allocator_type = _Allocator; + using __alloc_rr _LIBCPP_NODEBUG = __libcpp_remove_reference_t; + using __alloc_traits _LIBCPP_NODEBUG = allocator_traits<__alloc_rr>; + 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 iterator = pointer; + using const_iterator = const_pointer; -template > -struct __split_buffer { public: + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __split_buffer_pointer_layout() = default; + + _LIBCPP_CONSTEXPR_SINCE_CXX20 + _LIBCPP_HIDE_FROM_ABI explicit __split_buffer_pointer_layout(const allocator_type& __alloc) + : __alloc_(__alloc) {} + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer __data() _NOEXCEPT { return __data_; } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_pointer __data() const _NOEXCEPT { return __data_; } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer begin() _NOEXCEPT { return __begin_; } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_pointer begin() const _NOEXCEPT { return __begin_; } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer end() _NOEXCEPT { return __end_; } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer end() const _NOEXCEPT { return __end_; } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { + return static_cast(__end_ - __begin_); + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool empty() const _NOEXCEPT { return __begin_ == __end_; } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type capacity() const _NOEXCEPT { + return static_cast(__cap_ - __data_); + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI allocator_type& __get_allocator() _NOEXCEPT { return __alloc_; } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI allocator_type const& __get_allocator() const _NOEXCEPT { + return __alloc_; + } + + // Returns the sentinel object directly. Should be used in conjunction with automatic type deduction, + // not explicit types. + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer __sentinel() const _NOEXCEPT { return __end_; } + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer __raw_capacity() const _NOEXCEPT { return __cap_; } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_data(pointer __new_first) _NOEXCEPT { + __data_ = __new_first; + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void + __set_valid_range(pointer __new_begin, pointer __new_end) _NOEXCEPT { + __begin_ = __new_begin; + __end_ = __new_end; + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void + __set_valid_range(pointer __new_begin, size_type __new_size) _NOEXCEPT { + __begin_ = __new_begin; + __end_ = __begin_ + __new_size; + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_sentinel(pointer __new_end) _NOEXCEPT { + _LIBCPP_ASSERT_INTERNAL(__data_ <= __new_end, "__new_end cannot precede __data_"); + __end_ = __new_end; + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_sentinel(size_type __new_size) _NOEXCEPT { + __end_ = __begin_ + __new_size; + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_capacity(size_type __new_capacity) _NOEXCEPT { + __cap_ = __data_ + __new_capacity; + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_capacity(pointer __new_capacity) _NOEXCEPT { + __cap_ = __new_capacity; + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __front_spare() const _NOEXCEPT { + return static_cast(__begin_ - __data_); + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __back_spare() const _NOEXCEPT { + return static_cast(__cap_ - __end_); + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference back() _NOEXCEPT { return *(__end_ - 1); } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference back() const _NOEXCEPT { return *(__end_ - 1); } + + template + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __swap_without_allocator(_OtherLayout& __other) _NOEXCEPT { + std::swap(__data_, __other.__data_); + std::swap(__begin_, __other.__begin_); + std::swap(__cap_, __other.__cap_); + std::swap(__end_, __other.__end_); + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void swap(__split_buffer_pointer_layout& __other) _NOEXCEPT { + __swap_without_allocator(__other); + std::__swap_allocator(__alloc_, __other.__alloc_); + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __reset() _NOEXCEPT { + __data_ = nullptr; + __begin_ = nullptr; + __end_ = nullptr; + __cap_ = nullptr; + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void + __copy_without_alloc(__split_buffer_pointer_layout const& __other) + _NOEXCEPT_(is_nothrow_copy_assignable::value) { + __data_ = __other.__data_; + __begin_ = __other.__begin_; + __cap_ = __other.__cap_; + __end_ = __other.__end_; + } + +private: + pointer __data_ = nullptr; + pointer __begin_ = nullptr; + pointer __end_ = nullptr; + _LIBCPP_COMPRESSED_PAIR(pointer, __cap_ = nullptr, allocator_type, __alloc_); + + template + friend class __split_buffer_pointer_layout; +}; + +template +class __split_buffer_size_layout { +protected: using value_type = _Tp; using allocator_type = _Allocator; using __alloc_rr _LIBCPP_NODEBUG = __libcpp_remove_reference_t; @@ -65,6 +203,170 @@ public: using iterator = pointer; using const_iterator = const_pointer; +public: + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __split_buffer_size_layout() = default; + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __split_buffer_size_layout(const allocator_type& __alloc) + : __alloc_(__alloc) {} + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer __data() _NOEXCEPT { return __data_; } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_pointer __data() const _NOEXCEPT { return __data_; } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer begin() _NOEXCEPT { return __begin_; } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_pointer begin() const _NOEXCEPT { return __begin_; } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer end() _NOEXCEPT { return __begin_ + __size_; } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer end() const _NOEXCEPT { return __begin_ + __size_; } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __size_; } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool empty() const _NOEXCEPT { return __size_ == 0; } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type capacity() const _NOEXCEPT { return __cap_; } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI allocator_type& __get_allocator() _NOEXCEPT { return __alloc_; } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI allocator_type const& __get_allocator() const _NOEXCEPT { + return __alloc_; + } + + // Returns the sentinel object directly. Should be used in conjunction with automatic type deduction, + // not explicit types. + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __sentinel() const _NOEXCEPT { return __size_; } + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __raw_capacity() const _NOEXCEPT { return __cap_; } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_data(pointer __new_first) _NOEXCEPT { + __data_ = __new_first; + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void + __set_valid_range(pointer __new_begin, pointer __new_end) _NOEXCEPT { + // Size-based __split_buffers track their size directly: we need to explicitly update the size + // when the front is adjusted. + __size_ -= __new_begin - __begin_; + __begin_ = __new_begin; + __set_sentinel(__new_end); + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void + __set_valid_range(pointer __new_begin, size_type __new_size) _NOEXCEPT { + // Size-based __split_buffers track their size directly: we need to explicitly update the size + // when the front is adjusted. + __size_ -= __new_begin - __begin_; + __begin_ = __new_begin; + __set_sentinel(__new_size); + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_sentinel(pointer __new_end) _NOEXCEPT { + _LIBCPP_ASSERT_INTERNAL(__data_ <= __new_end, "__new_end cannot precede __data_"); + __size_ += __new_end - end(); + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_sentinel(size_type __new_size) _NOEXCEPT { + __size_ = __new_size; + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_capacity(size_type __new_capacity) _NOEXCEPT { + __cap_ = __new_capacity; + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_capacity(pointer __new_capacity) _NOEXCEPT { + __cap_ = __new_capacity - __begin_; + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __front_spare() const _NOEXCEPT { + return static_cast(__begin_ - __data_); + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __back_spare() const _NOEXCEPT { + // `__cap_ - __end_` tells us the total number of spares when in size-mode. We need to remove + // the __front_spare from the count. + return __cap_ - __size_ - __front_spare(); + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference back() _NOEXCEPT { return __begin_[__size_ - 1]; } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference back() const _NOEXCEPT { + return __begin_[__size_ - 1]; + } + + template + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __swap_without_allocator(_Data2& __other) _NOEXCEPT { + std::swap(__data_, __other.__data_); + std::swap(__begin_, __other.__begin_); + std::swap(__cap_, __other.__cap_); + std::swap(__size_, __other.__size_); + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void swap(__split_buffer_size_layout& __other) _NOEXCEPT { + __swap_without_allocator(__other); + std::__swap_allocator(__alloc_, __other.__alloc_); + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __reset() _NOEXCEPT { + __data_ = nullptr; + __begin_ = nullptr; + __size_ = 0; + __cap_ = 0; + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void + __copy_without_alloc(__split_buffer_size_layout const& __other) + _NOEXCEPT_(is_nothrow_copy_assignable::value) { + __data_ = __other.__data_; + __begin_ = __other.__begin_; + __cap_ = __other.__cap_; + __size_ = __other.__size_; + } + +private: + pointer __data_ = nullptr; + pointer __begin_ = nullptr; + size_type __size_ = 0; + size_type __cap_ = 0; + _LIBCPP_NO_UNIQUE_ADDRESS allocator_type __alloc_; + + template + friend class __split_buffer_size_layout; +}; + +// __split_buffer allocates a contiguous chunk of memory and stores objects in the range [__begin_, __end_). +// It has uninitialized memory in the ranges [__data_, __begin_) and [__end_, __cap_). That allows +// it to grow both in the front and back without having to move the data. + +template , + template class _Layout = __split_buffer_pointer_layout> +struct __split_buffer : _Layout<__split_buffer<_Tp, _Allocator, _Layout>, _Tp, _Allocator> { + using __base_type _LIBCPP_NODEBUG = _Layout<__split_buffer<_Tp, _Allocator, _Layout>, _Tp, _Allocator>; + using __base_type::__back_spare; + using __base_type::__copy_without_alloc; + using __base_type::__data; + using __base_type::__front_spare; + using __base_type::__get_allocator; + using __base_type::__reset; + using __base_type::__set_capacity; + using __base_type::__set_data; + using __base_type::__set_sentinel; + using __base_type::__set_valid_range; + using __base_type::__swap_without_allocator; + + using typename __base_type::__alloc_rr; + using typename __base_type::__alloc_traits; + using typename __base_type::allocator_type; + using typename __base_type::const_iterator; + using typename __base_type::const_pointer; + using typename __base_type::const_reference; + using typename __base_type::difference_type; + using typename __base_type::iterator; + using typename __base_type::pointer; + using typename __base_type::reference; + using typename __base_type::size_type; + using typename __base_type::value_type; + // A __split_buffer contains 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 @@ -78,23 +380,15 @@ public: __split_buffer, void>; - pointer __first_; - pointer __begin_; - pointer __end_; - _LIBCPP_COMPRESSED_PAIR(pointer, __cap_, allocator_type, __alloc_); - __split_buffer(const __split_buffer&) = delete; __split_buffer& operator=(const __split_buffer&) = delete; - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __split_buffer() - _NOEXCEPT_(is_nothrow_default_constructible::value) - : __first_(nullptr), __begin_(nullptr), __end_(nullptr), __cap_(nullptr) {} + _LIBCPP_HIDE_FROM_ABI __split_buffer() = default; - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __split_buffer(__alloc_rr& __a) - : __first_(nullptr), __begin_(nullptr), __end_(nullptr), __cap_(nullptr), __alloc_(__a) {} + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __split_buffer(__alloc_rr& __a) : __base_type(__a) {} _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __split_buffer(const __alloc_rr& __a) - : __first_(nullptr), __begin_(nullptr), __end_(nullptr), __cap_(nullptr), __alloc_(__a) {} + : __base_type(__a) {} _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __split_buffer(size_type __cap, size_type __start, __alloc_rr& __a); @@ -111,36 +405,16 @@ public: _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI ~__split_buffer(); - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { return __begin_; } - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { return __begin_; } - - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT { return __end_; } - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT { return __end_; } - - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void clear() _NOEXCEPT { __destruct_at_end(__begin_); } - - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type size() const { - return static_cast(__end_ - __begin_); - } + using __base_type::back; + using __base_type::begin; + using __base_type::capacity; + using __base_type::empty; + using __base_type::end; + using __base_type::size; - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool empty() const { return __end_ == __begin_; } - - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type capacity() const { - return static_cast(__cap_ - __first_); - } - - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __front_spare() const { - return static_cast(__begin_ - __first_); - } - - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __back_spare() const { - return static_cast(__cap_ - __end_); - } - - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference front() { return *__begin_; } - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference front() const { return *__begin_; } - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference back() { return *(__end_ - 1); } - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference back() const { return *(__end_ - 1); } + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void clear() _NOEXCEPT { __destruct_at_end(begin()); } + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference front() { return *begin(); } + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference front() const { return *begin(); } _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void shrink_to_fit() _NOEXCEPT; @@ -149,8 +423,8 @@ public: template _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void emplace_back(_Args&&... __args); - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void pop_front() { __destruct_at_begin(__begin_ + 1); } - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void pop_back() { __destruct_at_end(__end_ - 1); } + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void pop_front() { __destruct_at_begin(begin() + 1); } + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void pop_back() { __destruct_at_end(end() - 1); } _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __construct_at_end(size_type __n); _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __construct_at_end(size_type __n, const_reference __x); @@ -184,242 +458,232 @@ public: _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void swap(__split_buffer& __x) _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || __is_nothrow_swappable_v<__alloc_rr>); - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __invariants() const; + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __invariants() const { + if (__data() == nullptr) { + if (begin() != nullptr) + return false; + + if (!empty()) + return false; + + if (capacity() != 0) + return false; + + return true; + } else { + if (begin() < __data()) + return false; + + if (capacity() < size()) + return false; + + if (end() < begin()) + return false; + + return true; + } + } private: _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __move_assign_alloc(__split_buffer& __c, true_type) _NOEXCEPT_(is_nothrow_move_assignable::value) { - __alloc_ = std::move(__c.__alloc_); + __get_allocator() = std::move(__c.__get_allocator()); } _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __move_assign_alloc(__split_buffer&, false_type) _NOEXCEPT {} struct _ConstructTransaction { _LIBCPP_CONSTEXPR_SINCE_CXX20 - _LIBCPP_HIDE_FROM_ABI explicit _ConstructTransaction(pointer* __p, size_type __n) _NOEXCEPT - : __pos_(*__p), - __end_(*__p + __n), - __dest_(__p) {} + _LIBCPP_HIDE_FROM_ABI explicit _ConstructTransaction(__split_buffer* __parent, pointer __p, size_type __n) _NOEXCEPT + : __pos_(__p), + __end_(__p + __n), + __parent_(__parent) {} - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI ~_ConstructTransaction() { *__dest_ = __pos_; } + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI ~_ConstructTransaction() { __parent_->__set_sentinel(__pos_); } pointer __pos_; const pointer __end_; private: - pointer* __dest_; + __split_buffer* __parent_; }; }; -template -_LIBCPP_CONSTEXPR_SINCE_CXX20 bool __split_buffer<_Tp, _Allocator>::__invariants() const { - if (__first_ == nullptr) { - if (__begin_ != nullptr) - return false; - if (__end_ != nullptr) - return false; - if (__cap_ != nullptr) - return false; - } else { - if (__begin_ < __first_) - return false; - if (__end_ < __begin_) - return false; - if (__cap_ < __end_) - return false; - } - return true; -} - -// Default constructs __n objects starting at __end_ +// Default constructs __n objects starting at `__begin_ + size()` // throws if construction throws // Precondition: __n > 0 // Precondition: size() + __n <= capacity() // Postcondition: size() == size() + __n -template -_LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator>::__construct_at_end(size_type __n) { - _ConstructTransaction __tx(std::addressof(this->__end_), __n); +template class _Layout> +_LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator, _Layout>::__construct_at_end(size_type __n) { + _ConstructTransaction __tx(this, end(), __n); for (; __tx.__pos_ != __tx.__end_; ++__tx.__pos_) { - __alloc_traits::construct(__alloc_, std::__to_address(__tx.__pos_)); + __alloc_traits::construct(__get_allocator(), std::__to_address(__tx.__pos_)); } } -// Copy constructs __n objects starting at __end_ from __x +// Copy constructs __n objects starting at `__begin_ + size()` from __x // throws if construction throws // Precondition: __n > 0 // Precondition: size() + __n <= capacity() // Postcondition: size() == old size() + __n // Postcondition: [i] == __x for all i in [size() - __n, __n) -template +template class _Layout> _LIBCPP_CONSTEXPR_SINCE_CXX20 void -__split_buffer<_Tp, _Allocator>::__construct_at_end(size_type __n, const_reference __x) { - _ConstructTransaction __tx(std::addressof(this->__end_), __n); +__split_buffer<_Tp, _Allocator, _Layout>::__construct_at_end(size_type __n, const_reference __x) { + _ConstructTransaction __tx(this, end(), __n); for (; __tx.__pos_ != __tx.__end_; ++__tx.__pos_) { - __alloc_traits::construct(__alloc_, std::__to_address(__tx.__pos_), __x); + __alloc_traits::construct(__get_allocator(), std::__to_address(__tx.__pos_), __x); } } -template +template class _Layout> template _LIBCPP_CONSTEXPR_SINCE_CXX20 void -__split_buffer<_Tp, _Allocator>::__construct_at_end_with_sentinel(_Iterator __first, _Sentinel __last) { - __alloc_rr& __a = __alloc_; +__split_buffer<_Tp, _Allocator, _Layout>::__construct_at_end_with_sentinel(_Iterator __first, _Sentinel __last) { + __alloc_rr& __a = __get_allocator(); for (; __first != __last; ++__first) { - if (__end_ == __cap_) { - size_type __old_cap = __cap_ - __first_; + if (__back_spare() == 0) { + size_type __old_cap = capacity(); size_type __new_cap = std::max(2 * __old_cap, 8); __split_buffer __buf(__new_cap, 0, __a); - for (pointer __p = __begin_; __p != __end_; ++__p, (void)++__buf.__end_) - __alloc_traits::construct(__buf.__alloc_, std::__to_address(__buf.__end_), std::move(*__p)); + pointer __buf_end = __buf.end(); + pointer __end = end(); + for (pointer __p = begin(); __p != __end; ++__p) { + __alloc_traits::construct(__buf.__get_allocator(), std::__to_address(__buf_end), std::move(*__p)); + __buf.__set_sentinel(++__buf_end); + } swap(__buf); } - __alloc_traits::construct(__a, std::__to_address(this->__end_), *__first); - ++this->__end_; + + __alloc_traits::construct(__a, std::__to_address(end()), *__first); + __set_sentinel(size() + 1); } } -template + +template class _Layout> template ::value, int> > _LIBCPP_CONSTEXPR_SINCE_CXX20 void -__split_buffer<_Tp, _Allocator>::__construct_at_end(_ForwardIterator __first, _ForwardIterator __last) { +__split_buffer<_Tp, _Allocator, _Layout>::__construct_at_end(_ForwardIterator __first, _ForwardIterator __last) { __construct_at_end_with_size(__first, std::distance(__first, __last)); } -template +template class _Layout> template _LIBCPP_CONSTEXPR_SINCE_CXX20 void -__split_buffer<_Tp, _Allocator>::__construct_at_end_with_size(_ForwardIterator __first, size_type __n) { - _ConstructTransaction __tx(std::addressof(this->__end_), __n); +__split_buffer<_Tp, _Allocator, _Layout>::__construct_at_end_with_size(_ForwardIterator __first, size_type __n) { + _ConstructTransaction __tx(this, end(), __n); for (; __tx.__pos_ != __tx.__end_; ++__tx.__pos_, (void)++__first) { - __alloc_traits::construct(__alloc_, std::__to_address(__tx.__pos_), *__first); + __alloc_traits::construct(__get_allocator(), std::__to_address(__tx.__pos_), *__first); } } -template +template class _Layout> _LIBCPP_CONSTEXPR_SINCE_CXX20 inline void -__split_buffer<_Tp, _Allocator>::__destruct_at_begin(pointer __new_begin, false_type) { - while (__begin_ != __new_begin) - __alloc_traits::destroy(__alloc_, std::__to_address(__begin_++)); +__split_buffer<_Tp, _Allocator, _Layout>::__destruct_at_begin(pointer __new_begin, false_type) { + pointer __begin = begin(); + // Updating begin at every iteration is unnecessary because destruction can't throw. + while (__begin != __new_begin) + __alloc_traits::destroy(__get_allocator(), std::__to_address(__begin++)); + __set_valid_range(__begin, end()); } -template +template class _Layout> _LIBCPP_CONSTEXPR_SINCE_CXX20 inline void -__split_buffer<_Tp, _Allocator>::__destruct_at_begin(pointer __new_begin, true_type) { - __begin_ = __new_begin; +__split_buffer<_Tp, _Allocator, _Layout>::__destruct_at_begin(pointer __new_begin, true_type) { + __set_valid_range(__new_begin, end()); } -template +template class _Layout> _LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI void -__split_buffer<_Tp, _Allocator>::__destruct_at_end(pointer __new_last, false_type) _NOEXCEPT { - while (__new_last != __end_) - __alloc_traits::destroy(__alloc_, std::__to_address(--__end_)); +__split_buffer<_Tp, _Allocator, _Layout>::__destruct_at_end(pointer __new_last, false_type) _NOEXCEPT { + pointer __end = end(); + // Updating begin at every iteration is unnecessary because destruction can't throw. + while (__new_last != __end) + __alloc_traits::destroy(__get_allocator(), std::__to_address(--__end)); + __set_sentinel(__end); } -template -_LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI void -__split_buffer<_Tp, _Allocator>::__destruct_at_end(pointer __new_last, true_type) _NOEXCEPT { - __end_ = __new_last; -} - -template +template class _Layout> _LIBCPP_CONSTEXPR_SINCE_CXX20 -__split_buffer<_Tp, _Allocator>::__split_buffer(size_type __cap, size_type __start, __alloc_rr& __a) - : __cap_(nullptr), __alloc_(__a) { - if (__cap == 0) { - __first_ = nullptr; - } else { - auto __allocation = std::__allocate_at_least(__alloc_, __cap); - __first_ = __allocation.ptr; - __cap = __allocation.count; +__split_buffer<_Tp, _Allocator, _Layout>::__split_buffer(size_type __cap, size_type __start, __alloc_rr& __a) + : __base_type(__a) { + _LIBCPP_ASSERT_INTERNAL(__cap >= __start, "can't have a start point outside the capacity"); + if (__cap > 0) { + auto __allocation = std::__allocate_at_least(__get_allocator(), __cap); + __set_data(__allocation.ptr); + __cap = __allocation.count; } - __begin_ = __end_ = __first_ + __start; - __cap_ = __first_ + __cap; + + pointer __begin = __data() + __start; + __set_valid_range(__begin, __begin); + __set_capacity(__cap); } -template -_LIBCPP_CONSTEXPR_SINCE_CXX20 __split_buffer<_Tp, _Allocator>::~__split_buffer() { +template class _Layout> +_LIBCPP_CONSTEXPR_SINCE_CXX20 __split_buffer<_Tp, _Allocator, _Layout>::~__split_buffer() { clear(); - if (__first_) - __alloc_traits::deallocate(__alloc_, __first_, capacity()); + if (__data()) + __alloc_traits::deallocate(__get_allocator(), __data(), capacity()); } -template -_LIBCPP_CONSTEXPR_SINCE_CXX20 __split_buffer<_Tp, _Allocator>::__split_buffer(__split_buffer&& __c) +template class _Layout> +_LIBCPP_CONSTEXPR_SINCE_CXX20 __split_buffer<_Tp, _Allocator, _Layout>::__split_buffer(__split_buffer&& __c) _NOEXCEPT_(is_nothrow_move_constructible::value) - : __first_(std::move(__c.__first_)), - __begin_(std::move(__c.__begin_)), - __end_(std::move(__c.__end_)), - __cap_(std::move(__c.__cap_)), - __alloc_(std::move(__c.__alloc_)) { - __c.__first_ = nullptr; - __c.__begin_ = nullptr; - __c.__end_ = nullptr; - __c.__cap_ = nullptr; + : __base_type(std::move(__c)) { + __c.__reset(); } -template +template class _Layout> _LIBCPP_CONSTEXPR_SINCE_CXX20 -__split_buffer<_Tp, _Allocator>::__split_buffer(__split_buffer&& __c, const __alloc_rr& __a) - : __cap_(nullptr), __alloc_(__a) { - if (__a == __c.__alloc_) { - __first_ = __c.__first_; - __begin_ = __c.__begin_; - __end_ = __c.__end_; - __cap_ = __c.__cap_; - __c.__first_ = nullptr; - __c.__begin_ = nullptr; - __c.__end_ = nullptr; - __c.__cap_ = nullptr; +__split_buffer<_Tp, _Allocator, _Layout>::__split_buffer(__split_buffer&& __c, const __alloc_rr& __a) + : __base_type(__a) { + if (__a == __c.__get_allocator()) { + __set_data(__c.__data()); + __set_valid_range(__c.begin(), __c.end()); + __set_capacity(__c.capacity()); + __c.__reset(); } else { - auto __allocation = std::__allocate_at_least(__alloc_, __c.size()); - __first_ = __allocation.ptr; - __begin_ = __end_ = __first_; - __cap_ = __first_ + __allocation.count; + auto __allocation = std::__allocate_at_least(__get_allocator(), __c.size()); + __set_data(__allocation.ptr); + __set_valid_range(__data(), __data()); + __set_capacity(__allocation.count); typedef move_iterator _Ip; __construct_at_end(_Ip(__c.begin()), _Ip(__c.end())); } } -template -_LIBCPP_CONSTEXPR_SINCE_CXX20 __split_buffer<_Tp, _Allocator>& -__split_buffer<_Tp, _Allocator>::operator=(__split_buffer&& __c) +template class _Layout> +_LIBCPP_CONSTEXPR_SINCE_CXX20 __split_buffer<_Tp, _Allocator, _Layout>& +__split_buffer<_Tp, _Allocator, _Layout>::operator=(__split_buffer&& __c) _NOEXCEPT_((__alloc_traits::propagate_on_container_move_assignment::value && is_nothrow_move_assignable::value) || !__alloc_traits::propagate_on_container_move_assignment::value) { clear(); shrink_to_fit(); - __first_ = __c.__first_; - __begin_ = __c.__begin_; - __end_ = __c.__end_; - __cap_ = __c.__cap_; + __copy_without_alloc(__c); __move_assign_alloc(__c, integral_constant()); - __c.__first_ = __c.__begin_ = __c.__end_ = __c.__cap_ = nullptr; + __c.__reset(); return *this; } -template -_LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator>::swap(__split_buffer& __x) +template class _Layout> +_LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator, _Layout>::swap(__split_buffer& __x) _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || __is_nothrow_swappable_v<__alloc_rr>) { - std::swap(__first_, __x.__first_); - std::swap(__begin_, __x.__begin_); - std::swap(__end_, __x.__end_); - std::swap(__cap_, __x.__cap_); - std::__swap_allocator(__alloc_, __x.__alloc_); + __base_type::swap(__x); } -template -_LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator>::shrink_to_fit() _NOEXCEPT { +template class _Layout> +_LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator, _Layout>::shrink_to_fit() _NOEXCEPT { if (capacity() > size()) { #if _LIBCPP_HAS_EXCEPTIONS try { #endif // _LIBCPP_HAS_EXCEPTIONS - __split_buffer __t(size(), 0, __alloc_); + __split_buffer __t(size(), 0, __get_allocator()); if (__t.capacity() < capacity()) { - __t.__construct_at_end(move_iterator(__begin_), move_iterator(__end_)); - __t.__end_ = __t.__begin_ + (__end_ - __begin_); - std::swap(__first_, __t.__first_); - std::swap(__begin_, __t.__begin_); - std::swap(__end_, __t.__end_); - std::swap(__cap_, __t.__cap_); + __t.__construct_at_end(move_iterator(begin()), move_iterator(end())); + __t.__set_sentinel(size()); + __swap_without_allocator(__t); } #if _LIBCPP_HAS_EXCEPTIONS } catch (...) { @@ -428,50 +692,50 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator>::shrink_to_fi } } -template +template class _Layout> template -_LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator>::emplace_front(_Args&&... __args) { - if (__begin_ == __first_) { - if (__end_ < __cap_) { - difference_type __d = __cap_ - __end_; +_LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator, _Layout>::emplace_front(_Args&&... __args) { + if (__front_spare() == 0) { + pointer __end = end(); + if (__back_spare() > 0) { + // The elements are pressed up against the front of the buffer: we need to move them back a + // little bit to make `emplace_front` have amortised O(1) complexity. + difference_type __d = __back_spare(); __d = (__d + 1) / 2; - __begin_ = std::move_backward(__begin_, __end_, __end_ + __d); - __end_ += __d; + auto __new_end = __end + __d; + __set_valid_range(std::move_backward(begin(), __end, __new_end), __new_end); } else { - size_type __c = std::max(2 * static_cast(__cap_ - __first_), 1); - __split_buffer __t(__c, (__c + 3) / 4, __alloc_); - __t.__construct_at_end(move_iterator(__begin_), move_iterator(__end_)); - std::swap(__first_, __t.__first_); - std::swap(__begin_, __t.__begin_); - std::swap(__end_, __t.__end_); - std::swap(__cap_, __t.__cap_); + size_type __c = std::max(2 * capacity(), 1); + __split_buffer __t(__c, (__c + 3) / 4, __get_allocator()); + __t.__construct_at_end(move_iterator(begin()), move_iterator(__end)); + __swap_without_allocator(__t); } } - __alloc_traits::construct(__alloc_, std::__to_address(__begin_ - 1), std::forward<_Args>(__args)...); - --__begin_; + + __alloc_traits::construct(__get_allocator(), std::__to_address(begin() - 1), std::forward<_Args>(__args)...); + __set_valid_range(begin() - 1, size() + 1); } -template +template class _Layout> template -_LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator>::emplace_back(_Args&&... __args) { - if (__end_ == __cap_) { - if (__begin_ > __first_) { - difference_type __d = __begin_ - __first_; +_LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator, _Layout>::emplace_back(_Args&&... __args) { + pointer __end = end(); + if (__back_spare() == 0) { + if (__front_spare() > 0) { + difference_type __d = __front_spare(); __d = (__d + 1) / 2; - __end_ = std::move(__begin_, __end_, __begin_ - __d); - __begin_ -= __d; + __end = std::move(begin(), __end, begin() - __d); + __set_valid_range(begin() - __d, __end); } else { - size_type __c = std::max(2 * static_cast(__cap_ - __first_), 1); - __split_buffer __t(__c, __c / 4, __alloc_); - __t.__construct_at_end(move_iterator(__begin_), move_iterator(__end_)); - std::swap(__first_, __t.__first_); - std::swap(__begin_, __t.__begin_); - std::swap(__end_, __t.__end_); - std::swap(__cap_, __t.__cap_); + size_type __c = std::max(2 * capacity(), 1); + __split_buffer __t(__c, __c / 4, __get_allocator()); + __t.__construct_at_end(move_iterator(begin()), move_iterator(__end)); + __swap_without_allocator(__t); } } - __alloc_traits::construct(__alloc_, std::__to_address(__end_), std::forward<_Args>(__args)...); - ++__end_; + + __alloc_traits::construct(__get_allocator(), std::__to_address(__end), std::forward<_Args>(__args)...); + __set_sentinel(++__end); } template diff --git a/libcxx/include/__vector/vector.h b/libcxx/include/__vector/vector.h index 4307e78f6ddbc..490726b86af42 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,22 +85,331 @@ _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; + + __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_)) + , __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_ = nullptr, allocator_type, __alloc_); +}; +#endif // _LIBCPP_ABI_SIZE_BASED_VECTOR + template */> -class vector { +class vector : __vector_layout, _Tp, _Allocator> { + using __base _LIBCPP_NODEBUG = __vector_layout; + using __self _LIBCPP_NODEBUG = vector; + using __base::__raw_begin; + using __base::__raw_sentinel; + using __base::__raw_capacity; + using __base::__end_pointer; + using __base::__remaining_capacity; + using __base::__is_full; + using __base::__set_valid_range; + using __base::__set_sentinel; + using __base::__set_capacity; + using __base::__allocator_ref; + using typename __base::__alloc_traits; + using typename __base::__split_buffer; + using typename __base::__sentinel_type; 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 @@ -113,6 +423,12 @@ class vector { using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; + using __base::back; + using __base::capacity; + using __base::empty; + using __base::size; + using __base::__invariants; + // 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 @@ -141,7 +457,7 @@ class vector { #else noexcept #endif - : __alloc_(__a) { + : __base(__a) { } _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit vector(size_type __n) { @@ -155,7 +471,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); @@ -177,7 +493,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); @@ -200,7 +516,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); } @@ -221,7 +537,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); } @@ -230,7 +546,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); @@ -247,10 +563,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()); } } @@ -262,13 +578,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); @@ -279,7 +595,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()); } @@ -342,23 +658,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 { @@ -392,17 +708,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; @@ -412,50 +719,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()); } // @@ -480,7 +779,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_; } @@ -493,7 +792,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); @@ -549,41 +848,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, size_type{0}); + __set_capacity(__allocation.count); __annotate_new(0); } @@ -631,7 +928,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()); } } @@ -678,8 +975,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 @@ -690,17 +987,17 @@ 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); + __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) @@ -714,7 +1011,15 @@ 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 auto __emplace_back_slow_path(_Args&&... __args) -> __sentinel_type { + __split_buffer __v(__recommend(size() + 1), size(), __allocator_ref()); + // __v.emplace_back(std::forward<_Args>(__args)...); + pointer __end = __v.end(); + __alloc_traits::construct(__allocator_ref(), std::__to_address(__end), std::forward<_Args>(__args)...); + __v.__set_sentinel(++__end); + __swap_out_circular_buffer(__v); + return __raw_sentinel(); + } // The following functions are no-ops outside of AddressSanitizer mode. // We call annotations for every allocator, unless explicitly disabled. @@ -747,14 +1052,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()); } } @@ -767,10 +1072,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) { @@ -788,20 +1093,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, size_type{0}); + __set_capacity(__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 {} @@ -820,8 +1126,26 @@ class vector { __add_alignment_assumption(_Ptr __p) _NOEXCEPT { return __p; } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void + __swap_layouts(__split_buffer& __v) { + auto __begin = __raw_begin(); + auto __sentinel = __raw_sentinel(); + auto __cap = __raw_capacity(); + + auto __v_begin = __v.begin(); + auto __v_sentinel = __v.__sentinel(); + auto __v_cap = __v.__raw_capacity(); + + __set_valid_range(__v_begin, __v_sentinel); + __set_capacity(__v_cap); + + __v.__set_valid_range(__begin, __sentinel); + __v.__set_capacity(__cap); + } }; + #if _LIBCPP_STD_VER >= 17 template >, @@ -843,63 +1167,64 @@ 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) { +vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer& __v) { __annotate_delete(); - auto __new_begin = __v.__begin_ - (__end_ - __begin_); + 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)); - __v.__begin_ = __new_begin; - __end_ = __begin_; // All the objects have been destroyed by relocating them. - std::swap(this->__begin_, __v.__begin_); - std::swap(this->__end_, __v.__end_); - std::swap(this->__cap_, __v.__cap_); - __v.__first_ = __v.__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()); + __set_sentinel(size_type{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_; + 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_)); - __v.__end_ += (__end_ - __p); - __end_ = __p; // The objects in [__p, __end_) have been destroyed by relocating them. - auto __new_begin = __v.__begin_ - (__p - __begin_); + __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); + __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.__begin_ = __new_begin; - __end_ = __begin_; // All the objects have been destroyed by relocating them. - - std::swap(this->__begin_, __v.__begin_); - std::swap(this->__end_, __v.__end_); - std::swap(this->__cap_, __v.__cap_); - __v.__first_ = __v.__begin_; + __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(size_type{0}); // All the objects have been destroyed by relocating them. + + __swap_layouts(__v); + __v.__set_data(__v.begin()); __annotate_new(size()); return __ret; } template _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, size_type{0}); + __set_capacity(size_type{0}); } } @@ -916,7 +1241,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() @@ -926,11 +1251,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() @@ -942,7 +1267,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); } } @@ -951,34 +1276,34 @@ 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); } @@ -991,22 +1316,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, size_type{0}); + __x.__set_capacity(size_type{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, size_type{0}); + __x.__set_capacity(size_type{0}); } else { typedef move_iterator _Ip; __init_with_size(_Ip(__x.begin()), _Ip(__x.end()), __x.size()); @@ -1016,7 +1341,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 @@ -1028,10 +1353,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, size_type{0}); + __c.__set_capacity(size_type{0}); } template @@ -1039,7 +1364,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; } @@ -1048,10 +1373,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) @@ -1067,15 +1393,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 { @@ -1089,11 +1415,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))); @@ -1106,7 +1432,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); } } @@ -1117,7 +1443,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. @@ -1130,18 +1456,6 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::shrink_to_fit() _NOE } } -template -template -_LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::pointer -vector<_Tp, _Allocator>::__emplace_back_slow_path(_Args&&... __args) { - __split_buffer __v(__recommend(size() + 1), size(), this->__alloc_); - // __v.emplace_back(std::forward<_Args>(__args)...); - __alloc_traits::construct(this->__alloc_, std::__to_address(__v.__end_), std::forward<_Args>(__args)...); - __v.__end_++; - __swap_out_circular_buffer(__v); - return this->__end_; -} - template template _LIBCPP_CONSTEXPR_SINCE_CXX20 inline @@ -1151,16 +1465,16 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 inline void #endif vector<_Tp, _Allocator>::emplace_back(_Args&&... __args) { - pointer __end = this->__end_; - if (__end < this->__cap_) { + auto __current_sentinel = __raw_sentinel(); + if (__current_sentinel < __raw_capacity()) { __emplace_back_assume_capacity(std::forward<_Args>(__args)...); - ++__end; + ++__current_sentinel; } else { - __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 } @@ -1170,8 +1484,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); } @@ -1179,9 +1493,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); } @@ -1189,13 +1503,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); @@ -1204,19 +1518,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); } @@ -1226,16 +1541,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); } @@ -1246,17 +1562,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); } @@ -1266,25 +1583,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); } @@ -1297,29 +1615,30 @@ 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_); + __split_buffer __v(__allocator_ref()); + pointer __end = __end_pointer(); auto __guard = std::__make_exception_guard( - _AllocatorDestroyRangeReverse(__alloc_, __old_last, this->__end_)); + _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.__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_)); - __merged.__end_ += __v.size(); - __v.__end_ = __v.__begin_; + __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); } return __make_iter(__p); @@ -1330,16 +1649,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 { @@ -1355,7 +1675,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); } @@ -1369,7 +1689,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 @@ -1378,49 +1698,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/include/deque b/libcxx/include/deque index 395a1076fd3c4..c173f50fa5a9b 100644 --- a/libcxx/include/deque +++ b/libcxx/include/deque @@ -1238,8 +1238,8 @@ private: clear(); shrink_to_fit(); } - __alloc() = __c.__alloc(); - __map_.__alloc_ = __c.__map_.__alloc_; + __alloc() = __c.__alloc(); + __map_.__get_allocator() = __c.__map_.__get_allocator(); } _LIBCPP_HIDE_FROM_ABI void __copy_assign_alloc(const deque&, false_type) {} @@ -1318,7 +1318,7 @@ deque<_Tp, _Allocator>::deque(const deque& __c) : __map_(__pointer_allocator(__alloc_traits::select_on_container_copy_construction(__c.__alloc()))), __start_(0), __size_(0), - __alloc_(__map_.__alloc_) { + __alloc_(__map_.__get_allocator()) { __annotate_new(0); __append(__c.begin(), __c.end()); } @@ -2071,7 +2071,7 @@ void deque<_Tp, _Allocator>::__add_front_capacity() { // Else need to allocate 1 buffer, *and* we need to reallocate __map_. else { __split_buffer __buf( - std::max(2 * __map_.capacity(), 1), 0, __map_.__alloc_); + std::max(2 * __map_.capacity(), 1), 0, __map_.__get_allocator()); typedef __allocator_destructor<_Allocator> _Dp; unique_ptr __hold(__alloc_traits::allocate(__a, __block_size), _Dp(__a, __block_size)); @@ -2080,10 +2080,7 @@ void deque<_Tp, _Allocator>::__add_front_capacity() { for (__map_pointer __i = __map_.begin(); __i != __map_.end(); ++__i) __buf.emplace_back(*__i); - std::swap(__map_.__first_, __buf.__first_); - std::swap(__map_.__begin_, __buf.__begin_); - std::swap(__map_.__end_, __buf.__end_); - std::swap(__map_.__cap_, __buf.__cap_); + __map_.__swap_without_allocator(__buf); __start_ = __map_.size() == 1 ? __block_size / 2 : __start_ + __block_size; } __annotate_whole_block(0, __asan_poison); @@ -2134,7 +2131,7 @@ void deque<_Tp, _Allocator>::__add_front_capacity(size_type __n) { else { size_type __ds = (__nb + __back_capacity) * __block_size - __map_.empty(); __split_buffer __buf( - std::max(2 * __map_.capacity(), __nb + __map_.size()), 0, __map_.__alloc_); + std::max(2 * __map_.capacity(), __nb + __map_.size()), 0, __map_.__get_allocator()); # if _LIBCPP_HAS_EXCEPTIONS try { # endif // _LIBCPP_HAS_EXCEPTIONS @@ -2157,10 +2154,7 @@ void deque<_Tp, _Allocator>::__add_front_capacity(size_type __n) { } for (__map_pointer __i = __map_.begin(); __i != __map_.end(); ++__i) __buf.emplace_back(*__i); - std::swap(__map_.__first_, __buf.__first_); - std::swap(__map_.__begin_, __buf.__begin_); - std::swap(__map_.__end_, __buf.__end_); - std::swap(__map_.__cap_, __buf.__cap_); + __map_.__swap_without_allocator(__buf); __start_ += __ds; } } @@ -2194,7 +2188,7 @@ void deque<_Tp, _Allocator>::__add_back_capacity() { // Else need to allocate 1 buffer, *and* we need to reallocate __map_. else { __split_buffer __buf( - std::max(2 * __map_.capacity(), 1), __map_.size(), __map_.__alloc_); + std::max(2 * __map_.capacity(), 1), __map_.size(), __map_.__get_allocator()); typedef __allocator_destructor<_Allocator> _Dp; unique_ptr __hold(__alloc_traits::allocate(__a, __block_size), _Dp(__a, __block_size)); @@ -2203,10 +2197,7 @@ void deque<_Tp, _Allocator>::__add_back_capacity() { for (__map_pointer __i = __map_.end(); __i != __map_.begin();) __buf.emplace_front(*--__i); - std::swap(__map_.__first_, __buf.__first_); - std::swap(__map_.__begin_, __buf.__begin_); - std::swap(__map_.__end_, __buf.__end_); - std::swap(__map_.__cap_, __buf.__cap_); + __map_.__swap_without_allocator(__buf); __annotate_whole_block(__map_.size() - 1, __asan_poison); } } @@ -2259,7 +2250,7 @@ void deque<_Tp, _Allocator>::__add_back_capacity(size_type __n) { __split_buffer __buf( std::max(2 * __map_.capacity(), __nb + __map_.size()), __map_.size() - __front_capacity, - __map_.__alloc_); + __map_.__get_allocator()); # if _LIBCPP_HAS_EXCEPTIONS try { # endif // _LIBCPP_HAS_EXCEPTIONS @@ -2282,10 +2273,7 @@ void deque<_Tp, _Allocator>::__add_back_capacity(size_type __n) { } for (__map_pointer __i = __map_.end(); __i != __map_.begin();) __buf.emplace_front(*--__i); - std::swap(__map_.__first_, __buf.__first_); - std::swap(__map_.__begin_, __buf.__begin_); - std::swap(__map_.__end_, __buf.__end_); - std::swap(__map_.__cap_, __buf.__cap_); + __map_.__swap_without_allocator(__buf); __start_ -= __ds; } } 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..56b2d8ddc1c82 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,7 +167,28 @@ constexpr bool test() { }); }); - { // Test vector::iterator optimization + 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>(); @@ -191,8 +196,7 @@ constexpr bool test() { test_vector_bool<64>(); test_vector_bool<199>(); test_vector_bool<256>(); - } - return true; + return true; } static_assert(std::same_as, std::ranges::in_in_result>); @@ -201,5 +205,8 @@ int main(int, char**) { test(); static_assert(test()); + test_vector_bool(); + static_assert(test_vector_bool()); + return 0; } diff --git a/libcxx/test/tools/clang_tidy_checks/CMakeLists.txt b/libcxx/test/tools/clang_tidy_checks/CMakeLists.txt index 521a60c0fc498..a070a2c215f0c 100644 --- a/libcxx/test/tools/clang_tidy_checks/CMakeLists.txt +++ b/libcxx/test/tools/clang_tidy_checks/CMakeLists.txt @@ -103,6 +103,7 @@ set(SOURCES ) add_library(cxx-tidy MODULE ${SOURCES}) +target_compile_options(cxx-tidy PUBLIC -stdlib=libc++) target_link_libraries(cxx-tidy clangTidy) set_target_properties(cxx-tidy PROPERTIES diff --git a/lldb/examples/synthetic/libcxx.py b/lldb/examples/synthetic/libcxx.py index 5abeb3061f4f5..c24820f42ec26 100644 --- a/lldb/examples/synthetic/libcxx.py +++ b/lldb/examples/synthetic/libcxx.py @@ -1,3 +1,6 @@ +from enum import Enum +from sys import stderr +import sys import lldb import lldb.formatters.Logger @@ -74,6 +77,45 @@ def stdstring_SummaryProvider(valobj, dict): return '"' + strval + '"' +def get_buffer_end(buffer, begin): + """ + Returns a pointer to where the next element would be pushed. + + For libc++'s stable ABI and unstable < LLVM 22, returns `__end_`. + For libc++'s unstable ABI, returns `__begin_ + __size_`. + """ + map_end = buffer.GetChildMemberWithName("__end_") + if map_end.IsValid(): + return map_end.GetValueAsUnsigned(0) + map_size = buffer.GetChildMemberWithName("__size_").GetValueAsUnsigned(0) + return begin + map_size + + +def get_buffer_endcap(parent, buffer, begin, has_compressed_pair_layout, is_size_based): + """ + Returns a pointer to the end of the buffer. + + For libc++'s stable ABI and unstable < LLVM 22, returns: + * `__end_cap_`, if `__compressed_pair` is being used + * `__cap_`, otherwise + For libc++'s unstable ABI, returns `__begin_ + __cap_`. + """ + if has_compressed_pair_layout: + map_endcap = parent._get_value_of_compressed_pair( + buffer.GetChildMemberWithName("__end_cap_") + ) + else: + map_endcap = buffer.GetChildMemberWithName("__cap_") + if not map_endcap.IsValid(): + map_endcap = buffer.GetChildMemberWithName("__end_cap_") + map_endcap = map_endcap.GetValueAsUnsigned(0) + + if is_size_based: + return begin + map_endcap + + return map_endcap + + class stdvector_SynthProvider: def __init__(self, valobj, dict): logger = lldb.formatters.Logger.Logger() @@ -755,23 +797,18 @@ def update(self): if self.block_size < 0: logger.write("block_size < 0") return - map_ = self.valobj.GetChildMemberWithName("__map_") start = self.valobj.GetChildMemberWithName("__start_").GetValueAsUnsigned(0) + + map_ = self.valobj.GetChildMemberWithName("__map_") + is_size_based = map_.GetChildMemberWithName("__size_").IsValid() first = map_.GetChildMemberWithName("__first_") map_first = first.GetValueAsUnsigned(0) self.map_begin = map_.GetChildMemberWithName("__begin_") map_begin = self.map_begin.GetValueAsUnsigned(0) - map_end = map_.GetChildMemberWithName("__end_").GetValueAsUnsigned(0) - - if has_compressed_pair_layout: - map_endcap = self._get_value_of_compressed_pair( - map_.GetChildMemberWithName("__end_cap_") - ) - else: - map_endcap = map_.GetChildMemberWithName("__cap_") - if not map_endcap.IsValid(): - map_endcap = map_.GetChildMemberWithName("__end_cap_") - map_endcap = map_endcap.GetValueAsUnsigned(0) + map_end = get_buffer_end(map_, map_begin) + map_endcap = get_buffer_endcap( + self, map_, map_begin, has_compressed_pair_layout, is_size_based + ) # check consistency if not map_first <= map_begin <= map_end <= map_endcap: