[libcxx-commits] [libcxx] [libcxx] adds a size-based representation for `vector`'s unstable ABI (PR #155330)
Christopher Di Bella via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Jan 29 11:53:20 PST 2026
https://github.com/cjdb updated https://github.com/llvm/llvm-project/pull/155330
>From ba94eeba1e22ebee9708c770c3b7da73eaad131e Mon Sep 17 00:00:00 2001
From: Christopher Di Bella <cjdb at google.com>
Date: Mon, 25 Aug 2025 23:06:45 +0000
Subject: [PATCH 01/14] [libcxx] adds a size-based representation for
`vector`'s unstable ABI
**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 #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
---
libcxx/include/__configuration/abi.h | 1 +
libcxx/include/__split_buffer | 8 +-
libcxx/include/__vector/vector.h | 800 ++++++++++++------
.../alg.swap/ranges.swap_ranges.pass.cpp | 54 +-
libcxx/utils/gdb/libcxx/printers.py | 18 +-
5 files changed, 597 insertions(+), 284 deletions(-)
diff --git a/libcxx/include/__configuration/abi.h b/libcxx/include/__configuration/abi.h
index 38b85c6ac70de..70aef42b487ac 100644
--- a/libcxx/include/__configuration/abi.h
+++ b/libcxx/include/__configuration/abi.h
@@ -79,6 +79,7 @@
# define _LIBCPP_ABI_NO_REVERSE_ITERATOR_SECOND_MEMBER
# define _LIBCPP_ABI_OPTIMIZED_FUNCTION
# define _LIBCPP_ABI_REGEX_CONSTANTS_NONZERO
+# define _LIBCPP_ABI_SIZE_BASED_VECTOR
# define _LIBCPP_ABI_STRING_OPTIMIZED_EXTERNAL_INSTANTIATION
# define _LIBCPP_ABI_USE_WRAP_ITER_IN_STD_ARRAY
# define _LIBCPP_ABI_USE_WRAP_ITER_IN_STD_STRING_VIEW
diff --git a/libcxx/include/__split_buffer b/libcxx/include/__split_buffer
index 1e05e4df8ba0f..9a55f855bbfda 100644
--- a/libcxx/include/__split_buffer
+++ b/libcxx/include/__split_buffer
@@ -268,7 +268,6 @@ public:
__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);
}
@@ -277,7 +276,6 @@ public:
__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);
}
@@ -316,9 +314,9 @@ public:
}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __swap_without_allocator(
- __split_buffer_pointer_layout<__split_buffer<value_type, __alloc_rr&, __split_buffer_pointer_layout>,
- value_type,
- __alloc_rr&>& __other) _NOEXCEPT {
+ __split_buffer_size_layout<__split_buffer<value_type, __alloc_rr&, __split_buffer_size_layout>,
+ value_type,
+ __alloc_rr&>& __other) _NOEXCEPT {
std::swap(__front_cap_, __other.__front_cap_);
std::swap(__begin_, __other.__begin_);
std::swap(__cap_, __other.__cap_);
diff --git a/libcxx/include/__vector/vector.h b/libcxx/include/__vector/vector.h
index 7051e044314ea..9e94fe75123eb 100644
--- a/libcxx/include/__vector/vector.h
+++ b/libcxx/include/__vector/vector.h
@@ -55,6 +55,7 @@
#include <__type_traits/is_nothrow_constructible.h>
#include <__type_traits/is_pointer.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>
@@ -82,25 +83,334 @@ _LIBCPP_PUSH_MACROS
_LIBCPP_BEGIN_NAMESPACE_STD
+#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+template <class _Vector, class _Tp, class _Allocator>
+class __vector_layout {
+public:
+ using value_type = _Tp;
+ using allocator_type = _Allocator;
+ using __alloc_traits _LIBCPP_NODEBUG = allocator_traits<allocator_type>;
+ 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;
+
+ _LIBCPP_HIDE_FROM_ABI __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_)) {
+ __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<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"
+ " 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<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(pointer __pos) _NOEXCEPT {
+ __cap_ = static_cast<size_type>(__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, class _Tp, class _Allocator>
+class __vector_layout {
+public:
+ using value_type = _Tp;
+ using allocator_type = _Allocator;
+ using __alloc_traits _LIBCPP_NODEBUG = allocator_traits<allocator_type>;
+ using reference = value_type&;
+ using const_reference = const value_type&;
+ using size_type = typename __alloc_traits::size_type;
+ using difference_type = typename __alloc_traits::difference_type;
+ using pointer = typename __alloc_traits::pointer;
+ using const_pointer = typename __alloc_traits::const_pointer;
+ using __split_buffer _LIBCPP_NODEBUG = std::__split_buffer<_Tp, _Allocator&, __split_buffer_pointer_layout>;
+ using __sentinel_type _LIBCPP_NODEBUG = pointer;
+
+ // Can't be defaulted due to _LIBCPP_COMPRESSED_PAIR not being an aggregate in C++03 and C++11.
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __vector_layout()
+ _NOEXCEPT_(is_nothrow_default_constructible<allocator_type>::value)
+ : __cap_(nullptr) {}
+
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __vector_layout(allocator_type const& __a)
+ _NOEXCEPT_(is_nothrow_copy_constructible<allocator_type>::value)
+ : __cap_(nullptr), __alloc_(__a) {}
+
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __vector_layout(allocator_type&& __a)
+ _NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value)
+ : __cap_(nullptr), __alloc_(std::move(__a)) {}
+
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __vector_layout(__vector_layout&& __other)
+ _NOEXCEPT_(is_nothrow_move_constructible<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;
+ }
+
+ // Capacity
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT {
+ return static_cast<size_type>(__end_ - __begin_);
+ }
+
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type capacity() const _NOEXCEPT {
+ return static_cast<size_type>(__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<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"
+ " or the allocators must compare equal");
+ std::swap(__begin_, __x.__begin_);
+ std::swap(__end_, __x.__end_);
+ std::swap(__cap_, __x.__cap_);
+ std::__swap_allocator(__alloc_, __x.__alloc_);
+ }
+
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer __raw_begin() const _NOEXCEPT {
+ return __begin_;
+ }
+
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer __raw_sentinel() const _NOEXCEPT {
+ return __end_;
+ }
+
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer __raw_capacity() const _NOEXCEPT {
+ return __cap_;
+ }
+
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer __end_pointer() const _NOEXCEPT {
+ return __end_;
+ }
+
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type
+ __remaining_capacity() const _NOEXCEPT {
+ return __cap_ - __end_;
+ }
+
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __is_full() const _NOEXCEPT {
+ return __end_ == __cap_;
+ }
+
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_valid_range(pointer __begin, pointer __end) _NOEXCEPT {
+ __begin_ = __begin;
+ __end_ = __end;
+ }
+
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
+ __set_valid_range(pointer __begin, size_type __size) _NOEXCEPT {
+ __begin_ = __begin;
+ __end_ = __begin_ + __size;
+ }
+
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_sentinel(pointer __end) _NOEXCEPT { __end_ = __end; }
+
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_sentinel(size_type __offset) _NOEXCEPT {
+ __end_ = __begin_ + __offset;
+ }
+
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_capacity(pointer __cap) _NOEXCEPT { __cap_ = __cap; }
+
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_capacity(size_type __offset) _NOEXCEPT {
+ __cap_ = __begin_ + __offset;
+ }
+
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __invariants() const {
+ if (__begin_ == nullptr) {
+ if (__end_ != nullptr || __cap_ != nullptr)
+ return false;
+ } else {
+ if (__begin_ > __end_)
+ return false;
+ if (__begin_ == __cap_)
+ return false;
+ if (__end_ > __cap_)
+ return false;
+ }
+ return true;
+ }
+
+private:
+ pointer __begin_ = nullptr;
+ pointer __end_ = nullptr;
+ _LIBCPP_COMPRESSED_PAIR(pointer, __cap_, allocator_type, __alloc_);
+};
+#endif // _LIBCPP_ABI_SIZE_BASED_VECTOR
+
template <class _Tp, class _Allocator /* = allocator<_Tp> */>
-class vector {
- template <class _Up, class _Alloc>
- using __split_buffer _LIBCPP_NODEBUG = std::__split_buffer<_Up, _Alloc, __split_buffer_pointer_layout>;
+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_capacity;
+ using __base::__raw_sentinel;
+ using __base::__remaining_capacity;
+ using __base::__set_capacity;
+ using __base::__set_sentinel;
+ using __base::__set_valid_range;
+ using typename __base::__alloc_traits;
+ using typename __base::__sentinel_type;
+ using typename __base::__split_buffer;
public:
- //
- // Types
- //
- using __self _LIBCPP_NODEBUG = vector;
- using value_type = _Tp;
- using allocator_type = _Allocator;
- using __alloc_traits _LIBCPP_NODEBUG = allocator_traits<allocator_type>;
- 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
@@ -114,6 +424,8 @@ class vector {
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+ 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
@@ -138,7 +450,7 @@ class vector {
#else
noexcept
#endif
- : __alloc_(__a) {
+ : __base(__a) {
}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit vector(size_type __n) {
@@ -152,7 +464,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);
@@ -174,7 +486,7 @@ class vector {
template <__enable_if_t<__is_allocator_v<_Allocator>, 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);
@@ -197,7 +509,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);
}
@@ -218,7 +530,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<size_type>(std::distance(__first, __last));
__init_with_size(__first, __last, __n);
}
@@ -227,7 +539,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<size_type>(ranges::distance(__range));
__init_with_size(ranges::begin(__range), ranges::end(__range), __n);
@@ -244,10 +556,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());
}
}
@@ -259,13 +571,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<allocator_type>& __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);
@@ -276,7 +588,7 @@ class vector {
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
vector(initializer_list<value_type> __il, const allocator_type& __a)
- : __alloc_(__a) {
+ : __base(__a) {
__init_with_size(__il.begin(), __il.end(), __il.size());
}
@@ -339,23 +651,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 {
@@ -389,17 +701,19 @@ class vector {
//
// [vector.capacity], capacity
//
+
+ // Capacity
[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT {
- return static_cast<size_type>(this->__end_ - this->__begin_);
+ return __base::size();
}
[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type capacity() const _NOEXCEPT {
- return static_cast<size_type>(this->__cap_ - this->__begin_);
+ return __base::capacity();
}
[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool empty() const _NOEXCEPT {
- return this->__begin_ == this->__end_;
+ return __base::empty();
}
[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT {
- return std::min<size_type>(__alloc_traits::max_size(this->__alloc_), numeric_limits<difference_type>::max());
+ return std::min<size_type>(__alloc_traits::max_size(__allocator_ref()), numeric_limits<difference_type>::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;
@@ -409,50 +723,48 @@ 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_;
+ return *__raw_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);
+ return __base::back();
}
[[__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 __base::back();
}
//
// [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());
}
//
@@ -477,7 +789,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_;
}
@@ -490,7 +802,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);
@@ -546,41 +858,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<allocator_type>);
+ _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || __is_nothrow_swappable_v<allocator_type>)
#endif
-
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __invariants() const;
+ {
+ __base::swap(__other);
+ }
private:
- pointer __begin_ = nullptr;
- pointer __end_ = nullptr;
- _LIBCPP_COMPRESSED_PAIR(pointer, __cap_ = nullptr, allocator_type, __alloc_);
-
// Allocate space for __n objects
// throws length_error if __n > max_size()
// throws (probably bad_alloc) if memory run out
- // Precondition: __begin_ == __end_ == __cap_ == nullptr
+ // Precondition: begin() == nullptr
+ // Precondition: size() == 0
+ // Precondition: capacity() == 0
// Precondition: __n > 0
// Postcondition: capacity() >= __n
// Postcondition: size() == 0
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __vallocate(size_type __n) {
if (__n > max_size())
this->__throw_length_error();
- auto __allocation = std::__allocate_at_least(this->__alloc_, __n);
- __begin_ = __allocation.ptr;
- __end_ = __allocation.ptr;
- __cap_ = __begin_ + __allocation.count;
+ auto __allocation = std::__allocate_at_least(__allocator_ref(), __n);
+ __set_valid_range(__allocation.ptr, static_cast<size_type>(0));
+ __set_capacity(__allocation.count);
__annotate_new(0);
}
@@ -628,7 +938,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<value_type, _Allocator> __tmp(this->__alloc_, *__first);
+ __temp_value<value_type, _Allocator> __tmp(__allocator_ref(), *__first);
*__position = std::move(__tmp.get());
}
}
@@ -672,8 +982,8 @@ class vector {
// a laxer approach.
return std::__make_bounded_iter(
std::__wrap_iter<pointer>(__p),
- std::__wrap_iter<pointer>(this->__begin_),
- std::__wrap_iter<pointer>(this->__cap_));
+ std::__wrap_iter<pointer>(__raw_begin()),
+ std::__wrap_iter<pointer>(__raw_capacity()));
#else
return iterator(__p);
#endif // _LIBCPP_ABI_BOUNDED_ITERATORS_IN_VECTOR
@@ -684,17 +994,16 @@ class vector {
// Bound the iterator according to the capacity, rather than the size.
return std::__make_bounded_iter(
std::__wrap_iter<const_pointer>(__p),
- std::__wrap_iter<const_pointer>(this->__begin_),
- std::__wrap_iter<const_pointer>(this->__cap_));
+ std::__wrap_iter<const_pointer>(__raw_begin()),
+ std::__wrap_iter<const_pointer>(__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<value_type, allocator_type&>& __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<value_type, allocator_type&>& __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)
@@ -708,7 +1017,7 @@ class vector {
}
template <class... _Args>
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI inline pointer __emplace_back_slow_path(_Args&&... __args);
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __sentinel_type __emplace_back_slow_path(_Args&&... __args);
// The following functions are no-ops outside of AddressSanitizer mode.
// We call annotations for every allocator, unless explicitly disabled.
@@ -741,14 +1050,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());
}
}
@@ -761,10 +1070,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) {
@@ -782,20 +1091,21 @@ class vector {
[[__noreturn__]] _LIBCPP_HIDE_FROM_ABI static void __throw_out_of_range() { std::__throw_out_of_range("vector"); }
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __copy_assign_alloc(const vector& __c, true_type) {
- if (this->__alloc_ != __c.__alloc_) {
+ if (__allocator_ref() != __c.__allocator_ref()) {
clear();
__annotate_delete();
- __alloc_traits::deallocate(this->__alloc_, this->__begin_, capacity());
- this->__begin_ = this->__end_ = this->__cap_ = nullptr;
+ __alloc_traits::deallocate(__allocator_ref(), __raw_begin(), capacity());
+ __set_valid_range(nullptr, static_cast<size_type>(0));
+ __set_capacity(static_cast<__sentinel_type>(0));
}
- this->__alloc_ = __c.__alloc_;
+ __allocator_ref() = __c.__allocator_ref();
}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __copy_assign_alloc(const vector&, false_type) {}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __move_assign_alloc(vector& __c, true_type)
_NOEXCEPT_(is_nothrow_move_assignable<allocator_type>::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 {}
@@ -815,19 +1125,17 @@ class vector {
return __p;
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __swap_layouts(__split_buffer<_Tp, allocator_type&>& __sb) {
- auto __vector_begin = __begin_;
- auto __vector_sentinel = __end_;
- auto __vector_cap = __cap_;
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __swap_layouts(__split_buffer& __sb) {
+ auto __vector_begin = __raw_begin();
+ auto __vector_sentinel = __raw_sentinel();
+ auto __vector_cap = __raw_capacity();
auto __sb_begin = __sb.begin();
auto __sb_sentinel = __sb.__raw_sentinel();
auto __sb_cap = __sb.__raw_capacity();
- // TODO: replace with __set_valid_range and __set_capacity when vector supports it.
- __begin_ = __sb_begin;
- __end_ = __sb_sentinel;
- __cap_ = __sb_cap;
+ __set_valid_range(__sb_begin, __sb_sentinel);
+ __set_capacity(__sb_cap);
__sb.__set_valid_range(__vector_begin, __vector_sentinel);
__sb.__set_capacity(__vector_cap);
@@ -855,47 +1163,53 @@ 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 [__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 <class _Tp, class _Allocator>
-_LIBCPP_CONSTEXPR_SINCE_CXX20 void
-vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer<value_type, allocator_type&>& __v) {
+_LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer& __v) {
__annotate_delete();
auto __new_begin = __v.begin() - size();
std::__uninitialized_allocator_relocate(
- this->__alloc_, std::__to_address(__begin_), std::__to_address(__end_), std::__to_address(__new_begin));
+ __allocator_ref(),
+ std::__to_address(__raw_begin()),
+ std::__to_address(__end_pointer()),
+ std::__to_address(__new_begin));
__v.__set_valid_range(__new_begin, __v.end());
- __end_ = __begin_; // All the objects have been destroyed by relocating them.
+ __set_sentinel(static_cast<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 <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::pointer
-vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer<value_type, allocator_type&>& __v, pointer __p) {
+vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer& __v, pointer __p) {
__annotate_delete();
pointer __ret = __v.begin();
- // Relocate [__p, __end_) first to avoid having a hole in [__begin_, __end_)
- // in case something in [__begin_, __p) throws.
+ pointer __end = __end_pointer();
+ // Relocate [__p, __end) first to avoid having a hole in [__raw_begin(), __end)
+ // in case something in [__raw_begin(), __p) throws.
std::__uninitialized_allocator_relocate(
- this->__alloc_, std::__to_address(__p), std::__to_address(__end_), std::__to_address(__v.end()));
- auto __relocated_so_far = __end_ - __p;
+ __allocator_ref(), std::__to_address(__p), std::__to_address(__end), std::__to_address(__v.end()));
+ auto __relocated_so_far = __end - __p;
__v.__set_sentinel(__v.end() + __relocated_so_far);
- __end_ = __p; // The objects in [__p, __end_) have been destroyed by relocating them.
- auto __new_begin = __v.begin() - (__p - __begin_);
+ __set_sentinel(
+ __raw_sentinel() - __relocated_so_far); // The objects in [__p, __end_) have been destroyed by relocating them.
+ auto __new_begin = __v.begin() - (__p - __raw_begin());
std::__uninitialized_allocator_relocate(
- this->__alloc_, std::__to_address(__begin_), std::__to_address(__p), std::__to_address(__new_begin));
- __v.__set_valid_range(__new_begin, __v.end());
- __end_ = __begin_; // All the objects have been destroyed by relocating them.
+ __allocator_ref(), std::__to_address(__raw_begin()), std::__to_address(__p), std::__to_address(__new_begin));
+ __v.__set_valid_range(__new_begin, __v.size() + size());
+ __set_sentinel(static_cast<size_type>(0)); // All the objects have been destroyed by relocating them.
+
__swap_layouts(__v);
__v.__set_data(__v.begin());
__annotate_new(size());
@@ -904,11 +1218,12 @@ vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer<value_type, a
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::__vdeallocate() _NOEXCEPT {
- if (this->__begin_ != nullptr) {
+ if (__raw_begin() != nullptr) {
clear();
__annotate_delete();
- __alloc_traits::deallocate(this->__alloc_, this->__begin_, capacity());
- this->__begin_ = this->__end_ = this->__cap_ = nullptr;
+ __alloc_traits::deallocate(__allocator_ref(), __raw_begin(), capacity());
+ __set_valid_range(nullptr, static_cast<size_type>(0));
+ __set_capacity(static_cast<size_type>(0));
}
}
@@ -925,7 +1240,7 @@ vector<_Tp, _Allocator>::__recommend(size_type __new_size) const {
return std::max<size_type>(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()
@@ -935,11 +1250,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()
@@ -951,7 +1266,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);
}
}
@@ -960,7 +1275,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(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_);
}
template <class _Tp, class _Allocator>
@@ -970,22 +1286,22 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI vector<_Tp, _Allocato
#else
_NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value)
#endif
- : __alloc_(std::move(__x.__alloc_)) {
- this->__begin_ = __x.__begin_;
- this->__end_ = __x.__end_;
- this->__cap_ = __x.__cap_;
- __x.__begin_ = __x.__end_ = __x.__cap_ = nullptr;
+ : __base(std::move(__x.__allocator_ref())) {
+ __set_valid_range(__x.__raw_begin(), __x.__raw_sentinel());
+ __set_capacity(__x.__raw_capacity());
+ __x.__set_valid_range(nullptr, static_cast<size_type>(0));
+ __x.__set_capacity(static_cast<size_type>(0));
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI
vector<_Tp, _Allocator>::vector(vector&& __x, const __type_identity_t<allocator_type>& __a)
- : __alloc_(__a) {
- if (__a == __x.__alloc_) {
- this->__begin_ = __x.__begin_;
- this->__end_ = __x.__end_;
- this->__cap_ = __x.__cap_;
- __x.__begin_ = __x.__end_ = __x.__cap_ = nullptr;
+ : __base(__a) {
+ if (__a == __x.__allocator_ref()) {
+ __set_valid_range(__x.__raw_begin(), __x.__raw_sentinel());
+ __set_capacity(__x.__raw_capacity());
+ __x.__set_valid_range(nullptr, static_cast<size_type>(0));
+ __x.__set_capacity(static_cast<size_type>(0));
} else {
typedef move_iterator<iterator> _Ip;
__init_with_size(_Ip(__x.begin()), _Ip(__x.end()), __x.size());
@@ -995,7 +1311,7 @@ vector<_Tp, _Allocator>::vector(vector&& __x, const __type_identity_t<allocator_
template <class _Tp, class _Allocator>
_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<iterator> _Ip;
assign(_Ip(__c.begin()), _Ip(__c.end()));
} else
@@ -1007,10 +1323,10 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::__move_assign(vector
_NOEXCEPT_(is_nothrow_move_assignable<allocator_type>::value) {
__vdeallocate();
__move_assign_alloc(__c); // this can throw
- this->__begin_ = __c.__begin_;
- this->__end_ = __c.__end_;
- this->__cap_ = __c.__cap_;
- __c.__begin_ = __c.__end_ = __c.__cap_ = nullptr;
+ __set_valid_range(__c.__raw_begin(), __c.__raw_sentinel());
+ __set_capacity(__c.__raw_capacity());
+ __c.__set_valid_range(nullptr, static_cast<size_type>(0));
+ __c.__set_capacity(static_cast<size_type>(0));
}
template <class _Tp, class _Allocator>
@@ -1018,7 +1334,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;
}
@@ -1027,10 +1343,11 @@ template <class _Tp, class _Allocator>
template <class _Iterator, class _Sentinel>
_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)
@@ -1046,15 +1363,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 {
@@ -1068,11 +1385,11 @@ template <class _Tp, class _Allocator>
_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<size_type>(__n)));
@@ -1085,7 +1402,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<value_type, allocator_type&> __v(__n, size(), this->__alloc_);
+ __split_buffer __v(__n, size(), __allocator_ref());
__swap_out_circular_buffer(__v);
}
}
@@ -1096,7 +1413,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::shrink_to_fit() _NOE
#if _LIBCPP_HAS_EXCEPTIONS
try {
#endif // _LIBCPP_HAS_EXCEPTIONS
- __split_buffer<value_type, allocator_type&> __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.
@@ -1111,15 +1428,15 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::shrink_to_fit() _NOE
template <class _Tp, class _Allocator>
template <class... _Args>
-_LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::pointer
+_LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::__sentinel_type
vector<_Tp, _Allocator>::__emplace_back_slow_path(_Args&&... __args) {
- __split_buffer<value_type, allocator_type&> __v(__recommend(size() + 1), size(), this->__alloc_);
+ __split_buffer __v(__recommend(size() + 1), size(), __allocator_ref());
// __v.emplace_back(std::forward<_Args>(__args)...);
pointer __end = __v.end();
- __alloc_traits::construct(this->__alloc_, std::__to_address(__end), std::forward<_Args>(__args)...);
+ __alloc_traits::construct(__allocator_ref(), std::__to_address(__end), std::forward<_Args>(__args)...);
__v.__set_sentinel(++__end);
__swap_out_circular_buffer(__v);
- return this->__end_;
+ return __raw_sentinel();
}
// This makes the compiler inline `__else()` if `__cond` is known to be false. Currently LLVM doesn't do that without
@@ -1149,18 +1466,18 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 inline
void
#endif
vector<_Tp, _Allocator>::emplace_back(_Args&&... __args) {
- pointer __end = this->__end_;
+ auto __current_sentinel = __raw_sentinel();
std::__if_likely_else(
- __end < this->__cap_,
+ __current_sentinel < __raw_capacity(),
[&] {
__emplace_back_assume_capacity(std::forward<_Args>(__args)...);
- ++__end;
+ ++__current_sentinel;
},
- [&] { __end = __emplace_back_slow_path(std::forward<_Args>(__args)...); });
+ [&] { __current_sentinel = __emplace_back_slow_path(std::forward<_Args>(__args)...); });
- this->__end_ = __end;
+ __set_sentinel(__current_sentinel);
#if _LIBCPP_STD_VER >= 17
- return *(__end - 1);
+ return back();
#endif
}
@@ -1170,8 +1487,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 +1496,9 @@ template <class _Tp, class _Allocator>
_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 +1506,13 @@ vector<_Tp, _Allocator>::erase(const_iterator __first, const_iterator __last) {
template <class _Tp, class _Allocator>
_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 +1521,20 @@ vector<_Tp, _Allocator>::__move_range(pointer __from_s, pointer __from_e, pointe
template <class _Tp, class _Allocator>
_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<const_pointer>::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<value_type, allocator_type&> __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 +1544,17 @@ vector<_Tp, _Allocator>::insert(const_iterator __position, const_reference __x)
template <class _Tp, class _Allocator>
_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<value_type, allocator_type&> __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 +1565,18 @@ template <class _Tp, class _Allocator>
template <class... _Args>
_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<value_type, _Allocator> __tmp(this->__alloc_, std::forward<_Args>(__args)...);
- __move_range(__p, this->__end_, __p + 1);
+ __temp_value<value_type, _Allocator> __tmp(__allocator_ref(), std::forward<_Args>(__args)...);
+ __move_range(__p, __end, __p + 1);
*__p = std::move(__tmp.get());
}
} else {
- __split_buffer<value_type, allocator_type&> __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 +1586,26 @@ vector<_Tp, _Allocator>::emplace(const_iterator __position, _Args&&... __args) {
template <class _Tp, class _Allocator>
_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<size_type>(this->__cap_ - this->__end_)) {
+ if (__n <= __remaining_capacity()) {
size_type __old_n = __n;
- pointer __old_last = this->__end_;
- if (__n > static_cast<size_type>(this->__end_ - __p)) {
- size_type __cx = __n - (this->__end_ - __p);
+ pointer __end = __end_pointer();
+ pointer __old_last = __end;
+ if (__n > static_cast<size_type>(__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<const_pointer>::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<value_type, allocator_type&> __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,27 +1618,35 @@ template <class _InputIterator, class _Sentinel>
_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<value_type, allocator_type&> __v(__alloc_);
- auto __guard = std::__make_exception_guard(
- _AllocatorDestroyRangeReverse<allocator_type, pointer>(__alloc_, __old_last, this->__end_));
+ __split_buffer __v(__allocator_ref());
+ pointer __end = __end_pointer();
+ 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<value_type, allocator_type&> __merged(
- __recommend(size() + __v.size()), __off, __alloc_); // has `__off` positions available at the front
+ __split_buffer __merged(
+ __recommend(size() + __v.size()), __off, __allocator_ref()); // has `__off` positions available at the front
std::__uninitialized_allocator_relocate(
- __alloc_, std::__to_address(__old_last), std::__to_address(this->__end_), std::__to_address(__merged.end()));
- __guard.__complete(); // Release the guard once objects in [__old_last_, __end_) have been successfully relocated.
- __merged.__set_sentinel(__merged.end() + (this->__end_ - __old_last));
- this->__end_ = __old_last;
+ __allocator_ref(),
+ std::__to_address(__old_last),
+ std::__to_address(__end_pointer()),
+ std::__to_address(__merged.end()));
+ __guard.__complete(); // Release the guard once objects in [__old_last_, __end_pointer()) have been successfully
+ // relocated.
+ __merged.__set_sentinel(__merged.end() + (__end_pointer() - __old_last));
+ __set_sentinel(__old_last);
std::__uninitialized_allocator_relocate(
- __alloc_, std::__to_address(__v.begin()), std::__to_address(__v.end()), std::__to_address(__merged.end()));
+ __allocator_ref(),
+ std::__to_address(__v.begin()),
+ std::__to_address(__v.end()),
+ std::__to_address(__merged.end()));
__merged.__set_sentinel(__merged.size() + __v.size());
__v.__set_sentinel(__v.begin());
__p = __swap_out_circular_buffer(__merged, __p);
@@ -1330,16 +1659,17 @@ template <class _Iterator, class _Sentinel>
_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<difference_type>(__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 +1685,7 @@ vector<_Tp, _Allocator>::__insert_with_size(
__insert_assign_n_unchecked(std::move(__first), __n, __p);
}
} else {
- __split_buffer<value_type, allocator_type&> __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);
}
@@ -1370,12 +1700,12 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::resize(size_type __n
if (__new_size <= capacity()) {
__construct_at_end(__new_size - __current_size);
} else {
- __split_buffer<value_type, allocator_type&> __v(__recommend(__new_size), __current_size, __alloc_);
+ __split_buffer __v(__recommend(__new_size), __current_size, __allocator_ref());
__v.__construct_at_end(__new_size - __current_size);
__swap_out_circular_buffer(__v);
}
} else if (__current_size > __new_size) {
- this->__destruct_at_end(this->__begin_ + __new_size);
+ this->__destruct_at_end(__raw_begin() + __new_size);
}
}
@@ -1386,55 +1716,21 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::resize(size_type __n
if (__new_size <= capacity())
__construct_at_end(__new_size - __current_size, __x);
else {
- __split_buffer<value_type, allocator_type&> __v(__recommend(__new_size), __current_size, __alloc_);
+ __split_buffer __v(__recommend(__new_size), __current_size, __allocator_ref());
__v.__construct_at_end(__new_size - __current_size, __x);
__swap_out_circular_buffer(__v);
}
} else if (__current_size > __new_size) {
- this->__destruct_at_end(this->__begin_ + __new_size);
+ this->__destruct_at_end(__raw_begin() + __new_size);
}
}
-template <class _Tp, class _Allocator>
-_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<allocator_type>)
-#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 <class _Tp, class _Allocator>
-_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;
-}
-
#if _LIBCPP_STD_VER >= 20
-template <>
-inline constexpr bool __format::__enable_insertable<vector<char>> = true;
+template <class _Allocator>
+inline constexpr bool __format::__enable_insertable<vector<char, _Allocator>> = true;
# if _LIBCPP_HAS_WIDE_CHARACTERS
-template <>
-inline constexpr bool __format::__enable_insertable<vector<wchar_t>> = true;
+template <class _Allocator>
+inline constexpr bool __format::__enable_insertable<vector<wchar_t, _Allocator>> = true;
# endif
#endif // _LIBCPP_STD_VER >= 20
diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.swap/ranges.swap_ranges.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.swap/ranges.swap_ranges.pass.cpp
index 85557ecbbfabc..da42ce56db30a 100644
--- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.swap/ranges.swap_ranges.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.swap/ranges.swap_ranges.pass.cpp
@@ -67,22 +67,6 @@ TEST_CONSTEXPR_CXX20 void test_iterators() {
}
}
-template <std::size_t N>
-constexpr void test_vector_bool() {
- { // Test swap_ranges() with aligned bytes
- std::vector<bool> 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<bool> f(N, false), t(N + 8, true);
- std::ranges::swap_ranges(f.begin(), f.end(), t.begin() + 4, t.end() - 4);
- assert(std::all_of(f.begin(), f.end(), [](bool b) { return b; }));
- assert(std::all_of(t.begin() + 4, t.end() - 4, [](bool b) { return !b; }));
- }
-}
-
constexpr bool test() {
{ // Validate swapping ranges directly
std::array r1 = {1, 2, 3};
@@ -183,15 +167,34 @@ constexpr bool test() {
});
});
- { // Test vector<bool>::iterator optimization
- test_vector_bool<8>();
- test_vector_bool<19>();
- test_vector_bool<32>();
- test_vector_bool<49>();
- test_vector_bool<64>();
- test_vector_bool<199>();
- test_vector_bool<256>();
+ return true;
+}
+
+// Test vector<bool>::iterator optimization
+template <std::size_t N>
+constexpr void test_vector_bool() {
+ { // Test swap_ranges() with aligned bytes
+ std::vector<bool> 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<bool> f(N, false), t(N + 8, true);
+ std::ranges::swap_ranges(f.begin(), f.end(), t.begin() + 4, t.end() - 4);
+ assert(std::all_of(f.begin(), f.end(), [](bool b) { return b; }));
+ assert(std::all_of(t.begin() + 4, t.end() - 4, [](bool b) { return !b; }));
+ }
+}
+
+constexpr bool test_vector_bool() {
+ test_vector_bool<8>();
+ test_vector_bool<19>();
+ test_vector_bool<32>();
+ test_vector_bool<49>();
+ test_vector_bool<64>();
+ test_vector_bool<199>();
+ test_vector_bool<256>();
return true;
}
@@ -201,5 +204,8 @@ int main(int, char**) {
test();
static_assert(test());
+ test_vector_bool();
+ static_assert(test_vector_bool());
+
return 0;
}
diff --git a/libcxx/utils/gdb/libcxx/printers.py b/libcxx/utils/gdb/libcxx/printers.py
index 1c8ef6d7feb97..1bfdd718e36bc 100644
--- a/libcxx/utils/gdb/libcxx/printers.py
+++ b/libcxx/utils/gdb/libcxx/printers.py
@@ -13,6 +13,7 @@
from __future__ import print_function
import re
+import sys
import gdb
import gdb.printing
@@ -351,17 +352,28 @@ def __init__(self, val):
"""Set val, length, capacity, and iterator for bool and normal vectors."""
self.val = val
self.typename = _remove_generics(_prettify_typename(val.type))
- begin = self.val["__begin_"]
if self.val.type.template_argument(0).code == gdb.TYPE_CODE_BOOL:
+ begin = self.val["__begin_"]
self.typename += "<bool>"
self.length = self.val["__size_"]
bits_per_word = self.val["__bits_per_word"]
self.capacity = self.val["__cap_"] * bits_per_word
self.iterator = self._VectorBoolIterator(begin, self.length, bits_per_word)
else:
- end = self.val["__end_"]
+ for i in val.type.fields():
+ if i.is_base_class:
+ base = val[i]
+ break
+
+ begin = base["__begin_"]
+ end = base["__end_"]
self.length = end - begin
- self.capacity = self.val["__cap_"] - begin
+ for i in base.type.fields():
+ if i.name == "__cap_":
+ self.capacity = base["__cap_"] - begin
+ elif i.name == None:
+ self.capacity = base[i]["__cap_"] - begin
+ break
self.iterator = self._VectorIterator(begin, end)
def to_string(self):
>From 0580dea4fe36bd54f2b6581411f4584087411c2b Mon Sep 17 00:00:00 2001
From: Christopher Di Bella <cjdb at google.com>
Date: Tue, 13 Jan 2026 21:14:12 +0000
Subject: [PATCH 02/14] works `__vector_layout` into `vector`
[jyknight pointed out that we'd probably end up with a smaller diff][1]
(and simpler code) if we remove the `__vector_layout` type. [This also
reduces the volume of debuginfo, as pointed out by rnk][2].
[1]: https://github.com/llvm/llvm-project/pull/155330#discussion_r2607411335
[2]: https://github.com/llvm/llvm-project/pull/155330#discussion_r2612499610
---
libcxx/include/__vector/vector.h | 712 ++++++++++++-------------------
1 file changed, 281 insertions(+), 431 deletions(-)
diff --git a/libcxx/include/__vector/vector.h b/libcxx/include/__vector/vector.h
index a78ee5918517d..29cd205aeb8da 100644
--- a/libcxx/include/__vector/vector.h
+++ b/libcxx/include/__vector/vector.h
@@ -84,334 +84,18 @@ _LIBCPP_PUSH_MACROS
_LIBCPP_BEGIN_NAMESPACE_STD
-#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
-template <class _Vector, class _Tp, class _Allocator>
-class __vector_layout {
-public:
- using value_type = _Tp;
- using allocator_type = _Allocator;
- using __alloc_traits _LIBCPP_NODEBUG = allocator_traits<allocator_type>;
- 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;
-
- _LIBCPP_HIDE_FROM_ABI __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_)) {
- __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<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"
- " 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<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(pointer __pos) _NOEXCEPT {
- __cap_ = static_cast<size_type>(__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, class _Tp, class _Allocator>
-class __vector_layout {
-public:
- using value_type = _Tp;
- using allocator_type = _Allocator;
- using __alloc_traits _LIBCPP_NODEBUG = allocator_traits<allocator_type>;
- using reference = value_type&;
- using const_reference = const value_type&;
- using size_type = typename __alloc_traits::size_type;
- using difference_type = typename __alloc_traits::difference_type;
- using pointer = typename __alloc_traits::pointer;
- using const_pointer = typename __alloc_traits::const_pointer;
- using __split_buffer _LIBCPP_NODEBUG = std::__split_buffer<_Tp, _Allocator, __split_buffer_pointer_layout>;
- using __sentinel_type _LIBCPP_NODEBUG = pointer;
-
- // Can't be defaulted due to _LIBCPP_COMPRESSED_PAIR not being an aggregate in C++03 and C++11.
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __vector_layout()
- _NOEXCEPT_(is_nothrow_default_constructible<allocator_type>::value)
- : __cap_(nullptr) {}
-
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __vector_layout(allocator_type const& __a)
- _NOEXCEPT_(is_nothrow_copy_constructible<allocator_type>::value)
- : __cap_(nullptr), __alloc_(__a) {}
-
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __vector_layout(allocator_type&& __a)
- _NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value)
- : __cap_(nullptr), __alloc_(std::move(__a)) {}
-
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __vector_layout(__vector_layout&& __other)
- _NOEXCEPT_(is_nothrow_move_constructible<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;
- }
-
- // Capacity
- [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT {
- return static_cast<size_type>(__end_ - __begin_);
- }
-
- [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type capacity() const _NOEXCEPT {
- return static_cast<size_type>(__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<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"
- " or the allocators must compare equal");
- std::swap(__begin_, __x.__begin_);
- std::swap(__end_, __x.__end_);
- std::swap(__cap_, __x.__cap_);
- std::__swap_allocator(__alloc_, __x.__alloc_);
- }
-
- [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer __raw_begin() const _NOEXCEPT {
- return __begin_;
- }
-
- [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer __raw_sentinel() const _NOEXCEPT {
- return __end_;
- }
-
- [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer __raw_capacity() const _NOEXCEPT {
- return __cap_;
- }
-
- [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer __end_pointer() const _NOEXCEPT {
- return __end_;
- }
-
- [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type
- __remaining_capacity() const _NOEXCEPT {
- return __cap_ - __end_;
- }
-
- [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __is_full() const _NOEXCEPT {
- return __end_ == __cap_;
- }
-
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_valid_range(pointer __begin, pointer __end) _NOEXCEPT {
- __begin_ = __begin;
- __end_ = __end;
- }
-
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
- __set_valid_range(pointer __begin, size_type __size) _NOEXCEPT {
- __begin_ = __begin;
- __end_ = __begin_ + __size;
- }
-
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_sentinel(pointer __end) _NOEXCEPT { __end_ = __end; }
-
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_sentinel(size_type __offset) _NOEXCEPT {
- __end_ = __begin_ + __offset;
- }
-
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_capacity(pointer __cap) _NOEXCEPT { __cap_ = __cap; }
-
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_capacity(size_type __offset) _NOEXCEPT {
- __cap_ = __begin_ + __offset;
- }
-
- [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __invariants() const {
- if (__begin_ == nullptr) {
- if (__end_ != nullptr || __cap_ != nullptr)
- return false;
- } else {
- if (__begin_ > __end_)
- return false;
- if (__begin_ == __cap_)
- return false;
- if (__end_ > __cap_)
- return false;
- }
- return true;
- }
-
-private:
- pointer __begin_ = nullptr;
- pointer __end_ = nullptr;
- _LIBCPP_COMPRESSED_PAIR(pointer, __cap_, allocator_type, __alloc_);
-};
-#endif // _LIBCPP_ABI_SIZE_BASED_VECTOR
-
template <class _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_capacity;
- using __base::__raw_sentinel;
- using __base::__remaining_capacity;
- using __base::__set_capacity;
- using __base::__set_sentinel;
- using __base::__set_valid_range;
- using typename __base::__alloc_traits;
- using typename __base::__sentinel_type;
- using typename __base::__split_buffer;
-
+class vector {
public:
- 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;
+ using value_type = _Tp;
+ using allocator_type = _Allocator;
+ using __alloc_traits _LIBCPP_NODEBUG = allocator_traits<allocator_type>;
+ 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;
#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
@@ -425,8 +109,6 @@ class vector : __vector_layout<vector<_Tp, _Allocator>, _Tp, _Allocator> {
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
- using __base::__invariants;
-
// A vector 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
@@ -451,7 +133,7 @@ class vector : __vector_layout<vector<_Tp, _Allocator>, _Tp, _Allocator> {
#else
noexcept
#endif
- : __base(__a) {
+ : __alloc_(__a) {
}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit vector(size_type __n) {
@@ -465,7 +147,7 @@ class vector : __vector_layout<vector<_Tp, _Allocator>, _Tp, _Allocator> {
#if _LIBCPP_STD_VER >= 14
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit vector(size_type __n, const allocator_type& __a)
- : __base(__a) {
+ : __alloc_(__a) {
auto __guard = std::__make_exception_guard(__destroy_vector(*this));
if (__n > 0) {
__vallocate(__n);
@@ -487,7 +169,7 @@ class vector : __vector_layout<vector<_Tp, _Allocator>, _Tp, _Allocator> {
template <__enable_if_t<__is_allocator_v<_Allocator>, int> = 0>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
vector(size_type __n, const value_type& __x, const allocator_type& __a)
- : __base(__a) {
+ : __alloc_(__a) {
auto __guard = std::__make_exception_guard(__destroy_vector(*this));
if (__n > 0) {
__vallocate(__n);
@@ -510,7 +192,7 @@ class vector : __vector_layout<vector<_Tp, _Allocator>, _Tp, _Allocator> {
int> = 0>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
vector(_InputIterator __first, _InputIterator __last, const allocator_type& __a)
- : __base(__a) {
+ : __alloc_(__a) {
__init_with_sentinel(__first, __last);
}
@@ -531,7 +213,7 @@ class vector : __vector_layout<vector<_Tp, _Allocator>, _Tp, _Allocator> {
int> = 0>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
vector(_ForwardIterator __first, _ForwardIterator __last, const allocator_type& __a)
- : __base(__a) {
+ : __alloc_(__a) {
size_type __n = static_cast<size_type>(std::distance(__first, __last));
__init_with_size(__first, __last, __n);
}
@@ -540,7 +222,7 @@ class vector : __vector_layout<vector<_Tp, _Allocator>, _Tp, _Allocator> {
template <_ContainerCompatibleRange<_Tp> _Range>
_LIBCPP_HIDE_FROM_ABI constexpr vector(
from_range_t, _Range&& __range, const allocator_type& __alloc = allocator_type())
- : __base(__alloc) {
+ : __alloc_(__alloc) {
if constexpr (ranges::forward_range<_Range> || ranges::sized_range<_Range>) {
auto __n = static_cast<size_type>(ranges::distance(__range));
__init_with_size(ranges::begin(__range), ranges::end(__range), __n);
@@ -557,10 +239,10 @@ class vector : __vector_layout<vector<_Tp, _Allocator>, _Tp, _Allocator> {
_LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI __destroy_vector(vector& __vec) : __vec_(__vec) {}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void operator()() {
- if (__vec_.__raw_begin() != nullptr) {
+ if (__vec_.__begin_ != nullptr) {
__vec_.clear();
__vec_.__annotate_delete();
- __alloc_traits::deallocate(__vec_.__allocator_ref(), __vec_.__raw_begin(), __vec_.capacity());
+ __alloc_traits::deallocate(__vec_.__alloc_, __vec_.__begin_, __vec_.capacity());
}
}
@@ -572,13 +254,13 @@ class vector : __vector_layout<vector<_Tp, _Allocator>, _Tp, _Allocator> {
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI ~vector() { __destroy_vector (*this)(); }
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI vector(const vector& __x)
- : __base(__alloc_traits::select_on_container_copy_construction(__x.__allocator_ref())) {
- __init_with_size(__x.__raw_begin(), __x.__end_pointer(), __x.size());
+ : __alloc_(__alloc_traits::select_on_container_copy_construction(__x.__alloc_)) {
+ __init_with_size(__x.__begin_, __x.__end_pointer(), __x.size());
}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
vector(const vector& __x, const __type_identity_t<allocator_type>& __a)
- : __base(__a) {
- __init_with_size(__x.__raw_begin(), __x.__end_pointer(), __x.size());
+ : __alloc_(__a) {
+ __init_with_size(__x.__begin_, __x.__end_pointer(), __x.size());
}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI vector& operator=(const vector& __x);
@@ -589,7 +271,7 @@ class vector : __vector_layout<vector<_Tp, _Allocator>, _Tp, _Allocator> {
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
vector(initializer_list<value_type> __il, const allocator_type& __a)
- : __base(__a) {
+ : __alloc_(__a) {
__init_with_size(__il.begin(), __il.end(), __il.size());
}
@@ -652,17 +334,17 @@ class vector : __vector_layout<vector<_Tp, _Allocator>, _Tp, _Allocator> {
#endif
[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const _NOEXCEPT {
- return __allocator_ref();
+ return __alloc_;
}
//
// Iterators
//
[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT {
- return __make_iter(__add_alignment_assumption(__raw_begin()));
+ return __make_iter(__add_alignment_assumption(__begin_));
}
[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT {
- return __make_iter(__add_alignment_assumption(__raw_begin()));
+ return __make_iter(__add_alignment_assumption(__begin_));
}
[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT {
return __make_iter(__add_alignment_assumption(__end_pointer()));
@@ -704,17 +386,30 @@ class vector : __vector_layout<vector<_Tp, _Allocator>, _Tp, _Allocator> {
//
// Capacity
+#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT {
- return __base::size();
+ return __size_;
}
[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type capacity() const _NOEXCEPT {
- return __base::capacity();
+ return __cap_;
}
[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool empty() const _NOEXCEPT {
- return __base::empty();
+ return __size_ == 0;
}
+#else
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT {
+ return static_cast<size_type>(__end_ - __begin_);
+ }
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type capacity() const _NOEXCEPT {
+ return static_cast<size_type>(__cap_ - __begin_);
+ }
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool empty() const _NOEXCEPT {
+ return __begin_ == __end_;
+ }
+#endif // _LIBCPP_ABI_SIZE_BASED_VECTOR
+
[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT {
- return std::min<size_type>(__alloc_traits::max_size(__allocator_ref()), numeric_limits<difference_type>::max());
+ return std::min<size_type>(__alloc_traits::max_size(__alloc_), numeric_limits<difference_type>::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;
@@ -724,48 +419,62 @@ class vector : __vector_layout<vector<_Tp, _Allocator>, _Tp, _Allocator> {
//
[[__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 __raw_begin()[__n];
+ return __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 __raw_begin()[__n];
+ return __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 __raw_begin()[__n];
+ return __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 __raw_begin()[__n];
+ return __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 *__raw_begin();
+ return *__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 *__raw_begin();
+ return *__begin_;
}
+
+#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference back() _NOEXCEPT {
- return __base::back();
+ _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];
+ }
+#else
+ [[__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 {
- return __base::back();
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "back() called on an empty vector");
+ return *(__end_ - 1);
}
+#endif // _LIBCPP_ABI_SIZE_BASED_VECTOR
//
// [vector.data], data access
//
[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI value_type* data() _NOEXCEPT {
- return std::__to_address(__raw_begin());
+ return std::__to_address(__begin_);
}
[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const value_type* data() const _NOEXCEPT {
- return std::__to_address(__raw_begin());
+ return std::__to_address(__begin_);
}
//
@@ -790,7 +499,7 @@ class vector : __vector_layout<vector<_Tp, _Allocator>, _Tp, _Allocator> {
_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(__allocator_ref(), std::__to_address(__tx.__pos_), std::forward<_Args>(__args)...);
+ __alloc_traits::construct(__alloc_, std::__to_address(__tx.__pos_), std::forward<_Args>(__args)...);
++__tx.__pos_;
}
@@ -802,12 +511,12 @@ class vector : __vector_layout<vector<_Tp, _Allocator>, _Tp, _Allocator> {
if (__len < __raw_capacity() - __raw_sentinel()) {
__construct_at_end(ranges::begin(__range), ranges::end(__range), __len);
} else {
- __split_buffer __buffer(__recommend(size() + __len), size(), __allocator_ref());
+ __split_buffer __buffer(__recommend(size() + __len), size(), __alloc_);
__buffer.__construct_at_end_with_size(ranges::begin(__range), __len);
__swap_out_circular_buffer(__buffer);
}
} else {
- vector __buffer(__allocator_ref());
+ vector __buffer(__alloc_);
for (auto&& __val : __range)
__buffer.emplace_back(std::forward<decltype(__val)>(__val));
append_range(ranges::as_rvalue_view(__buffer));
@@ -873,7 +582,7 @@ class vector : __vector_layout<vector<_Tp, _Allocator>, _Tp, _Allocator> {
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void clear() _NOEXCEPT {
size_type __old_size = size();
- __base_destruct_at_end(__raw_begin());
+ __base_destruct_at_end(__begin_);
__annotate_shrink(__old_size);
}
@@ -887,10 +596,151 @@ class vector : __vector_layout<vector<_Tp, _Allocator>, _Tp, _Allocator> {
_NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || __is_nothrow_swappable_v<allocator_type>)
#endif
{
- __base::swap(__other);
+ _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(
+ __alloc_traits::propagate_on_container_swap::value || __alloc_ == __other.__alloc_,
+ "vector::swap: Either propagate_on_container_swap must be true"
+ " or the allocators must compare equal");
+ std::swap(__begin_, __other.__begin_);
+#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+ std::swap(__size_, __other.__size_);
+#else
+ std::swap(__end_, __other.__end_);
+#endif
+ std::swap(__cap_, __other.__cap_);
+ std::__swap_allocator(__alloc_, __other.__alloc_);
+ }
+
+#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+public:
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __invariants() const {
+ if (__begin_ == nullptr) {
+ if (__size_ != 0 || __cap_ != 0)
+ return false;
+ } else {
+ if (__size_ > __cap_)
+ return false;
+ }
+ return true;
+ }
+private:
+ using __sentinel_type _LIBCPP_NODEBUG = size_type;
+ using __split_buffer _LIBCPP_NODEBUG = __split_buffer<_Tp, _Allocator, __split_buffer_size_layout>;
+
+ [[__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 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<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(pointer __pos) _NOEXCEPT {
+ __cap_ = static_cast<size_type>(__pos - __begin_);
+ }
+
+ pointer __begin_ = nullptr;
+ size_type __size_ = 0;
+ size_type __cap_ = 0;
+ [[no_unique_address]] allocator_type __alloc_;
+#else
+public:
+ [[__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:
+ using __split_buffer _LIBCPP_NODEBUG = __split_buffer<_Tp, _Allocator, __split_buffer_pointer_layout>;
+ using __sentinel_type _LIBCPP_NODEBUG = pointer;
+
+ [[__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 __end_pointer() const _NOEXCEPT {
+ return __end_;
+ }
+
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __remaining_capacity() const _NOEXCEPT {
+ return __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(pointer __pos) _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;
+ }
+
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_capacity(size_type __offset) _NOEXCEPT {
+ __cap_ = __begin_ + __offset;
+ }
+
+ pointer __begin_ = nullptr;
+ pointer __end_ = nullptr;
+ _LIBCPP_COMPRESSED_PAIR(pointer, __cap_ = nullptr, allocator_type, __alloc_);
+#endif // _LIBCPP_ABI_SIZE_BASED_VECTOR
+
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __sentinel_type __raw_capacity() const _NOEXCEPT {
+ return __cap_;
+ }
+
// Allocate space for __n objects
// throws length_error if __n > max_size()
// throws (probably bad_alloc) if memory run out
@@ -903,7 +753,7 @@ class vector : __vector_layout<vector<_Tp, _Allocator>, _Tp, _Allocator> {
_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(__allocator_ref(), __n);
+ auto __allocation = std::__allocate_at_least(__alloc_, __n);
__set_valid_range(__allocation.ptr, static_cast<size_type>(0));
__set_capacity(__allocation.count);
__annotate_new(0);
@@ -954,7 +804,7 @@ class vector : __vector_layout<vector<_Tp, _Allocator>, _Tp, _Allocator> {
_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<value_type, _Allocator> __tmp(__allocator_ref(), *__first);
+ __temp_value<value_type, _Allocator> __tmp(__alloc_, *__first);
*__position = std::move(__tmp.get());
}
}
@@ -992,7 +842,7 @@ class vector : __vector_layout<vector<_Tp, _Allocator>, _Tp, _Allocator> {
// a laxer approach.
return std::__make_bounded_iter(
std::__wrap_iter<pointer>(__p),
- std::__wrap_iter<pointer>(__raw_begin()),
+ std::__wrap_iter<pointer>(__begin_),
std::__wrap_iter<pointer>(__raw_capacity()));
#else
return iterator(__p);
@@ -1004,7 +854,7 @@ class vector : __vector_layout<vector<_Tp, _Allocator>, _Tp, _Allocator> {
// Bound the iterator according to the capacity, rather than the size.
return std::__make_bounded_iter(
std::__wrap_iter<const_pointer>(__p),
- std::__wrap_iter<const_pointer>(__raw_begin()),
+ std::__wrap_iter<const_pointer>(__begin_),
std::__wrap_iter<const_pointer>(__raw_capacity()));
#else
return const_iterator(__p);
@@ -1068,7 +918,7 @@ class vector : __vector_layout<vector<_Tp, _Allocator>, _Tp, _Allocator> {
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI ~_ConstructTransaction() {
__v_.__set_sentinel(__pos_);
if (__pos_ != __new_end_) {
- __v_.__annotate_shrink(__new_end_ - __v_.__raw_begin());
+ __v_.__annotate_shrink(__new_end_ - __v_.__begin_);
}
}
@@ -1083,7 +933,7 @@ class vector : __vector_layout<vector<_Tp, _Allocator>, _Tp, _Allocator> {
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __base_destruct_at_end(pointer __new_last) _NOEXCEPT {
pointer __soon_to_be_end = __end_pointer();
while (__new_last != __soon_to_be_end)
- __alloc_traits::destroy(__allocator_ref(), std::__to_address(--__soon_to_be_end));
+ __alloc_traits::destroy(__alloc_, std::__to_address(--__soon_to_be_end));
__set_sentinel(__new_last);
}
@@ -1102,21 +952,21 @@ class vector : __vector_layout<vector<_Tp, _Allocator>, _Tp, _Allocator> {
[[__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 (__allocator_ref() != __c.__allocator_ref()) {
+ if (__alloc_ != __c.__alloc_) {
clear();
__annotate_delete();
- __alloc_traits::deallocate(__allocator_ref(), __raw_begin(), capacity());
+ __alloc_traits::deallocate(__alloc_, __begin_, capacity());
__set_valid_range(nullptr, static_cast<size_type>(0));
__set_capacity(static_cast<__sentinel_type>(0));
}
- __allocator_ref() = __c.__allocator_ref();
+ __alloc_ = __c.__alloc_;
}
_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<allocator_type>::value) {
- __allocator_ref() = std::move(__c.__allocator_ref());
+ __alloc_ = std::move(__c.__alloc_);
}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __move_assign_alloc(vector&, false_type) _NOEXCEPT {}
@@ -1137,7 +987,7 @@ class vector : __vector_layout<vector<_Tp, _Allocator>, _Tp, _Allocator> {
}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __swap_layouts(__split_buffer& __sb) {
- auto __vector_begin = __raw_begin();
+ auto __vector_begin = __begin_;
auto __vector_sentinel = __raw_sentinel();
auto __vector_cap = __raw_capacity();
@@ -1174,7 +1024,7 @@ 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
+// __swap_out_circular_buffer relocates the objects in [__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>
@@ -1182,8 +1032,8 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::__swap_out_circular_
__annotate_delete();
auto __new_begin = __v.begin() - size();
std::__uninitialized_allocator_relocate(
- __allocator_ref(),
- std::__to_address(__raw_begin()),
+ __alloc_,
+ std::__to_address(__begin_),
std::__to_address(__end_pointer()),
std::__to_address(__new_begin));
__v.__set_valid_range(__new_begin, __v.end());
@@ -1195,10 +1045,10 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::__swap_out_circular_
__annotate_new(size());
}
-// __swap_out_circular_buffer relocates the objects in [__raw_begin(), __p) into the front of __v, the objects in
+// __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 - __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.
+// exactly (__p - __begin_) objects in the front and space for at least (size() - __p) objects in the back. This
+// function has a strong exception guarantee if __begin_ == __p || size() == __p.
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::pointer
vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer& __v, pointer __p) {
@@ -1206,18 +1056,18 @@ vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer& __v, pointer
pointer __ret = __v.begin();
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.
+ // Relocate [__p, __end) first to avoid having a hole in [__begin_, __end)
+ // in case something in [__begin_, __p) throws.
std::__uninitialized_allocator_relocate(
- __allocator_ref(), std::__to_address(__p), std::__to_address(__end), std::__to_address(__v.end()));
+ __alloc_, 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());
+ auto __new_begin = __v.begin() - (__p - __begin_);
std::__uninitialized_allocator_relocate(
- __allocator_ref(), std::__to_address(__raw_begin()), std::__to_address(__p), std::__to_address(__new_begin));
+ __alloc_, std::__to_address(__begin_), std::__to_address(__p), std::__to_address(__new_begin));
__v.__set_valid_range(__new_begin, __v.size() + size());
__set_sentinel(static_cast<size_type>(0)); // All the objects have been destroyed by relocating them.
@@ -1229,10 +1079,10 @@ vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer& __v, pointer
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::__vdeallocate() _NOEXCEPT {
- if (__raw_begin() != nullptr) {
+ if (__begin_ != nullptr) {
clear();
__annotate_delete();
- __alloc_traits::deallocate(__allocator_ref(), __raw_begin(), capacity());
+ __alloc_traits::deallocate(__alloc_, __begin_, capacity());
__set_valid_range(nullptr, static_cast<size_type>(0));
__set_capacity(static_cast<size_type>(0));
}
@@ -1261,7 +1111,7 @@ _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(__allocator_ref(), std::__to_address(__pos));
+ __alloc_traits::construct(__alloc_, std::__to_address(__pos));
}
}
@@ -1277,7 +1127,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(__allocator_ref(), std::__to_address(__pos), __x);
+ __alloc_traits::construct(__alloc_, std::__to_address(__pos), __x);
}
}
@@ -1287,7 +1137,7 @@ _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_);
+ std::__uninitialized_allocator_copy(__alloc_, std::move(__first), std::move(__last), __tx.__pos_);
}
template <class _Tp, class _Allocator>
@@ -1297,8 +1147,8 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI vector<_Tp, _Allocato
#else
_NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value)
#endif
- : __base(std::move(__x.__allocator_ref())) {
- __set_valid_range(__x.__raw_begin(), __x.__raw_sentinel());
+ : __alloc_(std::move(__x.__alloc_)) {
+ __set_valid_range(__x.__begin_, __x.__raw_sentinel());
__set_capacity(__x.__raw_capacity());
__x.__set_valid_range(nullptr, static_cast<size_type>(0));
__x.__set_capacity(static_cast<size_type>(0));
@@ -1307,9 +1157,9 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI vector<_Tp, _Allocato
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI
vector<_Tp, _Allocator>::vector(vector&& __x, const __type_identity_t<allocator_type>& __a)
- : __base(__a) {
- if (__a == __x.__allocator_ref()) {
- __set_valid_range(__x.__raw_begin(), __x.__raw_sentinel());
+ : __alloc_(__a) {
+ if (__a == __x.__alloc_) {
+ __set_valid_range(__x.__begin_, __x.__raw_sentinel());
__set_capacity(__x.__raw_capacity());
__x.__set_valid_range(nullptr, static_cast<size_type>(0));
__x.__set_capacity(static_cast<size_type>(0));
@@ -1322,7 +1172,7 @@ vector<_Tp, _Allocator>::vector(vector&& __x, const __type_identity_t<allocator_
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::__move_assign(vector& __c, false_type)
_NOEXCEPT_(__alloc_traits::is_always_equal::value) {
- if (__allocator_ref() != __c.__allocator_ref()) {
+ if (__alloc_ != __c.__alloc_) {
typedef move_iterator<iterator> _Ip;
assign(_Ip(__c.begin()), _Ip(__c.end()));
} else
@@ -1334,7 +1184,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::__move_assign(vector
_NOEXCEPT_(is_nothrow_move_assignable<allocator_type>::value) {
__vdeallocate();
__move_assign_alloc(__c); // this can throw
- __set_valid_range(__c.__raw_begin(), __c.__raw_sentinel());
+ __set_valid_range(__c.__begin_, __c.__raw_sentinel());
__set_capacity(__c.__raw_capacity());
__c.__set_valid_range(nullptr, static_cast<size_type>(0));
__c.__set_capacity(static_cast<size_type>(0));
@@ -1345,7 +1195,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.__raw_begin(), __x.__end_pointer());
+ assign(__x.__begin_, __x.__end_pointer());
}
return *this;
}
@@ -1354,7 +1204,7 @@ template <class _Tp, class _Allocator>
template <class _Iterator, class _Sentinel>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
vector<_Tp, _Allocator>::__assign_with_sentinel(_Iterator __first, _Sentinel __last) {
- pointer __cur = __raw_begin();
+ pointer __cur = __begin_;
pointer __end = __end_pointer();
for (; __first != __last && __cur != __end; ++__first, (void)++__cur)
*__cur = *__first;
@@ -1374,10 +1224,10 @@ vector<_Tp, _Allocator>::__assign_with_size(_Iterator __first, _Sentinel __last,
if (__new_size <= capacity()) {
if (__new_size > size()) {
auto const __size = size();
- auto __mid = std::__copy_n<_AlgPolicy>(std::move(__first), __size, __raw_begin()).first;
+ auto __mid = std::__copy_n<_AlgPolicy>(std::move(__first), __size, __begin_).first;
__construct_at_end(std::move(__mid), std::move(__last), __new_size - __size);
} else {
- pointer __m = std::__copy(std::move(__first), __last, __raw_begin()).second;
+ pointer __m = std::__copy(std::move(__first), __last, __begin_).second;
this->__destruct_at_end(__m);
}
} else {
@@ -1391,11 +1241,11 @@ template <class _Tp, class _Allocator>
_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(__raw_begin(), std::min(__n, __s), __u);
+ std::fill_n(__begin_, std::min(__n, __s), __u);
if (__n > __s)
__construct_at_end(__n - __s, __u);
else
- this->__destruct_at_end(__raw_begin() + __n);
+ this->__destruct_at_end(__begin_ + __n);
} else {
__vdeallocate();
__vallocate(__recommend(static_cast<size_type>(__n)));
@@ -1408,7 +1258,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(), __allocator_ref());
+ __split_buffer __v(__n, size(), __alloc_);
__swap_out_circular_buffer(__v);
}
}
@@ -1419,7 +1269,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(), __allocator_ref());
+ __split_buffer __v(size(), size(), __alloc_);
// 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.
@@ -1436,10 +1286,10 @@ template <class _Tp, class _Allocator>
template <class... _Args>
_LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::__sentinel_type
vector<_Tp, _Allocator>::__emplace_back_slow_path(_Args&&... __args) {
- __split_buffer __v(__recommend(size() + 1), size(), __allocator_ref());
+ __split_buffer __v(__recommend(size() + 1), size(), __alloc_);
// __v.emplace_back(std::forward<_Args>(__args)...);
pointer __end = __v.end();
- __alloc_traits::construct(__allocator_ref(), std::__to_address(__end), std::forward<_Args>(__args)...);
+ __alloc_traits::construct(__alloc_, std::__to_address(__end), std::forward<_Args>(__args)...);
__v.__set_sentinel(++__end);
__swap_out_circular_buffer(__v);
return __raw_sentinel();
@@ -1493,7 +1343,7 @@ 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 = __raw_begin() + __ps;
+ pointer __p = __begin_ + __ps;
this->__destruct_at_end(std::move(__p + 1, __end_pointer(), __p));
return __make_iter(__p);
}
@@ -1502,7 +1352,7 @@ template <class _Tp, class _Allocator>
_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 = __raw_begin() + (__first - begin());
+ pointer __p = __begin_ + (__first - begin());
if (__first != __last) {
this->__destruct_at_end(std::move(__p + (__last - __first), __end_pointer(), __p));
}
@@ -1518,7 +1368,7 @@ vector<_Tp, _Allocator>::__move_range(pointer __from_s, pointer __from_e, pointe
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(__allocator_ref(), std::__to_address(__pos), std::move(*__i));
+ __alloc_traits::construct(__alloc_, std::__to_address(__pos), std::move(*__i));
}
}
std::move_backward(__from_s, __from_s + __n, __old_last);
@@ -1527,7 +1377,7 @@ vector<_Tp, _Allocator>::__move_range(pointer __from_s, pointer __from_e, pointe
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::iterator
vector<_Tp, _Allocator>::insert(const_iterator __position, const_reference __x) {
- pointer __p = __raw_begin() + (__position - begin());
+ pointer __p = __begin_ + (__position - begin());
if (!__is_full()) {
pointer __end = __end_pointer();
if (__p == __end) {
@@ -1540,7 +1390,7 @@ vector<_Tp, _Allocator>::insert(const_iterator __position, const_reference __x)
*__p = *__xr;
}
} else {
- __split_buffer __v(__recommend(size() + 1), __p - __raw_begin(), __allocator_ref());
+ __split_buffer __v(__recommend(size() + 1), __p - __begin_, __alloc_);
__v.emplace_back(__x);
__p = __swap_out_circular_buffer(__v, __p);
}
@@ -1550,7 +1400,7 @@ vector<_Tp, _Allocator>::insert(const_iterator __position, const_reference __x)
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::iterator
vector<_Tp, _Allocator>::insert(const_iterator __position, value_type&& __x) {
- pointer __p = __raw_begin() + (__position - begin());
+ pointer __p = __begin_ + (__position - begin());
if (!__is_full()) {
pointer __end = __end_pointer();
if (__p == __end) {
@@ -1560,7 +1410,7 @@ vector<_Tp, _Allocator>::insert(const_iterator __position, value_type&& __x) {
*__p = std::move(__x);
}
} else {
- __split_buffer __v(__recommend(size() + 1), __p - __raw_begin(), __allocator_ref());
+ __split_buffer __v(__recommend(size() + 1), __p - __begin_, __alloc_);
__v.emplace_back(std::move(__x));
__p = __swap_out_circular_buffer(__v, __p);
}
@@ -1571,18 +1421,18 @@ template <class _Tp, class _Allocator>
template <class... _Args>
_LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::iterator
vector<_Tp, _Allocator>::emplace(const_iterator __position, _Args&&... __args) {
- pointer __p = __raw_begin() + (__position - begin());
+ pointer __p = __begin_ + (__position - begin());
if (!__is_full()) {
pointer __end = __end_pointer();
if (__p == __end) {
__emplace_back_assume_capacity(std::forward<_Args>(__args)...);
} else {
- __temp_value<value_type, _Allocator> __tmp(__allocator_ref(), std::forward<_Args>(__args)...);
+ __temp_value<value_type, _Allocator> __tmp(__alloc_, std::forward<_Args>(__args)...);
__move_range(__p, __end, __p + 1);
*__p = std::move(__tmp.get());
}
} else {
- __split_buffer __v(__recommend(size() + 1), __p - __raw_begin(), __allocator_ref());
+ __split_buffer __v(__recommend(size() + 1), __p - __begin_, __alloc_);
__v.emplace_back(std::forward<_Args>(__args)...);
__p = __swap_out_circular_buffer(__v, __p);
}
@@ -1592,7 +1442,7 @@ vector<_Tp, _Allocator>::emplace(const_iterator __position, _Args&&... __args) {
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::iterator
vector<_Tp, _Allocator>::insert(const_iterator __position, size_type __n, const_reference __x) {
- pointer __p = __raw_begin() + (__position - begin());
+ pointer __p = __begin_ + (__position - begin());
if (__n > 0) {
if (__n <= __remaining_capacity()) {
size_type __old_n = __n;
@@ -1611,7 +1461,7 @@ vector<_Tp, _Allocator>::insert(const_iterator __position, size_type __n, const_
std::fill_n(__p, __n, *__xr);
}
} else {
- __split_buffer __v(__recommend(size() + __n), __p - __raw_begin(), __allocator_ref());
+ __split_buffer __v(__recommend(size() + __n), __p - __begin_, __alloc_);
__v.__construct_at_end(__n, __x);
__p = __swap_out_circular_buffer(__v, __p);
}
@@ -1624,7 +1474,7 @@ template <class _InputIterator, class _Sentinel>
_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 = __raw_begin() + __off;
+ pointer __p = __begin_ + __off;
pointer __old_last = __end_pointer();
for (; !__is_full() && __first != __last; ++__first)
__emplace_back_assume_capacity(*__first);
@@ -1632,15 +1482,15 @@ vector<_Tp, _Allocator>::__insert_with_sentinel(const_iterator __position, _Inpu
if (__first == __last)
(void)std::rotate(__p, __old_last, __end_pointer());
else {
- __split_buffer __v(__allocator_ref());
+ __split_buffer __v(__alloc_);
pointer __end = __end_pointer();
auto __guard = std::__make_exception_guard(
- _AllocatorDestroyRangeReverse<allocator_type, pointer>(__allocator_ref(), __old_last, __end));
+ _AllocatorDestroyRangeReverse<allocator_type, pointer>(__alloc_, __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
+ __recommend(size() + __v.size()), __off, __alloc_); // has `__off` positions available at the front
std::__uninitialized_allocator_relocate(
- __allocator_ref(),
+ __alloc_,
std::__to_address(__old_last),
std::__to_address(__end_pointer()),
std::__to_address(__merged.end()));
@@ -1649,7 +1499,7 @@ vector<_Tp, _Allocator>::__insert_with_sentinel(const_iterator __position, _Inpu
__merged.__set_sentinel(__merged.end() + (__end_pointer() - __old_last));
__set_sentinel(__old_last);
std::__uninitialized_allocator_relocate(
- __allocator_ref(),
+ __alloc_,
std::__to_address(__v.begin()),
std::__to_address(__v.end()),
std::__to_address(__merged.end()));
@@ -1665,7 +1515,7 @@ template <class _AlgPolicy, class _Iterator, class _Sentinel>
_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 = __raw_begin() + (__position - begin());
+ pointer __p = __begin_ + (__position - begin());
if (__n > 0) {
if (__n <= static_cast<difference_type>(__remaining_capacity())) {
pointer __end = __end_pointer();
@@ -1691,7 +1541,7 @@ vector<_Tp, _Allocator>::__insert_with_size(
__insert_assign_n_unchecked<_AlgPolicy>(std::move(__first), __n, __p);
}
} else {
- __split_buffer __v(__recommend(size() + __n), __p - __raw_begin(), __allocator_ref());
+ __split_buffer __v(__recommend(size() + __n), __p - __begin_, __alloc_);
__v.__construct_at_end_with_size(std::move(__first), __n);
__p = __swap_out_circular_buffer(__v, __p);
}
@@ -1706,12 +1556,12 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::resize(size_type __n
if (__new_size <= capacity()) {
__construct_at_end(__new_size - __current_size);
} else {
- __split_buffer __v(__recommend(__new_size), __current_size, __allocator_ref());
+ __split_buffer __v(__recommend(__new_size), __current_size, __alloc_);
__v.__construct_at_end(__new_size - __current_size);
__swap_out_circular_buffer(__v);
}
} else if (__current_size > __new_size) {
- this->__destruct_at_end(__raw_begin() + __new_size);
+ this->__destruct_at_end(__begin_ + __new_size);
}
}
@@ -1722,12 +1572,12 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::resize(size_type __n
if (__new_size <= capacity())
__construct_at_end(__new_size - __current_size, __x);
else {
- __split_buffer __v(__recommend(__new_size), __current_size, __allocator_ref());
+ __split_buffer __v(__recommend(__new_size), __current_size, __alloc_);
__v.__construct_at_end(__new_size - __current_size, __x);
__swap_out_circular_buffer(__v);
}
} else if (__current_size > __new_size) {
- this->__destruct_at_end(__raw_begin() + __new_size);
+ this->__destruct_at_end(__begin_ + __new_size);
}
}
>From f502629b7f53444056ef164cb057e2d321e1ea05 Mon Sep 17 00:00:00 2001
From: Christopher Di Bella <cjdb at google.com>
Date: Tue, 13 Jan 2026 22:48:54 +0000
Subject: [PATCH 03/14] further reduces the diff
0580dea significantly reduced the diff by returning the stable ABI code
to its original location. `__vector_base` did away with using `this->`
for most things, since it's largely redundant, but these were left out
in 0580dea. This commit adds most of those back.
---
libcxx/include/__vector/vector.h | 194 ++++++++++++++++---------------
1 file changed, 100 insertions(+), 94 deletions(-)
diff --git a/libcxx/include/__vector/vector.h b/libcxx/include/__vector/vector.h
index 29cd205aeb8da..28465a6b4c44d 100644
--- a/libcxx/include/__vector/vector.h
+++ b/libcxx/include/__vector/vector.h
@@ -334,17 +334,17 @@ class vector {
#endif
[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const _NOEXCEPT {
- return __alloc_;
+ return this->__alloc_;
}
//
// Iterators
//
[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT {
- return __make_iter(__add_alignment_assumption(__begin_));
+ return __make_iter(__add_alignment_assumption(this->__begin_));
}
[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT {
- return __make_iter(__add_alignment_assumption(__begin_));
+ return __make_iter(__add_alignment_assumption(this->__begin_));
}
[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT {
return __make_iter(__add_alignment_assumption(__end_pointer()));
@@ -398,18 +398,18 @@ class vector {
}
#else
[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT {
- return static_cast<size_type>(__end_ - __begin_);
+ return static_cast<size_type>(this->__end_ - this->__begin_);
}
[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type capacity() const _NOEXCEPT {
- return static_cast<size_type>(__cap_ - __begin_);
+ return static_cast<size_type>(this->__cap_ - this->__begin_);
}
[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool empty() const _NOEXCEPT {
- return __begin_ == __end_;
+ return this->__begin_ == this->__end_;
}
#endif // _LIBCPP_ABI_SIZE_BASED_VECTOR
[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT {
- return std::min<size_type>(__alloc_traits::max_size(__alloc_), numeric_limits<difference_type>::max());
+ return std::min<size_type>(__alloc_traits::max_size(this->__alloc_), numeric_limits<difference_type>::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;
@@ -419,31 +419,31 @@ 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 __begin_[__n];
+ return this->__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 __begin_[__n];
+ return this->__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 __begin_[__n];
+ return this->__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 __begin_[__n];
+ return this->__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 *__begin_;
+ return *this->__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 *__begin_;
+ return *this->__begin_;
}
#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
@@ -458,11 +458,11 @@ class vector {
#else
[[__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);
+ 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 *(__end_ - 1);
+ return *(this->__end_ - 1);
}
#endif // _LIBCPP_ABI_SIZE_BASED_VECTOR
@@ -470,11 +470,11 @@ class vector {
// [vector.data], data access
//
[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI value_type* data() _NOEXCEPT {
- return std::__to_address(__begin_);
+ return std::__to_address(this->__begin_);
}
[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const value_type* data() const _NOEXCEPT {
- return std::__to_address(__begin_);
+ return std::__to_address(this->__begin_);
}
//
@@ -499,7 +499,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(__alloc_, std::__to_address(__tx.__pos_), std::forward<_Args>(__args)...);
+ __alloc_traits::construct(this->__alloc_, std::__to_address(__tx.__pos_), std::forward<_Args>(__args)...);
++__tx.__pos_;
}
@@ -582,7 +582,7 @@ class vector {
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void clear() _NOEXCEPT {
size_type __old_size = size();
- __base_destruct_at_end(__begin_);
+ __base_destruct_at_end(this->__begin_);
__annotate_shrink(__old_size);
}
@@ -610,18 +610,10 @@ class vector {
std::__swap_allocator(__alloc_, __other.__alloc_);
}
+
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __invariants() const;
+
#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
-public:
- [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __invariants() const {
- if (__begin_ == nullptr) {
- if (__size_ != 0 || __cap_ != 0)
- return false;
- } else {
- if (__size_ > __cap_)
- return false;
- }
- return true;
- }
private:
using __sentinel_type _LIBCPP_NODEBUG = size_type;
using __split_buffer _LIBCPP_NODEBUG = __split_buffer<_Tp, _Allocator, __split_buffer_size_layout>;
@@ -671,21 +663,6 @@ class vector {
size_type __cap_ = 0;
[[no_unique_address]] allocator_type __alloc_;
#else
-public:
- [[__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:
using __split_buffer _LIBCPP_NODEBUG = __split_buffer<_Tp, _Allocator, __split_buffer_pointer_layout>;
using __sentinel_type _LIBCPP_NODEBUG = pointer;
@@ -753,7 +730,7 @@ class vector {
_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(__alloc_, __n);
+ auto __allocation = std::__allocate_at_least(this->__alloc_, __n);
__set_valid_range(__allocation.ptr, static_cast<size_type>(0));
__set_capacity(__allocation.count);
__annotate_new(0);
@@ -804,7 +781,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<value_type, _Allocator> __tmp(__alloc_, *__first);
+ __temp_value<value_type, _Allocator> __tmp(this->__alloc_, *__first);
*__position = std::move(__tmp.get());
}
}
@@ -842,7 +819,7 @@ class vector {
// a laxer approach.
return std::__make_bounded_iter(
std::__wrap_iter<pointer>(__p),
- std::__wrap_iter<pointer>(__begin_),
+ std::__wrap_iter<pointer>(this->__begin_),
std::__wrap_iter<pointer>(__raw_capacity()));
#else
return iterator(__p);
@@ -854,7 +831,7 @@ class vector {
// Bound the iterator according to the capacity, rather than the size.
return std::__make_bounded_iter(
std::__wrap_iter<const_pointer>(__p),
- std::__wrap_iter<const_pointer>(__begin_),
+ std::__wrap_iter<const_pointer>(this->__begin_),
std::__wrap_iter<const_pointer>(__raw_capacity()));
#else
return const_iterator(__p);
@@ -933,7 +910,7 @@ class vector {
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __base_destruct_at_end(pointer __new_last) _NOEXCEPT {
pointer __soon_to_be_end = __end_pointer();
while (__new_last != __soon_to_be_end)
- __alloc_traits::destroy(__alloc_, std::__to_address(--__soon_to_be_end));
+ __alloc_traits::destroy(this->__alloc_, std::__to_address(--__soon_to_be_end));
__set_sentinel(__new_last);
}
@@ -952,21 +929,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 (__alloc_ != __c.__alloc_) {
+ if (this->__alloc_ != __c.__alloc_) {
clear();
__annotate_delete();
- __alloc_traits::deallocate(__alloc_, __begin_, capacity());
+ __alloc_traits::deallocate(this->__alloc_, this->__begin_, capacity());
__set_valid_range(nullptr, static_cast<size_type>(0));
__set_capacity(static_cast<__sentinel_type>(0));
}
- __alloc_ = __c.__alloc_;
+ this->__alloc_ = __c.__alloc_;
}
_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<allocator_type>::value) {
- __alloc_ = std::move(__c.__alloc_);
+ this->__alloc_ = std::move(__c.__alloc_);
}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __move_assign_alloc(vector&, false_type) _NOEXCEPT {}
@@ -1032,7 +1009,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::__swap_out_circular_
__annotate_delete();
auto __new_begin = __v.begin() - size();
std::__uninitialized_allocator_relocate(
- __alloc_,
+ this->__alloc_,
std::__to_address(__begin_),
std::__to_address(__end_pointer()),
std::__to_address(__new_begin));
@@ -1059,7 +1036,7 @@ vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer& __v, pointer
// Relocate [__p, __end) first to avoid having a hole in [__begin_, __end)
// in case something in [__begin_, __p) throws.
std::__uninitialized_allocator_relocate(
- __alloc_, std::__to_address(__p), std::__to_address(__end), std::__to_address(__v.end()));
+ this->__alloc_, 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(
@@ -1067,7 +1044,7 @@ vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer& __v, pointer
auto __new_begin = __v.begin() - (__p - __begin_);
std::__uninitialized_allocator_relocate(
- __alloc_, std::__to_address(__begin_), std::__to_address(__p), std::__to_address(__new_begin));
+ this->__alloc_, std::__to_address(__begin_), std::__to_address(__p), std::__to_address(__new_begin));
__v.__set_valid_range(__new_begin, __v.size() + size());
__set_sentinel(static_cast<size_type>(0)); // All the objects have been destroyed by relocating them.
@@ -1079,10 +1056,10 @@ vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer& __v, pointer
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::__vdeallocate() _NOEXCEPT {
- if (__begin_ != nullptr) {
+ if (this->__begin_ != nullptr) {
clear();
__annotate_delete();
- __alloc_traits::deallocate(__alloc_, __begin_, capacity());
+ __alloc_traits::deallocate(this->__alloc_, this->__begin_, capacity());
__set_valid_range(nullptr, static_cast<size_type>(0));
__set_capacity(static_cast<size_type>(0));
}
@@ -1111,7 +1088,7 @@ _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(__alloc_, std::__to_address(__pos));
+ __alloc_traits::construct(this->__alloc_, std::__to_address(__pos));
}
}
@@ -1127,7 +1104,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(__alloc_, std::__to_address(__pos), __x);
+ __alloc_traits::construct(this->__alloc_, std::__to_address(__pos), __x);
}
}
@@ -1136,8 +1113,7 @@ 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(__alloc_, std::move(__first), std::move(__last), __tx.__pos_);
+ __tx.__pos_ = std::__uninitialized_allocator_copy(this->__alloc_, std::move(__first), std::move(__last), __tx.__pos_);
}
template <class _Tp, class _Allocator>
@@ -1172,7 +1148,7 @@ vector<_Tp, _Allocator>::vector(vector&& __x, const __type_identity_t<allocator_
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::__move_assign(vector& __c, false_type)
_NOEXCEPT_(__alloc_traits::is_always_equal::value) {
- if (__alloc_ != __c.__alloc_) {
+ if (this->__alloc_ != __c.__alloc_) {
typedef move_iterator<iterator> _Ip;
assign(_Ip(__c.begin()), _Ip(__c.end()));
} else
@@ -1224,10 +1200,10 @@ vector<_Tp, _Allocator>::__assign_with_size(_Iterator __first, _Sentinel __last,
if (__new_size <= capacity()) {
if (__new_size > size()) {
auto const __size = size();
- auto __mid = std::__copy_n<_AlgPolicy>(std::move(__first), __size, __begin_).first;
+ auto __mid = std::__copy_n<_AlgPolicy>(std::move(__first), __size, this->__begin_).first;
__construct_at_end(std::move(__mid), std::move(__last), __new_size - __size);
} else {
- pointer __m = std::__copy(std::move(__first), __last, __begin_).second;
+ pointer __m = std::__copy(std::move(__first), __last, this->__begin_).second;
this->__destruct_at_end(__m);
}
} else {
@@ -1241,11 +1217,11 @@ template <class _Tp, class _Allocator>
_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(__begin_, std::min(__n, __s), __u);
+ std::fill_n(this->__begin_, std::min(__n, __s), __u);
if (__n > __s)
__construct_at_end(__n - __s, __u);
else
- this->__destruct_at_end(__begin_ + __n);
+ this->__destruct_at_end(this->__begin_ + __n);
} else {
__vdeallocate();
__vallocate(__recommend(static_cast<size_type>(__n)));
@@ -1258,7 +1234,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(), __alloc_);
+ __split_buffer __v(__n, size(), this->__alloc_);
__swap_out_circular_buffer(__v);
}
}
@@ -1269,7 +1245,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(), __alloc_);
+ __split_buffer __v(size(), size(), this->__alloc_);
// 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.
@@ -1286,10 +1262,10 @@ template <class _Tp, class _Allocator>
template <class... _Args>
_LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::__sentinel_type
vector<_Tp, _Allocator>::__emplace_back_slow_path(_Args&&... __args) {
- __split_buffer __v(__recommend(size() + 1), size(), __alloc_);
+ __split_buffer __v(__recommend(size() + 1), size(), this->__alloc_);
// __v.emplace_back(std::forward<_Args>(__args)...);
pointer __end = __v.end();
- __alloc_traits::construct(__alloc_, std::__to_address(__end), std::forward<_Args>(__args)...);
+ __alloc_traits::construct(this->__alloc_, std::__to_address(__end), std::forward<_Args>(__args)...);
__v.__set_sentinel(++__end);
__swap_out_circular_buffer(__v);
return __raw_sentinel();
@@ -1343,7 +1319,7 @@ 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 = __begin_ + __ps;
+ pointer __p = this->__begin_ + __ps;
this->__destruct_at_end(std::move(__p + 1, __end_pointer(), __p));
return __make_iter(__p);
}
@@ -1352,7 +1328,7 @@ template <class _Tp, class _Allocator>
_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 = __begin_ + (__first - begin());
+ pointer __p = this->__begin_ + (__first - begin());
if (__first != __last) {
this->__destruct_at_end(std::move(__p + (__last - __first), __end_pointer(), __p));
}
@@ -1368,7 +1344,7 @@ vector<_Tp, _Allocator>::__move_range(pointer __from_s, pointer __from_e, pointe
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(__alloc_, std::__to_address(__pos), std::move(*__i));
+ __alloc_traits::construct(this->__alloc_, std::__to_address(__pos), std::move(*__i));
}
}
std::move_backward(__from_s, __from_s + __n, __old_last);
@@ -1377,7 +1353,7 @@ vector<_Tp, _Allocator>::__move_range(pointer __from_s, pointer __from_e, pointe
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::iterator
vector<_Tp, _Allocator>::insert(const_iterator __position, const_reference __x) {
- pointer __p = __begin_ + (__position - begin());
+ pointer __p = this->__begin_ + (__position - begin());
if (!__is_full()) {
pointer __end = __end_pointer();
if (__p == __end) {
@@ -1390,7 +1366,7 @@ vector<_Tp, _Allocator>::insert(const_iterator __position, const_reference __x)
*__p = *__xr;
}
} else {
- __split_buffer __v(__recommend(size() + 1), __p - __begin_, __alloc_);
+ __split_buffer __v(__recommend(size() + 1), __p - this->__begin_, this->__alloc_);
__v.emplace_back(__x);
__p = __swap_out_circular_buffer(__v, __p);
}
@@ -1400,7 +1376,7 @@ vector<_Tp, _Allocator>::insert(const_iterator __position, const_reference __x)
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::iterator
vector<_Tp, _Allocator>::insert(const_iterator __position, value_type&& __x) {
- pointer __p = __begin_ + (__position - begin());
+ pointer __p = this->__begin_ + (__position - begin());
if (!__is_full()) {
pointer __end = __end_pointer();
if (__p == __end) {
@@ -1410,7 +1386,7 @@ vector<_Tp, _Allocator>::insert(const_iterator __position, value_type&& __x) {
*__p = std::move(__x);
}
} else {
- __split_buffer __v(__recommend(size() + 1), __p - __begin_, __alloc_);
+ __split_buffer __v(__recommend(size() + 1), __p - this->__begin_, this->__alloc_);
__v.emplace_back(std::move(__x));
__p = __swap_out_circular_buffer(__v, __p);
}
@@ -1421,18 +1397,18 @@ template <class _Tp, class _Allocator>
template <class... _Args>
_LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::iterator
vector<_Tp, _Allocator>::emplace(const_iterator __position, _Args&&... __args) {
- pointer __p = __begin_ + (__position - begin());
+ pointer __p = this->__begin_ + (__position - begin());
if (!__is_full()) {
pointer __end = __end_pointer();
if (__p == __end) {
__emplace_back_assume_capacity(std::forward<_Args>(__args)...);
} else {
- __temp_value<value_type, _Allocator> __tmp(__alloc_, std::forward<_Args>(__args)...);
+ __temp_value<value_type, _Allocator> __tmp(this->__alloc_, std::forward<_Args>(__args)...);
__move_range(__p, __end, __p + 1);
*__p = std::move(__tmp.get());
}
} else {
- __split_buffer __v(__recommend(size() + 1), __p - __begin_, __alloc_);
+ __split_buffer __v(__recommend(size() + 1), __p - this->__begin_, this->__alloc_);
__v.emplace_back(std::forward<_Args>(__args)...);
__p = __swap_out_circular_buffer(__v, __p);
}
@@ -1442,7 +1418,7 @@ vector<_Tp, _Allocator>::emplace(const_iterator __position, _Args&&... __args) {
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::iterator
vector<_Tp, _Allocator>::insert(const_iterator __position, size_type __n, const_reference __x) {
- pointer __p = __begin_ + (__position - begin());
+ pointer __p = this->__begin_ + (__position - begin());
if (__n > 0) {
if (__n <= __remaining_capacity()) {
size_type __old_n = __n;
@@ -1461,7 +1437,7 @@ vector<_Tp, _Allocator>::insert(const_iterator __position, size_type __n, const_
std::fill_n(__p, __n, *__xr);
}
} else {
- __split_buffer __v(__recommend(size() + __n), __p - __begin_, __alloc_);
+ __split_buffer __v(__recommend(size() + __n), __p - this->__begin_, this->__alloc_);
__v.__construct_at_end(__n, __x);
__p = __swap_out_circular_buffer(__v, __p);
}
@@ -1474,7 +1450,7 @@ template <class _InputIterator, class _Sentinel>
_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 = __begin_ + __off;
+ pointer __p = this->__begin_ + __off;
pointer __old_last = __end_pointer();
for (; !__is_full() && __first != __last; ++__first)
__emplace_back_assume_capacity(*__first);
@@ -1515,7 +1491,7 @@ template <class _AlgPolicy, class _Iterator, class _Sentinel>
_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 = __begin_ + (__position - begin());
+ pointer __p = this->__begin_ + (__position - begin());
if (__n > 0) {
if (__n <= static_cast<difference_type>(__remaining_capacity())) {
pointer __end = __end_pointer();
@@ -1541,7 +1517,7 @@ vector<_Tp, _Allocator>::__insert_with_size(
__insert_assign_n_unchecked<_AlgPolicy>(std::move(__first), __n, __p);
}
} else {
- __split_buffer __v(__recommend(size() + __n), __p - __begin_, __alloc_);
+ __split_buffer __v(__recommend(size() + __n), __p - this->__begin_, this->__alloc_);
__v.__construct_at_end_with_size(std::move(__first), __n);
__p = __swap_out_circular_buffer(__v, __p);
}
@@ -1556,12 +1532,12 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::resize(size_type __n
if (__new_size <= capacity()) {
__construct_at_end(__new_size - __current_size);
} else {
- __split_buffer __v(__recommend(__new_size), __current_size, __alloc_);
+ __split_buffer __v(__recommend(__new_size), __current_size, this->__alloc_);
__v.__construct_at_end(__new_size - __current_size);
__swap_out_circular_buffer(__v);
}
} else if (__current_size > __new_size) {
- this->__destruct_at_end(__begin_ + __new_size);
+ this->__destruct_at_end(this->__begin_ + __new_size);
}
}
@@ -1577,16 +1553,46 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::resize(size_type __n
__swap_out_circular_buffer(__v);
}
} else if (__current_size > __new_size) {
- this->__destruct_at_end(__begin_ + __new_size);
+ this->__destruct_at_end(this->__begin_ + __new_size);
+ }
+}
+
+#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+template<class _Tp, class _Allocator>
+[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool vector<_Tp, _Allocator>::__invariants() const {
+ if (__begin_ == nullptr) {
+ if (__size_ != 0 || __cap_ != 0)
+ return false;
+ } else {
+ if (__size_ > __cap_)
+ return false;
}
+ return true;
}
+#else
+template<class _Tp, class _Allocator>
+[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool vector<_Tp, _Allocator>::__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;
+}
+#endif // _LIBCPP_ABI_SIZE_BASED_VECTOR
#if _LIBCPP_STD_VER >= 20
-template <class _Allocator>
-inline constexpr bool __format::__enable_insertable<vector<char, _Allocator>> = true;
+template <>
+inline constexpr bool __format::__enable_insertable<vector<char>> = true;
# if _LIBCPP_HAS_WIDE_CHARACTERS
-template <class _Allocator>
-inline constexpr bool __format::__enable_insertable<vector<wchar_t, _Allocator>> = true;
+template <>
+inline constexpr bool __format::__enable_insertable<vector<wchar_t>> = true;
# endif
#endif // _LIBCPP_STD_VER >= 20
>From 935405c3d732684229ed15ba4721d0fcb4fde9cb Mon Sep 17 00:00:00 2001
From: Christopher Di Bella <cjdb at google.com>
Date: Tue, 13 Jan 2026 23:25:20 +0000
Subject: [PATCH 04/14] fixes breaks from generic-cxx20
---
libcxx/include/__vector/vector.h | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/libcxx/include/__vector/vector.h b/libcxx/include/__vector/vector.h
index 28465a6b4c44d..ea56b3ecc65b3 100644
--- a/libcxx/include/__vector/vector.h
+++ b/libcxx/include/__vector/vector.h
@@ -676,7 +676,7 @@ class vector {
}
[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __remaining_capacity() const _NOEXCEPT {
- return __end_;
+ return __cap_ - __end_;
}
[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __is_full() const _NOEXCEPT {
@@ -695,16 +695,12 @@ class vector {
_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 __pos) _NOEXCEPT {
+ _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;
- }
-
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_capacity(size_type __offset) _NOEXCEPT {
__cap_ = __begin_ + __offset;
}
>From 970d4588c0e261f762b47258b6bc620b8825fdaf Mon Sep 17 00:00:00 2001
From: Christopher Di Bella <cjdb at google.com>
Date: Wed, 14 Jan 2026 01:38:47 +0000
Subject: [PATCH 05/14] further reduces diff
---
libcxx/include/__split_buffer | 3 +-
libcxx/include/__vector/vector.h | 187 ++++++++++++++++---------------
2 files changed, 99 insertions(+), 91 deletions(-)
diff --git a/libcxx/include/__split_buffer b/libcxx/include/__split_buffer
index 1b1492dadaddc..da26a6e74935a 100644
--- a/libcxx/include/__split_buffer
+++ b/libcxx/include/__split_buffer
@@ -310,7 +310,8 @@ public:
return __begin_[__size_ - 1];
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __swap_without_allocator(__split_buffer_size_layout& __other) _NOEXCEPT {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
+ __swap_without_allocator(__split_buffer_size_layout& __other) _NOEXCEPT {
std::swap(__front_cap_, __other.__front_cap_);
std::swap(__begin_, __other.__begin_);
std::swap(__cap_, __other.__cap_);
diff --git a/libcxx/include/__vector/vector.h b/libcxx/include/__vector/vector.h
index ea56b3ecc65b3..2ffa67453adc9 100644
--- a/libcxx/include/__vector/vector.h
+++ b/libcxx/include/__vector/vector.h
@@ -87,6 +87,9 @@ _LIBCPP_BEGIN_NAMESPACE_STD
template <class _Tp, class _Allocator /* = allocator<_Tp> */>
class vector {
public:
+ ///
+ /// Types
+ ///
using value_type = _Tp;
using allocator_type = _Allocator;
using __alloc_traits _LIBCPP_NODEBUG = allocator_traits<allocator_type>;
@@ -589,97 +592,87 @@ class vector {
_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& __other)
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void swap(vector&)
#if _LIBCPP_STD_VER >= 14
- _NOEXCEPT
+ _NOEXCEPT;
#else
- _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>);
#endif
- {
- _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(
- __alloc_traits::propagate_on_container_swap::value || __alloc_ == __other.__alloc_,
- "vector::swap: Either propagate_on_container_swap must be true"
- " or the allocators must compare equal");
- std::swap(__begin_, __other.__begin_);
-#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
- std::swap(__size_, __other.__size_);
-#else
- std::swap(__end_, __other.__end_);
-#endif
- std::swap(__cap_, __other.__cap_);
- std::__swap_allocator(__alloc_, __other.__alloc_);
- }
-
- [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __invariants() const;
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __invariants() const;
#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+
private:
- using __sentinel_type _LIBCPP_NODEBUG = size_type;
- using __split_buffer _LIBCPP_NODEBUG = __split_buffer<_Tp, _Allocator, __split_buffer_size_layout>;
+ using __sentinel_type _LIBCPP_NODEBUG = size_type;
+ using __split_buffer _LIBCPP_NODEBUG = __split_buffer<_Tp, _Allocator, __split_buffer_size_layout>;
- [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __raw_sentinel() const _NOEXCEPT {
+ [[__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 pointer __end_pointer() const _NOEXCEPT {
- return __begin_ + __size_;
- }
+ [[__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 size_type
+ __remaining_capacity() const _NOEXCEPT {
+ return __cap_ - __size_;
+ }
- [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __is_full() const _NOEXCEPT {
+ [[__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 {
+ _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;
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_sentinel(size_type __size) _NOEXCEPT {
+ _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 {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_sentinel(pointer __pos) _NOEXCEPT {
__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(pointer __pos) _NOEXCEPT {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_capacity(pointer __pos) _NOEXCEPT {
__cap_ = static_cast<size_type>(__pos - __begin_);
- }
+ }
- pointer __begin_ = nullptr;
- size_type __size_ = 0;
- size_type __cap_ = 0;
- [[no_unique_address]] allocator_type __alloc_;
+ pointer __begin_ = nullptr;
+ size_type __size_ = 0;
+ size_type __cap_ = 0;
+ [[no_unique_address]] allocator_type __alloc_;
#else
+
private:
- using __split_buffer _LIBCPP_NODEBUG = __split_buffer<_Tp, _Allocator, __split_buffer_pointer_layout>;
- using __sentinel_type _LIBCPP_NODEBUG = pointer;
+ using __split_buffer _LIBCPP_NODEBUG = __split_buffer<_Tp, _Allocator, __split_buffer_pointer_layout>;
+ using __sentinel_type _LIBCPP_NODEBUG = pointer;
- [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer __raw_sentinel() const _NOEXCEPT {
+ [[__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 __end_pointer() const _NOEXCEPT {
- return __end_;
- }
+ [[__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 size_type
+ __remaining_capacity() const _NOEXCEPT {
+ return __cap_ - __end_;
+ }
- [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __is_full() const _NOEXCEPT {
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __is_full() const _NOEXCEPT {
return __end_ == __cap_;
}
@@ -688,29 +681,31 @@ class vector {
__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;
}
- _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 {
+ _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 {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_capacity(size_type __offset) _NOEXCEPT {
__cap_ = __begin_ + __offset;
}
- pointer __begin_ = nullptr;
- pointer __end_ = nullptr;
- _LIBCPP_COMPRESSED_PAIR(pointer, __cap_ = nullptr, allocator_type, __alloc_);
+ pointer __begin_ = nullptr;
+ pointer __end_ = nullptr;
+ _LIBCPP_COMPRESSED_PAIR(pointer, __cap_ = nullptr, allocator_type, __alloc_);
#endif // _LIBCPP_ABI_SIZE_BASED_VECTOR
- [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __sentinel_type __raw_capacity() const _NOEXCEPT {
+ [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20
+ _LIBCPP_HIDE_FROM_ABI __sentinel_type __raw_capacity() const _NOEXCEPT {
return __cap_;
}
@@ -834,8 +829,7 @@ class vector {
#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
@@ -851,7 +845,8 @@ class vector {
}
template <class... _Args>
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __sentinel_type __emplace_back_slow_path(_Args&&... __args);
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI inline __sentinel_type
+ __emplace_back_slow_path(_Args&&... __args);
// The following functions are no-ops outside of AddressSanitizer mode.
// We call annotations for every allocator, unless explicitly disabled.
@@ -1005,13 +1000,9 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::__swap_out_circular_
__annotate_delete();
auto __new_begin = __v.begin() - size();
std::__uninitialized_allocator_relocate(
- this->__alloc_,
- std::__to_address(__begin_),
- std::__to_address(__end_pointer()),
- std::__to_address(__new_begin));
+ this->__alloc_, std::__to_address(__begin_), std::__to_address(__end_pointer()), std::__to_address(__new_begin));
__v.__set_valid_range(__new_begin, __v.end());
__set_sentinel(static_cast<size_type>(0)); // All the objects have been destroyed by relocating them.
- // __v.__size_ += __size_;
__swap_layouts(__v);
__v.__set_data(__v.begin());
@@ -1194,8 +1185,8 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
vector<_Tp, _Allocator>::__assign_with_size(_Iterator __first, _Sentinel __last, difference_type __n) {
size_type __new_size = static_cast<size_type>(__n);
if (__new_size <= capacity()) {
- if (__new_size > size()) {
- auto const __size = size();
+ auto const __size = size();
+ if (__new_size > __size) {
auto __mid = std::__copy_n<_AlgPolicy>(std::move(__first), __size, this->__begin_).first;
__construct_at_end(std::move(__mid), std::move(__last), __new_size - __size);
} else {
@@ -1462,19 +1453,13 @@ vector<_Tp, _Allocator>::__insert_with_sentinel(const_iterator __position, _Inpu
__split_buffer __merged(
__recommend(size() + __v.size()), __off, __alloc_); // has `__off` positions available at the front
std::__uninitialized_allocator_relocate(
- __alloc_,
- std::__to_address(__old_last),
- std::__to_address(__end_pointer()),
- std::__to_address(__merged.end()));
+ __alloc_, 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()));
+ __alloc_, 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);
@@ -1528,7 +1513,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::resize(size_type __n
if (__new_size <= capacity()) {
__construct_at_end(__new_size - __current_size);
} else {
- __split_buffer __v(__recommend(__new_size), __current_size, this->__alloc_);
+ __split_buffer __v(__recommend(__new_size), __current_size, __alloc_);
__v.__construct_at_end(__new_size - __current_size);
__swap_out_circular_buffer(__v);
}
@@ -1553,9 +1538,31 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::resize(size_type __n
}
}
+template <class _Tp, class _Allocator>
+_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<allocator_type>)
+#endif
+{
+ _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(this->__begin_, __x.__begin_);
#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
-template<class _Tp, class _Allocator>
-[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool vector<_Tp, _Allocator>::__invariants() const {
+ std::swap(this->__size_, __x.__size_);
+#else
+ std::swap(this->__end_, __x.__end_);
+#endif
+ std::swap(this->__cap_, __x.__cap_);
+ std::__swap_allocator(this->__alloc_, __x.__alloc_);
+}
+
+#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+template <class _Tp, class _Allocator>
+_LIBCPP_CONSTEXPR_SINCE_CXX20 bool vector<_Tp, _Allocator>::__invariants() const {
if (__begin_ == nullptr) {
if (__size_ != 0 || __cap_ != 0)
return false;
@@ -1566,17 +1573,17 @@ template<class _Tp, class _Allocator>
return true;
}
#else
-template<class _Tp, class _Allocator>
-[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool vector<_Tp, _Allocator>::__invariants() const {
- if (__begin_ == nullptr) {
- if (__end_ != nullptr || __cap_ != nullptr)
+template <class _Tp, class _Allocator>
+_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 (__begin_ > __end_)
+ if (this->__begin_ > this->__end_)
return false;
- if (__begin_ == __cap_)
+ if (this->__begin_ == this->__cap_)
return false;
- if (__end_ > __cap_)
+ if (this->__end_ > this->__cap_)
return false;
}
return true;
>From c87e88382d31e74a946bbc3f58c213dae1324d15 Mon Sep 17 00:00:00 2001
From: Christopher Di Bella <cjdb at google.com>
Date: Wed, 14 Jan 2026 02:35:00 +0000
Subject: [PATCH 06/14] gets GDB pretty-printer working
---
libcxx/utils/gdb/libcxx/printers.py | 32 ++++++++++++++---------------
1 file changed, 16 insertions(+), 16 deletions(-)
diff --git a/libcxx/utils/gdb/libcxx/printers.py b/libcxx/utils/gdb/libcxx/printers.py
index 1bfdd718e36bc..83df6be78a1bb 100644
--- a/libcxx/utils/gdb/libcxx/printers.py
+++ b/libcxx/utils/gdb/libcxx/printers.py
@@ -13,7 +13,6 @@
from __future__ import print_function
import re
-import sys
import gdb
import gdb.printing
@@ -352,28 +351,29 @@ def __init__(self, val):
"""Set val, length, capacity, and iterator for bool and normal vectors."""
self.val = val
self.typename = _remove_generics(_prettify_typename(val.type))
+ begin = self.val["__begin_"]
if self.val.type.template_argument(0).code == gdb.TYPE_CODE_BOOL:
- begin = self.val["__begin_"]
self.typename += "<bool>"
self.length = self.val["__size_"]
bits_per_word = self.val["__bits_per_word"]
self.capacity = self.val["__cap_"] * bits_per_word
self.iterator = self._VectorBoolIterator(begin, self.length, bits_per_word)
else:
- for i in val.type.fields():
- if i.is_base_class:
- base = val[i]
- break
-
- begin = base["__begin_"]
- end = base["__end_"]
- self.length = end - begin
- for i in base.type.fields():
- if i.name == "__cap_":
- self.capacity = base["__cap_"] - begin
- elif i.name == None:
- self.capacity = base[i]["__cap_"] - begin
- break
+ cap = self.val["__cap_"]
+
+ # We test for integers because `vector<T>::size_type` is required to
+ # be an unsigned integer, whereas `vector<T>::pointer` can be any
+ # type that satisfies the Cpp17NullablePointer requirements.
+ if cap.type.strip_typedefs().code == gdb.TYPE_CODE_INT:
+ size = self.val["__size_"]
+ self.length = size
+ self.capacity = cap
+ end = begin + size
+ else:
+ end = self.val["__end_"]
+ self.length = end - begin
+ self.capacity = cap - begin
+
self.iterator = self._VectorIterator(begin, end)
def to_string(self):
>From 44adc2d0c03ea421871d7a9b2aaa178ad828b1b7 Mon Sep 17 00:00:00 2001
From: Christopher Di Bella <cjdb at google.com>
Date: Thu, 15 Jan 2026 01:10:06 +0000
Subject: [PATCH 07/14] ensures that generic-cxx23 passes
---
libcxx/include/__vector/vector.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/libcxx/include/__vector/vector.h b/libcxx/include/__vector/vector.h
index 2ffa67453adc9..46635045bc704 100644
--- a/libcxx/include/__vector/vector.h
+++ b/libcxx/include/__vector/vector.h
@@ -510,8 +510,8 @@ class vector {
template <_ContainerCompatibleRange<_Tp> _Range>
_LIBCPP_HIDE_FROM_ABI constexpr void append_range(_Range&& __range) {
if constexpr (ranges::forward_range<_Range> || ranges::sized_range<_Range>) {
- auto __len = static_cast<size_type>(ranges::distance(__range));
- if (__len < __raw_capacity() - __raw_sentinel()) {
+ auto __len = ranges::distance(__range);
+ if (__len < static_cast<difference_type>(__raw_capacity() - __raw_sentinel())) {
__construct_at_end(ranges::begin(__range), ranges::end(__range), __len);
} else {
__split_buffer __buffer(__recommend(size() + __len), size(), __alloc_);
>From fe98721a13c700986159e12a90a20134daf671b9 Mon Sep 17 00:00:00 2001
From: Christopher Di Bella <cjdb at google.com>
Date: Thu, 15 Jan 2026 02:23:38 +0000
Subject: [PATCH 08/14] attempts to fix GCC issue
---
libcxx/include/__vector/vector.h | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/libcxx/include/__vector/vector.h b/libcxx/include/__vector/vector.h
index 46635045bc704..18004abbd1899 100644
--- a/libcxx/include/__vector/vector.h
+++ b/libcxx/include/__vector/vector.h
@@ -86,6 +86,11 @@ _LIBCPP_BEGIN_NAMESPACE_STD
template <class _Tp, class _Allocator /* = allocator<_Tp> */>
class vector {
+#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+ using __split_buffer _LIBCPP_NODEBUG = __split_buffer<_Tp, _Allocator, __split_buffer_size_layout>;
+#else
+ using __split_buffer _LIBCPP_NODEBUG = __split_buffer<_Tp, _Allocator, __split_buffer_pointer_layout>;
+#endif
public:
///
/// Types
@@ -605,7 +610,6 @@ class vector {
private:
using __sentinel_type _LIBCPP_NODEBUG = size_type;
- using __split_buffer _LIBCPP_NODEBUG = __split_buffer<_Tp, _Allocator, __split_buffer_size_layout>;
[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __raw_sentinel() const _NOEXCEPT {
return __size_;
@@ -656,7 +660,6 @@ class vector {
#else
private:
- using __split_buffer _LIBCPP_NODEBUG = __split_buffer<_Tp, _Allocator, __split_buffer_pointer_layout>;
using __sentinel_type _LIBCPP_NODEBUG = pointer;
[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer __raw_sentinel() const _NOEXCEPT {
>From 81b360bf70d0dddb5e416159e43262f8f9c1655f Mon Sep 17 00:00:00 2001
From: Christopher Di Bella <cjdb at google.com>
Date: Fri, 16 Jan 2026 01:42:32 +0000
Subject: [PATCH 09/14] replaces alias to comply with GCC's -Wchanges-meaning
---
libcxx/include/__vector/vector.h | 52 ++++++++++++++++++++------------
1 file changed, 32 insertions(+), 20 deletions(-)
diff --git a/libcxx/include/__vector/vector.h b/libcxx/include/__vector/vector.h
index 18004abbd1899..309fa0502752a 100644
--- a/libcxx/include/__vector/vector.h
+++ b/libcxx/include/__vector/vector.h
@@ -87,10 +87,13 @@ _LIBCPP_BEGIN_NAMESPACE_STD
template <class _Tp, class _Allocator /* = allocator<_Tp> */>
class vector {
#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
- using __split_buffer _LIBCPP_NODEBUG = __split_buffer<_Tp, _Allocator, __split_buffer_size_layout>;
+ template <class _SplitBuffer, class _Tp2, class _Allocator2>
+ using __split_buffer_layout _LIBCPP_NODEBUG = __split_buffer_size_layout<_SplitBuffer, _Tp2, _Allocator2>;
#else
- using __split_buffer _LIBCPP_NODEBUG = __split_buffer<_Tp, _Allocator, __split_buffer_pointer_layout>;
+ template <class _SplitBuffer, class _Tp2, class _Allocator2>
+ using __split_buffer_layout _LIBCPP_NODEBUG = __split_buffer_pointer_layout<_SplitBuffer, _Tp2, _Allocator2>;
#endif
+
public:
///
/// Types
@@ -519,7 +522,7 @@ class vector {
if (__len < static_cast<difference_type>(__raw_capacity() - __raw_sentinel())) {
__construct_at_end(ranges::begin(__range), ranges::end(__range), __len);
} else {
- __split_buffer __buffer(__recommend(size() + __len), size(), __alloc_);
+ __split_buffer<_Tp, _Allocator, __split_buffer_layout> __buffer(__recommend(size() + __len), size(), __alloc_);
__buffer.__construct_at_end_with_size(ranges::begin(__range), __len);
__swap_out_circular_buffer(__buffer);
}
@@ -832,9 +835,10 @@ class vector {
#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<_Tp, _Allocator, __split_buffer_layout>& __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<_Tp, _Allocator, __split_buffer_layout>& __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)
@@ -957,7 +961,8 @@ class vector {
return __p;
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __swap_layouts(__split_buffer& __sb) {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
+ __swap_layouts(__split_buffer<_Tp, _Allocator, __split_buffer_layout>& __sb) {
auto __vector_begin = __begin_;
auto __vector_sentinel = __raw_sentinel();
auto __vector_cap = __raw_capacity();
@@ -999,7 +1004,8 @@ vector(from_range_t, _Range&&, _Alloc = _Alloc()) -> vector<ranges::range_value_
// 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<_Tp, _Allocator, __split_buffer_layout>& __v) {
__annotate_delete();
auto __new_begin = __v.begin() - size();
std::__uninitialized_allocator_relocate(
@@ -1018,7 +1024,8 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::__swap_out_circular_
// function has a strong exception guarantee if __begin_ == __p || size() == __p.
template <class _Tp, class _Allocator>
_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<_Tp, _Allocator, __split_buffer_layout>& __v,
+ pointer __p) {
__annotate_delete();
pointer __ret = __v.begin();
@@ -1224,7 +1231,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<_Tp, _Allocator, __split_buffer_layout> __v(__n, size(), this->__alloc_);
__swap_out_circular_buffer(__v);
}
}
@@ -1235,7 +1242,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<_Tp, _Allocator, __split_buffer_layout> __v(size(), size(), this->__alloc_);
// 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.
@@ -1252,7 +1259,7 @@ template <class _Tp, class _Allocator>
template <class... _Args>
_LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::__sentinel_type
vector<_Tp, _Allocator>::__emplace_back_slow_path(_Args&&... __args) {
- __split_buffer __v(__recommend(size() + 1), size(), this->__alloc_);
+ __split_buffer<_Tp, _Allocator, __split_buffer_layout> __v(__recommend(size() + 1), size(), this->__alloc_);
// __v.emplace_back(std::forward<_Args>(__args)...);
pointer __end = __v.end();
__alloc_traits::construct(this->__alloc_, std::__to_address(__end), std::forward<_Args>(__args)...);
@@ -1356,7 +1363,8 @@ vector<_Tp, _Allocator>::insert(const_iterator __position, const_reference __x)
*__p = *__xr;
}
} else {
- __split_buffer __v(__recommend(size() + 1), __p - this->__begin_, this->__alloc_);
+ __split_buffer<_Tp, _Allocator, __split_buffer_layout> __v(
+ __recommend(size() + 1), __p - this->__begin_, this->__alloc_);
__v.emplace_back(__x);
__p = __swap_out_circular_buffer(__v, __p);
}
@@ -1376,7 +1384,8 @@ vector<_Tp, _Allocator>::insert(const_iterator __position, value_type&& __x) {
*__p = std::move(__x);
}
} else {
- __split_buffer __v(__recommend(size() + 1), __p - this->__begin_, this->__alloc_);
+ __split_buffer<_Tp, _Allocator, __split_buffer_layout> __v(
+ __recommend(size() + 1), __p - this->__begin_, this->__alloc_);
__v.emplace_back(std::move(__x));
__p = __swap_out_circular_buffer(__v, __p);
}
@@ -1398,7 +1407,8 @@ vector<_Tp, _Allocator>::emplace(const_iterator __position, _Args&&... __args) {
*__p = std::move(__tmp.get());
}
} else {
- __split_buffer __v(__recommend(size() + 1), __p - this->__begin_, this->__alloc_);
+ __split_buffer<_Tp, _Allocator, __split_buffer_layout> __v(
+ __recommend(size() + 1), __p - this->__begin_, this->__alloc_);
__v.emplace_back(std::forward<_Args>(__args)...);
__p = __swap_out_circular_buffer(__v, __p);
}
@@ -1427,7 +1437,8 @@ vector<_Tp, _Allocator>::insert(const_iterator __position, size_type __n, const_
std::fill_n(__p, __n, *__xr);
}
} else {
- __split_buffer __v(__recommend(size() + __n), __p - this->__begin_, this->__alloc_);
+ __split_buffer<_Tp, _Allocator, __split_buffer_layout> __v(
+ __recommend(size() + __n), __p - this->__begin_, this->__alloc_);
__v.__construct_at_end(__n, __x);
__p = __swap_out_circular_buffer(__v, __p);
}
@@ -1448,12 +1459,12 @@ vector<_Tp, _Allocator>::__insert_with_sentinel(const_iterator __position, _Inpu
if (__first == __last)
(void)std::rotate(__p, __old_last, __end_pointer());
else {
- __split_buffer __v(__alloc_);
+ __split_buffer<_Tp, _Allocator, __split_buffer_layout> __v(__alloc_);
pointer __end = __end_pointer();
auto __guard = std::__make_exception_guard(
_AllocatorDestroyRangeReverse<allocator_type, pointer>(__alloc_, __old_last, __end));
__v.__construct_at_end_with_sentinel(std::move(__first), std::move(__last));
- __split_buffer __merged(
+ __split_buffer<_Tp, _Allocator, __split_buffer_layout> __merged(
__recommend(size() + __v.size()), __off, __alloc_); // has `__off` positions available at the front
std::__uninitialized_allocator_relocate(
__alloc_, std::__to_address(__old_last), std::__to_address(__end_pointer()), std::__to_address(__merged.end()));
@@ -1501,7 +1512,8 @@ vector<_Tp, _Allocator>::__insert_with_size(
__insert_assign_n_unchecked<_AlgPolicy>(std::move(__first), __n, __p);
}
} else {
- __split_buffer __v(__recommend(size() + __n), __p - this->__begin_, this->__alloc_);
+ __split_buffer<_Tp, _Allocator, __split_buffer_layout> __v(
+ __recommend(size() + __n), __p - this->__begin_, this->__alloc_);
__v.__construct_at_end_with_size(std::move(__first), __n);
__p = __swap_out_circular_buffer(__v, __p);
}
@@ -1516,7 +1528,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::resize(size_type __n
if (__new_size <= capacity()) {
__construct_at_end(__new_size - __current_size);
} else {
- __split_buffer __v(__recommend(__new_size), __current_size, __alloc_);
+ __split_buffer<_Tp, _Allocator, __split_buffer_layout> __v(__recommend(__new_size), __current_size, __alloc_);
__v.__construct_at_end(__new_size - __current_size);
__swap_out_circular_buffer(__v);
}
@@ -1532,7 +1544,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::resize(size_type __n
if (__new_size <= capacity())
__construct_at_end(__new_size - __current_size, __x);
else {
- __split_buffer __v(__recommend(__new_size), __current_size, __alloc_);
+ __split_buffer<_Tp, _Allocator, __split_buffer_layout> __v(__recommend(__new_size), __current_size, __alloc_);
__v.__construct_at_end(__new_size - __current_size, __x);
__swap_out_circular_buffer(__v);
}
>From ff25eb8f2210893f4699e564634e576cb068575f Mon Sep 17 00:00:00 2001
From: Christopher Di Bella <cjdb at google.com>
Date: Tue, 20 Jan 2026 21:36:48 +0000
Subject: [PATCH 10/14] Revert "replaces alias to comply with GCC's
-Wchanges-meaning"
This reverts commit 81b360bf70d0dddb5e416159e43262f8f9c1655f.
---
libcxx/include/__vector/vector.h | 1 -
1 file changed, 1 deletion(-)
diff --git a/libcxx/include/__vector/vector.h b/libcxx/include/__vector/vector.h
index 309fa0502752a..0a6a572c87a37 100644
--- a/libcxx/include/__vector/vector.h
+++ b/libcxx/include/__vector/vector.h
@@ -93,7 +93,6 @@ class vector {
template <class _SplitBuffer, class _Tp2, class _Allocator2>
using __split_buffer_layout _LIBCPP_NODEBUG = __split_buffer_pointer_layout<_SplitBuffer, _Tp2, _Allocator2>;
#endif
-
public:
///
/// Types
>From bafc15386fdef256752b34cde86b6572911cc315 Mon Sep 17 00:00:00 2001
From: Christopher Di Bella <cjdb at google.com>
Date: Tue, 20 Jan 2026 21:35:29 +0000
Subject: [PATCH 11/14] renames __split_buffer to comply with GCC's
-Wchanges-meaning
---
libcxx/include/__vector/vector.h | 42 +++++++++++++++-----------------
1 file changed, 20 insertions(+), 22 deletions(-)
diff --git a/libcxx/include/__vector/vector.h b/libcxx/include/__vector/vector.h
index 0a6a572c87a37..f6a5a6453a2d0 100644
--- a/libcxx/include/__vector/vector.h
+++ b/libcxx/include/__vector/vector.h
@@ -87,11 +87,9 @@ _LIBCPP_BEGIN_NAMESPACE_STD
template <class _Tp, class _Allocator /* = allocator<_Tp> */>
class vector {
#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
- template <class _SplitBuffer, class _Tp2, class _Allocator2>
- using __split_buffer_layout _LIBCPP_NODEBUG = __split_buffer_size_layout<_SplitBuffer, _Tp2, _Allocator2>;
+ using _SplitBuffer _LIBCPP_NODEBUG = __split_buffer<_Tp, _Allocator, __split_buffer_size_layout>;
#else
- template <class _SplitBuffer, class _Tp2, class _Allocator2>
- using __split_buffer_layout _LIBCPP_NODEBUG = __split_buffer_pointer_layout<_SplitBuffer, _Tp2, _Allocator2>;
+ using _SplitBuffer _LIBCPP_NODEBUG = __split_buffer<_Tp, _Allocator, __split_buffer_pointer_layout>;
#endif
public:
///
@@ -521,7 +519,7 @@ class vector {
if (__len < static_cast<difference_type>(__raw_capacity() - __raw_sentinel())) {
__construct_at_end(ranges::begin(__range), ranges::end(__range), __len);
} else {
- __split_buffer<_Tp, _Allocator, __split_buffer_layout> __buffer(__recommend(size() + __len), size(), __alloc_);
+ _SplitBuffer __buffer(__recommend(size() + __len), size(), __alloc_);
__buffer.__construct_at_end_with_size(ranges::begin(__range), __len);
__swap_out_circular_buffer(__buffer);
}
@@ -835,9 +833,9 @@ class vector {
}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
- __swap_out_circular_buffer(__split_buffer<_Tp, _Allocator, __split_buffer_layout>& __v);
+ __swap_out_circular_buffer(_SplitBuffer& __v);
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer
- __swap_out_circular_buffer(__split_buffer<_Tp, _Allocator, __split_buffer_layout>& __v, pointer __p);
+ __swap_out_circular_buffer(_SplitBuffer& __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)
@@ -961,7 +959,7 @@ class vector {
}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
- __swap_layouts(__split_buffer<_Tp, _Allocator, __split_buffer_layout>& __sb) {
+ __swap_layouts(_SplitBuffer& __sb) {
auto __vector_begin = __begin_;
auto __vector_sentinel = __raw_sentinel();
auto __vector_cap = __raw_capacity();
@@ -1004,7 +1002,7 @@ vector(from_range_t, _Range&&, _Alloc = _Alloc()) -> vector<ranges::range_value_
// 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<_Tp, _Allocator, __split_buffer_layout>& __v) {
+vector<_Tp, _Allocator>::__swap_out_circular_buffer(_SplitBuffer& __v) {
__annotate_delete();
auto __new_begin = __v.begin() - size();
std::__uninitialized_allocator_relocate(
@@ -1023,7 +1021,7 @@ vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer<_Tp, _Allocat
// function has a strong exception guarantee if __begin_ == __p || size() == __p.
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::pointer
-vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer<_Tp, _Allocator, __split_buffer_layout>& __v,
+vector<_Tp, _Allocator>::__swap_out_circular_buffer(_SplitBuffer& __v,
pointer __p) {
__annotate_delete();
pointer __ret = __v.begin();
@@ -1230,7 +1228,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<_Tp, _Allocator, __split_buffer_layout> __v(__n, size(), this->__alloc_);
+ _SplitBuffer __v(__n, size(), this->__alloc_);
__swap_out_circular_buffer(__v);
}
}
@@ -1241,7 +1239,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::shrink_to_fit() _NOE
#if _LIBCPP_HAS_EXCEPTIONS
try {
#endif // _LIBCPP_HAS_EXCEPTIONS
- __split_buffer<_Tp, _Allocator, __split_buffer_layout> __v(size(), size(), this->__alloc_);
+ _SplitBuffer __v(size(), size(), this->__alloc_);
// 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.
@@ -1258,7 +1256,7 @@ template <class _Tp, class _Allocator>
template <class... _Args>
_LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::__sentinel_type
vector<_Tp, _Allocator>::__emplace_back_slow_path(_Args&&... __args) {
- __split_buffer<_Tp, _Allocator, __split_buffer_layout> __v(__recommend(size() + 1), size(), this->__alloc_);
+ _SplitBuffer __v(__recommend(size() + 1), size(), this->__alloc_);
// __v.emplace_back(std::forward<_Args>(__args)...);
pointer __end = __v.end();
__alloc_traits::construct(this->__alloc_, std::__to_address(__end), std::forward<_Args>(__args)...);
@@ -1362,7 +1360,7 @@ vector<_Tp, _Allocator>::insert(const_iterator __position, const_reference __x)
*__p = *__xr;
}
} else {
- __split_buffer<_Tp, _Allocator, __split_buffer_layout> __v(
+ _SplitBuffer __v(
__recommend(size() + 1), __p - this->__begin_, this->__alloc_);
__v.emplace_back(__x);
__p = __swap_out_circular_buffer(__v, __p);
@@ -1383,7 +1381,7 @@ vector<_Tp, _Allocator>::insert(const_iterator __position, value_type&& __x) {
*__p = std::move(__x);
}
} else {
- __split_buffer<_Tp, _Allocator, __split_buffer_layout> __v(
+ _SplitBuffer __v(
__recommend(size() + 1), __p - this->__begin_, this->__alloc_);
__v.emplace_back(std::move(__x));
__p = __swap_out_circular_buffer(__v, __p);
@@ -1406,7 +1404,7 @@ vector<_Tp, _Allocator>::emplace(const_iterator __position, _Args&&... __args) {
*__p = std::move(__tmp.get());
}
} else {
- __split_buffer<_Tp, _Allocator, __split_buffer_layout> __v(
+ _SplitBuffer __v(
__recommend(size() + 1), __p - this->__begin_, this->__alloc_);
__v.emplace_back(std::forward<_Args>(__args)...);
__p = __swap_out_circular_buffer(__v, __p);
@@ -1436,7 +1434,7 @@ vector<_Tp, _Allocator>::insert(const_iterator __position, size_type __n, const_
std::fill_n(__p, __n, *__xr);
}
} else {
- __split_buffer<_Tp, _Allocator, __split_buffer_layout> __v(
+ _SplitBuffer __v(
__recommend(size() + __n), __p - this->__begin_, this->__alloc_);
__v.__construct_at_end(__n, __x);
__p = __swap_out_circular_buffer(__v, __p);
@@ -1458,12 +1456,12 @@ vector<_Tp, _Allocator>::__insert_with_sentinel(const_iterator __position, _Inpu
if (__first == __last)
(void)std::rotate(__p, __old_last, __end_pointer());
else {
- __split_buffer<_Tp, _Allocator, __split_buffer_layout> __v(__alloc_);
+ _SplitBuffer __v(__alloc_);
pointer __end = __end_pointer();
auto __guard = std::__make_exception_guard(
_AllocatorDestroyRangeReverse<allocator_type, pointer>(__alloc_, __old_last, __end));
__v.__construct_at_end_with_sentinel(std::move(__first), std::move(__last));
- __split_buffer<_Tp, _Allocator, __split_buffer_layout> __merged(
+ _SplitBuffer __merged(
__recommend(size() + __v.size()), __off, __alloc_); // has `__off` positions available at the front
std::__uninitialized_allocator_relocate(
__alloc_, std::__to_address(__old_last), std::__to_address(__end_pointer()), std::__to_address(__merged.end()));
@@ -1511,7 +1509,7 @@ vector<_Tp, _Allocator>::__insert_with_size(
__insert_assign_n_unchecked<_AlgPolicy>(std::move(__first), __n, __p);
}
} else {
- __split_buffer<_Tp, _Allocator, __split_buffer_layout> __v(
+ _SplitBuffer __v(
__recommend(size() + __n), __p - this->__begin_, this->__alloc_);
__v.__construct_at_end_with_size(std::move(__first), __n);
__p = __swap_out_circular_buffer(__v, __p);
@@ -1527,7 +1525,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::resize(size_type __n
if (__new_size <= capacity()) {
__construct_at_end(__new_size - __current_size);
} else {
- __split_buffer<_Tp, _Allocator, __split_buffer_layout> __v(__recommend(__new_size), __current_size, __alloc_);
+ _SplitBuffer __v(__recommend(__new_size), __current_size, __alloc_);
__v.__construct_at_end(__new_size - __current_size);
__swap_out_circular_buffer(__v);
}
@@ -1543,7 +1541,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::resize(size_type __n
if (__new_size <= capacity())
__construct_at_end(__new_size - __current_size, __x);
else {
- __split_buffer<_Tp, _Allocator, __split_buffer_layout> __v(__recommend(__new_size), __current_size, __alloc_);
+ _SplitBuffer __v(__recommend(__new_size), __current_size, __alloc_);
__v.__construct_at_end(__new_size - __current_size, __x);
__swap_out_circular_buffer(__v);
}
>From 7627e34033eb7e8fb95b2bfe813a2b30e8bbf7f4 Mon Sep 17 00:00:00 2001
From: Christopher Di Bella <cjdb at google.com>
Date: Tue, 27 Jan 2026 18:12:20 +0000
Subject: [PATCH 12/14] [libcxx] fixes `__split_buffer_size_layout` bugs
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
**tl;dr**
As `__split_buffer` doesn't have any unit tests, and because #139632
disassociated adding `__split_buffer` support for both pointer-based
and size-based layouts from its `vector` counterpart, libc++ had no
way to expose `__split_buffer_size_layout` bugs until the size-based
vector patch integrated #139632. This commit fixes the two problems
that were identified while working on #155330.
**Context**
* `__split_buffer_size_layout` needs to update its size whenever
`__begin_` is adjusted (relative to `__front_`).
* `__split_buffer`'s layout types originally updated `__begin_`
independently of the sentinel type, via `__set_begin()` and
`__set_sentinel()`, respectively.
* [Louis Dionne observed that `__set_begin()` was always coupled
with `__set_sentinel()`][1], and suggested combining them into
a single setter. This feedback was applied in ec20ccc.
**What went wrong (part 1)**
ec20ccc combined `__set_begin()` and `__set_sentinel()` into a single
function, but didn't remove the overlapping behaviour for
`__split_buffer_size_layout`. The code below shows how this caused a
problem:
```
void __set_valid_range(pointer __new_begin, pointer __new_end)
{
__size_ -= __new_begin - __begin_;
__begin_ = __new_begin;
__set_sentinel(__new_end);
// Inlining call to `__set_sentinel(__new_end)`:
// __size_ += __new_end - end();
//
// Inlining call to `end()`:
// __size_ += __new_end - (__begin_ + __size_);
}
```
`__set_valid_range(pointer, pointer)` sets `__size_` on both sides of
setting `__begin_`. While either is valid on its own, applying both is
incorrect. `__set_valid_range(pointer, size_type)` has the same abstract
logic, but only wastes compute cycles, rather than affecting
correctness:
```
void __set_valid_range(pointer __new_begin, size_type __new_size)
{
__size_ -= __new_begin_ - __begin_;
__begin_ = __new_begin_;
__set_sentinel(__new_size);
// Inlining call to `__set_sentinel(__new_size)`:
// __size = __new_size;
//
// First line is an efficiency bug, not a correctness bug.
}
```
This commit removes the first line both overloads. Additionally, this
commit optimises `__set_sentinel(pointer)` computes, as described
below:
```
__set_sentinel(__new_end)
≡ __size_ += __new_end - end()
≡ __size_ += __new_end - (__begin_ + __size_)
≡ __size_ = __size_ + __new_end - (__begin_ + __size_)
= __size_ + __new_end - __begin_ - __size_
= __new_end - __begin_
```
**What went wrong (part 2)**
The second bug was a type error in `__swap_without_allocator`. As most
function signatures identical in both layout types, they were copied
from `__split_buffer_pointer_layout` into `__split_buffer_size_layout`
to ensure that they were correct. `__swap_without_allocator` is a member
function that operates on the layout type directly, and so its signature
needs to differ with each layout type. Although other member functions
were adjusted (e.g. `swap`), `__swap_without_allocator` was not, leading
to compile-time errors when working on size-based vector, since
`__split_buffer_pointer_layout` is not used when `vector` is size-based.
**How this ended up in the main branch**
Since the size-based vector project applies very similar changes to
`__split_buffer` and `std::vector`, it was split into two PRs, so that
reviewers didn't need to provide duplicate feedback. The PRs were split
on types: #139632 patches `__split_buffer` and #155330 patches `vector`.
Since `vector` needs a layout-compatible `__split_buffer`, #139632 was
merged before #155330, to keep the PR story as simple as possible.
`__split_buffer` is an implementation detail and does not have its own
unit tests: correctness bugs are being surfaced by its drivers, namely
`std::vector` and `std::deque`. As such, there isn't a way to identify
that `__split_buffer_size_layout` was correct without paradoxically
testing it alongside a size-based vector implementation.
**How this can be avoided in the future**
There are two primary ways to avoid this type of problem moving forward.
1. **Split work across logic instead of types.** #139632 could have
introduced the pointer layouts for both `__split_buffer` and
`vector`, which would have set the structure for both types, but not
made any material changes to the implementation. This would have
coupled dependencies instead of typenames, and possibly simplified
the review process further, as no logic would have changed.
The trade-off for this approach is that both layouts influenced the
layout's API design, and might have initially favoured the pointer
layout, leading to adjustments later on.
2. **Stack dependent PRs, and submit when all have been LGTM'd.** This
approach would allow the PRs to be sent for review as they were, but
ensures that logic that's coupled across commits is checked in
together. Stacking the PRs would allow CI to pick up both PRs, which
is critical for ensuring that the dependent PR is correct.
This was considered for #155330, but the GitHub model for [stacking
PRs][2] required some work to be done ahead of #139632's creation
without the risk of confusing reviewers. Closing #139632 and opening a
new PR in service wasn't ideal, as it would have separated the PR
history from the PR that was ultimately merged.
**How this patch was tested**
Since this commit is a change to `__split_buffer_size_layout`, and needs
to be merged with `main` before #155330, this commit was cherry-picked
into #155330, and tested using the libc++ buildbot job for the unstable
ABI.
[1]: https://github.com/llvm/llvm-project/pull/139632/#discussion_r2282535795
[2]: https://llvm.org/docs/GitHub.html#stacked-pull-requests
---
libcxx/include/__split_buffer | 12 +++---------
1 file changed, 3 insertions(+), 9 deletions(-)
diff --git a/libcxx/include/__split_buffer b/libcxx/include/__split_buffer
index da26a6e74935a..d6f479980961f 100644
--- a/libcxx/include/__split_buffer
+++ b/libcxx/include/__split_buffer
@@ -156,10 +156,8 @@ public:
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference back() const _NOEXCEPT { return *(__end_ - 1); }
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __swap_without_allocator(
- __split_buffer_pointer_layout<__split_buffer<value_type, allocator_type, __split_buffer_pointer_layout>,
- value_type,
- allocator_type>& __other) _NOEXCEPT {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
+ __swap_without_allocator(__split_buffer_pointer_layout& __other) _NOEXCEPT {
std::swap(__front_cap_, __other.__front_cap_);
std::swap(__begin_, __other.__begin_);
std::swap(__back_cap_, __other.__back_cap_);
@@ -263,23 +261,19 @@ public:
_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.
__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.
__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(__front_cap_ <= __new_end, "__new_end cannot precede __front_cap_");
- __size_ += __new_end - end();
+ __size_ = __new_end - __begin_;
}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_sentinel(size_type __new_size) _NOEXCEPT {
>From 832fdb07056eeb03eade88e5f712d4ed82511c81 Mon Sep 17 00:00:00 2001
From: Christopher Di Bella <cjdb at google.com>
Date: Wed, 28 Jan 2026 02:41:51 +0000
Subject: [PATCH 13/14] reverts ranges.swap_ranges.pass.cpp
---
.../alg.swap/ranges.swap_ranges.pass.cpp | 54 +++++++++----------
1 file changed, 24 insertions(+), 30 deletions(-)
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 da42ce56db30a..85557ecbbfabc 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,6 +67,22 @@ TEST_CONSTEXPR_CXX20 void test_iterators() {
}
}
+template <std::size_t N>
+constexpr void test_vector_bool() {
+ { // Test swap_ranges() with aligned bytes
+ std::vector<bool> 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<bool> 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};
@@ -167,34 +183,15 @@ constexpr bool test() {
});
});
- return true;
-}
-
-// Test vector<bool>::iterator optimization
-template <std::size_t N>
-constexpr void test_vector_bool() {
- { // Test swap_ranges() with aligned bytes
- std::vector<bool> 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 vector<bool>::iterator optimization
+ test_vector_bool<8>();
+ test_vector_bool<19>();
+ test_vector_bool<32>();
+ test_vector_bool<49>();
+ test_vector_bool<64>();
+ test_vector_bool<199>();
+ test_vector_bool<256>();
}
- { // Test swap_ranges() with unaligned bytes
- std::vector<bool> f(N, false), t(N + 8, true);
- std::ranges::swap_ranges(f.begin(), f.end(), t.begin() + 4, t.end() - 4);
- assert(std::all_of(f.begin(), f.end(), [](bool b) { return b; }));
- assert(std::all_of(t.begin() + 4, t.end() - 4, [](bool b) { return !b; }));
- }
-}
-
-constexpr bool test_vector_bool() {
- test_vector_bool<8>();
- test_vector_bool<19>();
- test_vector_bool<32>();
- test_vector_bool<49>();
- test_vector_bool<64>();
- test_vector_bool<199>();
- test_vector_bool<256>();
return true;
}
@@ -204,8 +201,5 @@ int main(int, char**) {
test();
static_assert(test());
- test_vector_bool();
- static_assert(test_vector_bool());
-
return 0;
}
>From 10b2fc9615e75498d1b1dfd92ae92e596a4afdd9 Mon Sep 17 00:00:00 2001
From: Christopher Di Bella <cjdb at google.com>
Date: Wed, 28 Jan 2026 20:12:20 +0000
Subject: [PATCH 14/14] explicitly casts `__other` to `__base_type&`
---
libcxx/include/__split_buffer | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/include/__split_buffer b/libcxx/include/__split_buffer
index d6f479980961f..89c398e525998 100644
--- a/libcxx/include/__split_buffer
+++ b/libcxx/include/__split_buffer
@@ -575,7 +575,7 @@ public:
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
__swap_without_allocator(__split_buffer<value_type, allocator_type, _Layout>& __other) _NOEXCEPT {
- __base_type::__swap_without_allocator(__other);
+ __base_type::__swap_without_allocator(static_cast<__base_type&>(__other));
}
private:
More information about the libcxx-commits
mailing list