-
Notifications
You must be signed in to change notification settings - Fork 14.9k
[libcxx] adds a size-based representation for vector's unstable ABI
#155330
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
**tl;dr** We can significantly improve the runtime performance of `std::vector` by changing its representation from three pointers to one pointer and two integers. This document explains the details of this change, along with the justifications for making it. See the [RFC] for more information. `vector` depends on `__split_buffer` for inserting elements. Changing `__split_buffer` to match `vector`'s representation simplifies the model, as it eliminates the need to convert between two different representations of a contiguous buffer in the same configuration of libc++. [RFC]: TODO
**tl;dr** We can significantly improve the runtime performance of `std::vector` by changing its representation from three pointers to one pointer and two integers. This document explains the details of this change, along with the justifications for making it. See the [RFC] for more information. This commit changes `std::vector`'s representation in a similar manner to `__split_buffer` in llvm#139632. We introduce a layout type that tracks implementation details that differ between the pointer-based vector and size-based vector representations. `vector` does not parameterise its layout type, unlike `__split_buffer`. `__split_buffer` is used by both `vector` and `deque`, and being able to take an ABI break on `vector` doesn't automatically mean that users can also tolerate a break on `deque`. The most convenient way to work around this problem is to parameterise the layout type. Users of `std::vector` should not depend on its layout, and libc++ has no internal reason to toggle it, so we keep the representation concrete. To use this feature, you'll need to configure libc++ so that it's built with `-DLIBCXX_UNSTABLE_ABI=Yes`. [RFC]: https://discourse.llvm.org/t/adding-a-size-based-vector-to-libc-s-unstable-abi/86306
|
@llvm/pr-subscribers-lldb @llvm/pr-subscribers-libcxx Author: Christopher Di Bella (cjdb) Changestl;dr We can significantly improve the runtime performance of This commit changes To use this feature, you'll need to configure libc++ so that it's built with Patch is 113.37 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/155330.diff 6 Files Affected:
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 _SplitBuffer, class _Tp, class _Allocator>
+class __split_buffer_pointer_layout {
+protected:
+ using value_type = _Tp;
+ using allocator_type = _Allocator;
+ using __alloc_rr _LIBCPP_NODEBUG = __libcpp_remove_reference_t<allocator_type>;
+ 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 <class _Tp, class _Allocator = allocator<_Tp> >
-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<size_type>(__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<size_type>(__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<size_type>(__begin_ - __data_);
+ }
+
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __back_spare() const _NOEXCEPT {
+ return static_cast<size_type>(__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 <class _OtherLayout>
+ _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<pointer>::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 <class, class, class>
+ friend class __split_buffer_pointer_layout;
+};
+
+template <class _SplitBuffer, class _Tp, class _Allocator>
+class __split_buffer_size_layout {
+protected:
using value_type = _Tp;
using allocator_type = _Allocator;
using __alloc_rr _LIBCPP_NODEBUG = __libcpp_remove_reference_t<allocator_type>;
@@ -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<size_type>(__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 <class _Data2>
+ _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<pointer>::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 <class, class, class>
+ 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 <class _Tp,
+ class _Allocator = allocator<_Tp>,
+ template <class, class, class> 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<allocator_type>::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<size_type>(__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<size_type>(__cap_ - __first_);
- }
-
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __front_spare() const {
- return static_cast<size_type>(__begin_ - __first_);
- }
-
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __back_spare() const {
- return static_cast<size_type>(__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 <class... _Args>
_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<allocator_type>::value) {
- __alloc_ = std::move(__c.__alloc_);
+ __get_allocator() = std::move(__c.__get_allocator());
}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __move_assign...
[truncated]
|
877d560 to
ccc8d09
Compare
You can test this locally with the following command:git-clang-format --diff HEAD~1 HEAD --extensions ,h,cpp -- libcxx/include/__split_buffer libcxx/include/__vector/vector.h libcxx/include/deque libcxx/test/std/algorithms/alg.modifying.operations/alg.swap/ranges.swap_ranges.pass.cppView the diff from clang-format here.diff --git a/libcxx/include/__vector/vector.h b/libcxx/include/__vector/vector.h
index 490726b86..81f0db2f1 100644
--- a/libcxx/include/__vector/vector.h
+++ b/libcxx/include/__vector/vector.h
@@ -86,7 +86,7 @@ _LIBCPP_PUSH_MACROS
_LIBCPP_BEGIN_NAMESPACE_STD
#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
-template<class _Vector, class _Tp, class _Allocator>
+template <class _Vector, class _Tp, class _Allocator>
class __vector_layout {
public:
using value_type = _Tp;
@@ -101,26 +101,25 @@ public:
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<allocator_type>::value)
- : __alloc_(__a)
- {}
-
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __vector_layout(allocator_type&& __a) _NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value)
- : __alloc_(std::move(__a))
- {}
-
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __vector_layout(__vector_layout&& __other) _NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value)
- : __begin_(std::move(__other.__begin_))
- , __size_(std::move(__other.__size_))
- , __cap_(std::move(__other.__cap_))
- , __alloc_(std::move(__other.__alloc_))
- {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __vector_layout(allocator_type const& __a)
+ _NOEXCEPT_(is_nothrow_copy_constructible<allocator_type>::value)
+ : __alloc_(__a) {}
+
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __vector_layout(allocator_type&& __a)
+ _NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value)
+ : __alloc_(std::move(__a)) {}
+
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __vector_layout(__vector_layout&& __other)
+ _NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::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;
+ __other.__size_ = 0;
+ __other.__cap_ = 0;
}
// Capacity
@@ -148,13 +147,13 @@ public:
return __alloc_;
}
- [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI allocator_type const& __allocator_ref() const _NOEXCEPT {
+ [[__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<allocator_type>)
- {
+ _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || __is_nothrow_swappable_v<allocator_type>) {
_LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(
__alloc_traits::propagate_on_container_swap::value || __alloc_ == __x.__alloc_,
"vector::swap: Either propagate_on_container_swap must be true"
@@ -181,7 +180,8 @@ public:
return __begin_ + __size_;
}
- [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __remaining_capacity() const _NOEXCEPT {
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type
+ __remaining_capacity() const _NOEXCEPT {
return __cap_ - __size_;
}
@@ -191,12 +191,13 @@ public:
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_valid_range(pointer __begin, pointer __end) _NOEXCEPT {
__begin_ = __begin;
- __size_ = __end - __begin_;
+ __size_ = __end - __begin_;
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_valid_range(pointer __begin, size_type __size) _NOEXCEPT {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
+ __set_valid_range(pointer __begin, size_type __size) _NOEXCEPT {
__begin_ = __begin;
- __size_ = __size;
+ __size_ = __size;
}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_sentinel(size_type __size) _NOEXCEPT {
@@ -207,9 +208,7 @@ public:
__size_ = static_cast<size_type>(__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(size_type __cap) _NOEXCEPT { __cap_ = __cap; }
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_capacity(pointer __pos) _NOEXCEPT {
__cap_ = static_cast<size_type>(__pos - __begin_);
@@ -225,14 +224,15 @@ public:
}
return true;
}
+
private:
- pointer __begin_ = nullptr;
+ pointer __begin_ = nullptr;
size_type __size_ = 0;
- size_type __cap_ = 0;
+ size_type __cap_ = 0;
[[no_unique_address]] allocator_type __alloc_;
};
#else
-template<class _Vector, class _Tp, class _Allocator>
+template <class _Vector, class _Tp, class _Allocator>
class __vector_layout {
public:
using value_type = _Tp;
@@ -249,23 +249,23 @@ public:
__vector_layout() = default;
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __vector_layout(allocator_type const& __a) _NOEXCEPT_(is_nothrow_copy_constructible<allocator_type>::value)
- : __alloc_(__a)
- {}
-
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __vector_layout(allocator_type&& __a) _NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value)
- : __alloc_(std::move(__a))
- {}
-
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __vector_layout(__vector_layout&& __other) _NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value)
- : __begin_(std::move(__other.__begin_))
- , __end_(std::move(__other.__end_))
- , __cap_(std::move(__other.__cap_))
- , __alloc_(std::move(__other.__alloc_))
- {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __vector_layout(allocator_type const& __a)
+ _NOEXCEPT_(is_nothrow_copy_constructible<allocator_type>::value)
+ : __alloc_(__a) {}
+
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __vector_layout(allocator_type&& __a)
+ _NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value)
+ : __alloc_(std::move(__a)) {}
+
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __vector_layout(__vector_layout&& __other)
+ _NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::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;
+ __other.__end_ = nullptr;
+ __other.__cap_ = nullptr;
}
// Capacity
@@ -296,13 +296,13 @@ public:
return __alloc_;
}
- [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI allocator_type const& __allocator_ref() const _NOEXCEPT {
+ [[__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<allocator_type>)
- {
+ _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || __is_nothrow_swappable_v<allocator_type>) {
_LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(
__alloc_traits::propagate_on_container_swap::value || __alloc_ == __x.__alloc_,
"vector::swap: Either propagate_on_container_swap must be true"
@@ -329,7 +329,8 @@ public:
return __end_;
}
- [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __remaining_capacity() const _NOEXCEPT {
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type
+ __remaining_capacity() const _NOEXCEPT {
return __cap_ - __end_;
}
@@ -339,25 +340,22 @@ public:
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_valid_range(pointer __begin, pointer __end) _NOEXCEPT {
__begin_ = __begin;
- __end_ = __end;
+ __end_ = __end;
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_valid_range(pointer __begin, size_type __size) _NOEXCEPT {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
+ __set_valid_range(pointer __begin, size_type __size) _NOEXCEPT {
__begin_ = __begin;
- __end_ = __begin_ + __size;
+ __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(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(pointer __cap) _NOEXCEPT { __cap_ = __cap; }
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_capacity(size_type __offset) _NOEXCEPT {
__cap_ = __begin_ + __offset;
@@ -377,6 +375,7 @@ public:
}
return true;
}
+
private:
pointer __begin_ = nullptr;
pointer __end_ = nullptr;
@@ -388,19 +387,20 @@ template <class _Tp, class _Allocator /* = allocator<_Tp> */>
class vector : __vector_layout<vector<_Tp, _Allocator>, _Tp, _Allocator> {
using __base _LIBCPP_NODEBUG = __vector_layout<vector, _Tp, _Allocator>;
using __self _LIBCPP_NODEBUG = vector;
+ using __base::__allocator_ref;
+ using __base::__end_pointer;
+ using __base::__is_full;
using __base::__raw_begin;
- using __base::__raw_sentinel;
using __base::__raw_capacity;
- using __base::__end_pointer;
+ using __base::__raw_sentinel;
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 __base::__set_sentinel;
+ using __base::__set_valid_range;
using typename __base::__alloc_traits;
- using typename __base::__split_buffer;
using typename __base::__sentinel_type;
+ using typename __base::__split_buffer;
+
public:
using value_type = _Tp;
using allocator_type = _Allocator;
@@ -423,11 +423,11 @@ public:
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+ using __base::__invariants;
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
@@ -994,8 +994,7 @@ private:
#endif // _LIBCPP_ABI_BOUNDED_ITERATORS_IN_VECTOR
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
- __swap_out_circular_buffer(__split_buffer& __v);
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __swap_out_circular_buffer(__split_buffer& __v);
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer
__swap_out_circular_buffer(__split_buffer& __v, pointer __p);
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
@@ -1011,7 +1010,8 @@ private:
}
template <class... _Args>
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI auto __emplace_back_slow_path(_Args&&... __args) -> __sentinel_type {
+ _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();
@@ -1127,15 +1127,14 @@ private:
return __p;
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
- __swap_layouts(__split_buffer& __v) {
- auto __begin = __raw_begin();
+ _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 __cap = __raw_capacity();
- auto __v_begin = __v.begin();
+ auto __v_begin = __v.begin();
auto __v_sentinel = __v.__sentinel();
- auto __v_cap = __v.__raw_capacity();
+ auto __v_cap = __v.__raw_capacity();
__set_valid_range(__v_begin, __v_sentinel);
__set_capacity(__v_cap);
@@ -1145,7 +1144,6 @@ private:
}
};
-
#if _LIBCPP_STD_VER >= 17
template <class _InputIterator,
class _Alloc = allocator<__iter_value_type<_InputIterator>>,
@@ -1167,16 +1165,18 @@ template <ranges::input_range _Range,
vector(from_range_t, _Range&&, _Alloc = _Alloc()) -> vector<ranges::range_value_t<_Range>, _Alloc>;
#endif
-// __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
+// __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 <class _Tp, class _Allocator>
-_LIBCPP_CONSTEXPR_SINCE_CXX20 void
-vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer& __v) {
+_LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer& __v) {
__annotate_delete();
auto __new_begin = __v.begin() - size();
std::__uninitialized_allocator_relocate(
- __allocator_ref(), std::__to_address(__raw_begin()), std::__to_address(__end_pointer()), std::__to_address(__new_begin));
+ __allocator_ref(),
+ std::__to_address(__raw_begin()),
+ std::__to_address(__end_pointer()),
+ std::__to_address(__new_begin));
__v.__set_valid_range(__new_begin, __v.end());
__set_sentinel(size_type{0}); // All the objects have been destroyed by relocating them.
// __v.__size_ += __size_;
@@ -1203,7 +1203,8 @@ vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer& __v, pointer
__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.
+ __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(
@@ -1276,7 +1277,8 @@ template <class _InputIterator, class _Sentinel>
_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(__allocator_ref(), 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_pointer()
@@ -1587,7 +1589,7 @@ vector<_Tp, _Allocator>::insert(const_iterator __position, size_type __n, const_
if (__n > 0) {
if (__n <= __remaining_capacity()) {
size_type __old_n = __n;
- pointer __end = __end_pointer();
+ pointer __end = __end_pointer();
pointer __old_last = __end;
if (__n > static_cast<size_type>(__end - __p)) {
size_type __cx = __n - (__end - __p);
@@ -1625,18 +1627,25 @@ vector<_Tp, _Allocator>::__insert_with_sentinel(const_iterator __position, _Inpu
else {
__split_buffer __v(__allocator_ref());
pointer __end = __end_pointer();
- auto __guard = std::__make_exception_guard(
+ auto __guard = std::__make_exception_guard(
_AllocatorDestroyRangeReverse<allocator_type, pointer>(__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, __allocator_ref()); // has `__off` positions available at the front
std::__uninitialized_allocator_relocate(
- __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.
+ __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(
- __allocator_ref(), std::__to_address(__v.begin()), std::__to_address(__v.end()), std::__to_address(__merged.end()));
+ __allocator_ref(),
+ std::__to_address(__v.begin()),
+ std::__to_address(__v.end()),
+ std::__to_address(__merged.end()));
__merged.__set_sentinel(__merged.size() + __v.size());
__v.__set_sentinel(__v.begin());
__p = __swap_out_circular_buffer(__merged, __p);
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 56b2d8ddc..da42ce56d 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
@@ -187,16 +187,15 @@ constexpr void test_vector_bool() {
}
}
-constexpr bool test_vector_bool()
-{
- test_vector_bool<8>();
- test_vector_bool<19>();
- test_vector_bool<32>();
- test_vector_bool<49>();
- test_vector_bool<64>();
- test_vector_bool<199>();
- test_vector_bool<256>();
- return true;
+constexpr bool test_vector_bool() {
+ test_vector_bool<8>();
+ test_vector_bool<19>();
+ test_vector_bool<32>();
+ test_vector_bool<49>();
+ test_vector_bool<64>();
+ test_vector_bool<199>();
+ test_vector_bool<256>();
+ return true;
}
static_assert(std::same_as<std::ranges::swap_ranges_result<int, char>, std::ranges::in_in_result<int, char>>);
|
|
This PR contains #139632 for CI purposes. Only two files require review: The LLDB and GDB pretty-printers will require some tweaking again, but those changes haven't been applied yet. |
|
After having attempted to build all of our code with this change, I've observed a few things. None of them are really surprising, but putting some countermeasures in place to nudge users in the right direction would be worthwhile.
|
tl;dr We can significantly improve the runtime performance of
std::vectorby changing its representation from three pointers to one pointer and two integers. This document explains the details of this change, along with the justifications for making it. See the RFC for more information.This commit changes
std::vector's representation in a similar manner to__split_bufferin #139632. We introduce a layout type that tracks implementation details that differ between the pointer-based vector and size-based vector representations.vectordoes not parameterise its layout type, unlike__split_buffer.__split_bufferis used by bothvectoranddeque, and being able to take an ABI break onvectordoesn't automatically mean that users can also tolerate a break ondeque. The most convenient way to work around this problem is to parameterise the layout type. Users ofstd::vectorshould not depend on its layout, and libc++ has no internal reason to toggle it, so we keep the representation concrete.To use this feature, you'll need to configure libc++ so that it's built with
-DLIBCXX_UNSTABLE_ABI=Yes.