[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 Sep 18 13:19:58 PDT 2025


https://github.com/cjdb updated https://github.com/llvm/llvm-project/pull/155330

>From 1e7c6fe152c2b580ed4366a32397f2541f42953a 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] [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/__vector/vector.h              | 815 ++++++++++++------
 .../alg.swap/ranges.swap_ranges.pass.cpp      |  54 +-
 libcxx/utils/gdb/libcxx/printers.py           |  18 +-
 3 files changed, 594 insertions(+), 293 deletions(-)

diff --git a/libcxx/include/__vector/vector.h b/libcxx/include/__vector/vector.h
index 27e681aeef22a..a924b7d7e6581 100644
--- a/libcxx/include/__vector/vector.h
+++ b/libcxx/include/__vector/vector.h
@@ -57,6 +57,7 @@
 #include <__type_traits/is_pointer.h>
 #include <__type_traits/is_replaceable.h>
 #include <__type_traits/is_same.h>
+#include <__type_traits/is_swappable.h>
 #include <__type_traits/is_trivially_relocatable.h>
 #include <__type_traits/type_identity.h>
 #include <__utility/declval.h>
@@ -84,25 +85,334 @@ _LIBCPP_PUSH_MACROS
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
+#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+template <class _Vector, 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;
+
+  __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
@@ -116,6 +426,12 @@ class vector {
   using reverse_iterator       = std::reverse_iterator<iterator>;
   using const_reverse_iterator = std::reverse_iterator<const_iterator>;
 
+  using __base::__invariants;
+  using __base::back;
+  using __base::capacity;
+  using __base::empty;
+  using __base::size;
+
   // A vector containers the following members which may be trivially relocatable:
   // - pointer: may be trivially relocatable, so it's checked
   // - allocator_type: may be trivially relocatable, so it's checked
@@ -144,7 +460,7 @@ class vector {
 #else
       noexcept
 #endif
-      : __alloc_(__a) {
+      : __base(__a) {
   }
 
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit vector(size_type __n) {
@@ -158,7 +474,7 @@ class vector {
 
 #if _LIBCPP_STD_VER >= 14
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit vector(size_type __n, const allocator_type& __a)
-      : __alloc_(__a) {
+      : __base(__a) {
     auto __guard = std::__make_exception_guard(__destroy_vector(*this));
     if (__n > 0) {
       __vallocate(__n);
@@ -180,7 +496,7 @@ class vector {
   template <__enable_if_t<__is_allocator<_Allocator>::value, int> = 0>
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
   vector(size_type __n, const value_type& __x, const allocator_type& __a)
-      : __alloc_(__a) {
+      : __base(__a) {
     auto __guard = std::__make_exception_guard(__destroy_vector(*this));
     if (__n > 0) {
       __vallocate(__n);
@@ -203,7 +519,7 @@ class vector {
                           int> = 0>
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
   vector(_InputIterator __first, _InputIterator __last, const allocator_type& __a)
-      : __alloc_(__a) {
+      : __base(__a) {
     __init_with_sentinel(__first, __last);
   }
 
@@ -224,7 +540,7 @@ class vector {
                     int> = 0>
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
   vector(_ForwardIterator __first, _ForwardIterator __last, const allocator_type& __a)
-      : __alloc_(__a) {
+      : __base(__a) {
     size_type __n = static_cast<size_type>(std::distance(__first, __last));
     __init_with_size(__first, __last, __n);
   }
@@ -233,7 +549,7 @@ class vector {
   template <_ContainerCompatibleRange<_Tp> _Range>
   _LIBCPP_HIDE_FROM_ABI constexpr vector(
       from_range_t, _Range&& __range, const allocator_type& __alloc = allocator_type())
-      : __alloc_(__alloc) {
+      : __base(__alloc) {
     if constexpr (ranges::forward_range<_Range> || ranges::sized_range<_Range>) {
       auto __n = static_cast<size_type>(ranges::distance(__range));
       __init_with_size(ranges::begin(__range), ranges::end(__range), __n);
@@ -250,10 +566,10 @@ class vector {
     _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI __destroy_vector(vector& __vec) : __vec_(__vec) {}
 
     _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void operator()() {
-      if (__vec_.__begin_ != nullptr) {
+      if (__vec_.__raw_begin() != nullptr) {
         __vec_.clear();
         __vec_.__annotate_delete();
-        __alloc_traits::deallocate(__vec_.__alloc_, __vec_.__begin_, __vec_.capacity());
+        __alloc_traits::deallocate(__vec_.__allocator_ref(), __vec_.__raw_begin(), __vec_.capacity());
       }
     }
 
@@ -265,13 +581,13 @@ class vector {
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI ~vector() { __destroy_vector (*this)(); }
 
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI vector(const vector& __x)
-      : __alloc_(__alloc_traits::select_on_container_copy_construction(__x.__alloc_)) {
-    __init_with_size(__x.__begin_, __x.__end_, __x.size());
+      : __base(__alloc_traits::select_on_container_copy_construction(__x.__allocator_ref())) {
+    __init_with_size(__x.__raw_begin(), __x.__end_pointer(), __x.size());
   }
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
   vector(const vector& __x, const __type_identity_t<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);
 
@@ -282,7 +598,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());
   }
 
@@ -345,23 +661,23 @@ class vector {
 #endif
 
   [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const _NOEXCEPT {
-    return this->__alloc_;
+    return __allocator_ref();
   }
 
   //
   // Iterators
   //
   [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT {
-    return __make_iter(__add_alignment_assumption(this->__begin_));
+    return __make_iter(__add_alignment_assumption(__raw_begin()));
   }
   [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT {
-    return __make_iter(__add_alignment_assumption(this->__begin_));
+    return __make_iter(__add_alignment_assumption(__raw_begin()));
   }
   [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT {
-    return __make_iter(__add_alignment_assumption(this->__end_));
+    return __make_iter(__add_alignment_assumption(__end_pointer()));
   }
   [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT {
-    return __make_iter(__add_alignment_assumption(this->__end_));
+    return __make_iter(__add_alignment_assumption(__end_pointer()));
   }
 
   [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reverse_iterator rbegin() _NOEXCEPT {
@@ -395,17 +711,8 @@ class vector {
   //
   // [vector.capacity], capacity
   //
-  [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT {
-    return static_cast<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>(this->__cap_ - this->__begin_);
-  }
-  [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool empty() const _NOEXCEPT {
-    return this->__begin_ == this->__end_;
-  }
   [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT {
-    return std::min<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;
@@ -415,50 +722,42 @@ class vector {
   //
   [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference operator[](size_type __n) _NOEXCEPT {
     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__n < size(), "vector[] index out of bounds");
-    return this->__begin_[__n];
+    return __raw_begin()[__n];
   }
   [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference
   operator[](size_type __n) const _NOEXCEPT {
     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__n < size(), "vector[] index out of bounds");
-    return this->__begin_[__n];
+    return __raw_begin()[__n];
   }
   [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference at(size_type __n) {
     if (__n >= size())
       this->__throw_out_of_range();
-    return this->__begin_[__n];
+    return __raw_begin()[__n];
   }
   [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference at(size_type __n) const {
     if (__n >= size())
       this->__throw_out_of_range();
-    return this->__begin_[__n];
+    return __raw_begin()[__n];
   }
 
   [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference front() _NOEXCEPT {
     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "front() called on an empty vector");
-    return *this->__begin_;
+    return *__raw_begin();
   }
   [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference front() const _NOEXCEPT {
     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "front() called on an empty vector");
-    return *this->__begin_;
-  }
-  [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference back() _NOEXCEPT {
-    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "back() called on an empty vector");
-    return *(this->__end_ - 1);
-  }
-  [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference back() const _NOEXCEPT {
-    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "back() called on an empty vector");
-    return *(this->__end_ - 1);
+    return *__raw_begin();
   }
 
   //
   // [vector.data], data access
   //
   [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI value_type* data() _NOEXCEPT {
-    return std::__to_address(this->__begin_);
+    return std::__to_address(__raw_begin());
   }
 
   [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const value_type* data() const _NOEXCEPT {
-    return std::__to_address(this->__begin_);
+    return std::__to_address(__raw_begin());
   }
 
   //
@@ -483,7 +782,7 @@ class vector {
     _LIBCPP_ASSERT_INTERNAL(
         size() < capacity(), "We assume that we have enough space to insert an element at the end of the vector");
     _ConstructTransaction __tx(*this, 1);
-    __alloc_traits::construct(this->__alloc_, std::__to_address(__tx.__pos_), std::forward<_Args>(__args)...);
+    __alloc_traits::construct(__allocator_ref(), std::__to_address(__tx.__pos_), std::forward<_Args>(__args)...);
     ++__tx.__pos_;
   }
 
@@ -496,7 +795,7 @@ class vector {
 
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void pop_back() {
     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "vector::pop_back called on an empty vector");
-    this->__destruct_at_end(this->__end_ - 1);
+    this->__destruct_at_end(__end_pointer() - 1);
   }
 
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __position, const_reference __x);
@@ -552,41 +851,39 @@ class vector {
 
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void clear() _NOEXCEPT {
     size_type __old_size = size();
-    __base_destruct_at_end(this->__begin_);
+    __base_destruct_at_end(__raw_begin());
     __annotate_shrink(__old_size);
   }
 
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void resize(size_type __sz);
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void resize(size_type __sz, const_reference __x);
 
-  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void swap(vector&)
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void swap(vector& __other)
 #if _LIBCPP_STD_VER >= 14
-      _NOEXCEPT;
+      _NOEXCEPT
 #else
-      _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || __is_nothrow_swappable_v<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);
   }
 
@@ -634,7 +931,7 @@ class vector {
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
   __insert_assign_n_unchecked(_Iterator __first, difference_type __n, pointer __position) {
     for (pointer __end_position = __position + __n; __position != __end_position; ++__position, (void)++__first) {
-      __temp_value<value_type, _Allocator> __tmp(this->__alloc_, *__first);
+      __temp_value<value_type, _Allocator> __tmp(__allocator_ref(), *__first);
       *__position = std::move(__tmp.get());
     }
   }
@@ -681,8 +978,8 @@ class vector {
     // a laxer approach.
     return std::__make_bounded_iter(
         std::__wrap_iter<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
@@ -693,17 +990,16 @@ class vector {
     // Bound the iterator according to the capacity, rather than the size.
     return std::__make_bounded_iter(
         std::__wrap_iter<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)
@@ -717,7 +1013,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.
@@ -750,14 +1046,14 @@ class vector {
 
   struct _ConstructTransaction {
     _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit _ConstructTransaction(vector& __v, size_type __n)
-        : __v_(__v), __pos_(__v.__end_), __new_end_(__v.__end_ + __n) {
+        : __v_(__v), __pos_(__v.__end_pointer()), __new_end_(__pos_ + __n) {
       __v_.__annotate_increase(__n);
     }
 
     _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI ~_ConstructTransaction() {
-      __v_.__end_ = __pos_;
+      __v_.__set_sentinel(__pos_);
       if (__pos_ != __new_end_) {
-        __v_.__annotate_shrink(__new_end_ - __v_.__begin_);
+        __v_.__annotate_shrink(__new_end_ - __v_.__raw_begin());
       }
     }
 
@@ -770,10 +1066,10 @@ class vector {
   };
 
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __base_destruct_at_end(pointer __new_last) _NOEXCEPT {
-    pointer __soon_to_be_end = this->__end_;
+    pointer __soon_to_be_end = __end_pointer();
     while (__new_last != __soon_to_be_end)
-      __alloc_traits::destroy(this->__alloc_, std::__to_address(--__soon_to_be_end));
-    this->__end_ = __new_last;
+      __alloc_traits::destroy(__allocator_ref(), std::__to_address(--__soon_to_be_end));
+    __set_sentinel(__new_last);
   }
 
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __copy_assign_alloc(const vector& __c) {
@@ -791,20 +1087,21 @@ class vector {
   [[__noreturn__]] _LIBCPP_HIDE_FROM_ABI static void __throw_out_of_range() { std::__throw_out_of_range("vector"); }
 
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __copy_assign_alloc(const vector& __c, true_type) {
-    if (this->__alloc_ != __c.__alloc_) {
+    if (__allocator_ref() != __c.__allocator_ref()) {
       clear();
       __annotate_delete();
-      __alloc_traits::deallocate(this->__alloc_, this->__begin_, capacity());
-      this->__begin_ = this->__end_ = this->__cap_ = nullptr;
+      __alloc_traits::deallocate(__allocator_ref(), __raw_begin(), capacity());
+      __set_valid_range(nullptr, static_cast<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 {}
@@ -824,19 +1121,17 @@ class vector {
     return __p;
   }
 
-  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __swap_layouts(__split_buffer<_Tp, allocator_type&>& __sb) {
-    auto __vector_begin    = __begin_;
-    auto __vector_sentinel = __end_;
-    auto __vector_cap      = __cap_;
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __swap_layouts(__split_buffer& __sb) {
+    auto __vector_begin    = __raw_begin();
+    auto __vector_sentinel = __raw_sentinel();
+    auto __vector_cap      = __raw_capacity();
 
     auto __sb_begin    = __sb.begin();
     auto __sb_sentinel = __sb.__raw_sentinel();
     auto __sb_cap      = __sb.__raw_capacity();
 
-    // TODO: replace with __set_valid_range and __set_capacity when vector supports it.
-    __begin_ = __sb_begin;
-    __end_   = __sb_sentinel;
-    __cap_   = __sb_cap;
+    __set_valid_range(__sb_begin, __sb_sentinel);
+    __set_capacity(__sb_cap);
 
     __sb.__set_valid_range(__vector_begin, __vector_sentinel);
     __sb.__set_capacity(__vector_cap);
@@ -864,47 +1159,53 @@ template <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());
@@ -913,11 +1214,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));
   }
 }
 
@@ -934,7 +1236,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()
@@ -944,11 +1246,11 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::__construct_at_end(s
   _ConstructTransaction __tx(*this, __n);
   const_pointer __new_end = __tx.__new_end_;
   for (pointer __pos = __tx.__pos_; __pos != __new_end; __tx.__pos_ = ++__pos) {
-    __alloc_traits::construct(this->__alloc_, std::__to_address(__pos));
+    __alloc_traits::construct(__allocator_ref(), std::__to_address(__pos));
   }
 }
 
-//  Copy constructs __n objects starting at __end_ from __x
+//  Copy constructs __n objects starting at __end_pointer() from __x
 //  throws if construction throws
 //  Precondition:  __n > 0
 //  Precondition:  size() + __n <= capacity()
@@ -960,7 +1262,7 @@ vector<_Tp, _Allocator>::__construct_at_end(size_type __n, const_reference __x)
   _ConstructTransaction __tx(*this, __n);
   const_pointer __new_end = __tx.__new_end_;
   for (pointer __pos = __tx.__pos_; __pos != __new_end; __tx.__pos_ = ++__pos) {
-    __alloc_traits::construct(this->__alloc_, std::__to_address(__pos), __x);
+    __alloc_traits::construct(__allocator_ref(), std::__to_address(__pos), __x);
   }
 }
 
@@ -969,34 +1271,35 @@ template <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_);
 }
 
-//  Default constructs __n objects starting at __end_
+//  Default constructs __n objects starting at __end_pointer()
 //  throws if construction throws
 //  Postcondition:  size() == size() + __n
 //  Exception safety: strong.
 template <class _Tp, class _Allocator>
 _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::__append(size_type __n) {
-  if (static_cast<size_type>(this->__cap_ - this->__end_) >= __n)
+  if (__remaining_capacity() >= __n)
     this->__construct_at_end(__n);
   else {
-    __split_buffer<value_type, allocator_type&> __v(__recommend(size() + __n), size(), this->__alloc_);
+    __split_buffer __v(__recommend(size() + __n), size(), __allocator_ref());
     __v.__construct_at_end(__n);
     __swap_out_circular_buffer(__v);
   }
 }
 
-//  Default constructs __n objects starting at __end_
+//  Default constructs __n objects starting at __end_pointer()
 //  throws if construction throws
 //  Postcondition:  size() == size() + __n
 //  Exception safety: strong.
 template <class _Tp, class _Allocator>
 _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::__append(size_type __n, const_reference __x) {
-  if (static_cast<size_type>(this->__cap_ - this->__end_) >= __n)
+  if (__remaining_capacity() >= __n)
     this->__construct_at_end(__n, __x);
   else {
-    __split_buffer<value_type, allocator_type&> __v(__recommend(size() + __n), size(), this->__alloc_);
+    __split_buffer __v(__recommend(size() + __n), size(), __allocator_ref());
     __v.__construct_at_end(__n, __x);
     __swap_out_circular_buffer(__v);
   }
@@ -1009,22 +1312,22 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI vector<_Tp, _Allocato
 #else
     _NOEXCEPT_(is_nothrow_move_constructible<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());
@@ -1034,7 +1337,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
@@ -1046,10 +1349,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>
@@ -1057,7 +1360,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI vector<_Tp, _Allocato
 vector<_Tp, _Allocator>::operator=(const vector& __x) {
   if (this != std::addressof(__x)) {
     __copy_assign_alloc(__x);
-    assign(__x.__begin_, __x.__end_);
+    assign(__x.__raw_begin(), __x.__end_pointer());
   }
   return *this;
 }
@@ -1066,10 +1369,11 @@ template <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)
@@ -1085,15 +1389,15 @@ vector<_Tp, _Allocator>::__assign_with_size(_Iterator __first, _Sentinel __last,
   if (__new_size <= capacity()) {
     if (__new_size > size()) {
 #if _LIBCPP_STD_VER >= 23
-      auto __mid = ranges::copy_n(std::move(__first), size(), this->__begin_).in;
+      auto __mid = ranges::copy_n(std::move(__first), size(), __raw_begin()).in;
       __construct_at_end(std::move(__mid), std::move(__last), __new_size - size());
 #else
       _Iterator __mid = std::next(__first, size());
-      std::copy(__first, __mid, this->__begin_);
+      std::copy(__first, __mid, __raw_begin());
       __construct_at_end(__mid, __last, __new_size - size());
 #endif
     } else {
-      pointer __m = std::__copy(std::move(__first), __last, this->__begin_).second;
+      pointer __m = std::__copy(std::move(__first), __last, __raw_begin()).second;
       this->__destruct_at_end(__m);
     }
   } else {
@@ -1107,11 +1411,11 @@ template <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)));
@@ -1124,7 +1428,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::reserve(size_type __
   if (__n > capacity()) {
     if (__n > max_size())
       this->__throw_length_error();
-    __split_buffer<value_type, allocator_type&> __v(__n, size(), this->__alloc_);
+    __split_buffer __v(__n, size(), __allocator_ref());
     __swap_out_circular_buffer(__v);
   }
 }
@@ -1135,7 +1439,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::shrink_to_fit() _NOE
 #if _LIBCPP_HAS_EXCEPTIONS
     try {
 #endif // _LIBCPP_HAS_EXCEPTIONS
-      __split_buffer<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.
@@ -1150,15 +1454,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
@@ -1188,18 +1492,18 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 inline
     void
 #endif
     vector<_Tp, _Allocator>::emplace_back(_Args&&... __args) {
-  pointer __end = this->__end_;
+  auto __current_sentinel = __raw_sentinel();
   std::__if_likely_else(
-      __end < this->__cap_,
+      __current_sentinel < __raw_capacity(),
       [&] {
         __emplace_back_assume_capacity(std::forward<_Args>(__args)...);
-        ++__end;
+        ++__current_sentinel;
       },
-      [&] { __end = __emplace_back_slow_path(std::forward<_Args>(__args)...); });
+      [&] { __current_sentinel = __emplace_back_slow_path(std::forward<_Args>(__args)...); });
 
-  this->__end_ = __end;
+  __set_sentinel(__current_sentinel);
 #if _LIBCPP_STD_VER >= 17
-  return *(__end - 1);
+  return back();
 #endif
 }
 
@@ -1209,8 +1513,8 @@ vector<_Tp, _Allocator>::erase(const_iterator __position) {
   _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
       __position != end(), "vector::erase(iterator) called with a non-dereferenceable iterator");
   difference_type __ps = __position - cbegin();
-  pointer __p          = this->__begin_ + __ps;
-  this->__destruct_at_end(std::move(__p + 1, this->__end_, __p));
+  pointer __p          = __raw_begin() + __ps;
+  this->__destruct_at_end(std::move(__p + 1, __end_pointer(), __p));
   return __make_iter(__p);
 }
 
@@ -1218,9 +1522,9 @@ template <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);
 }
@@ -1228,13 +1532,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);
@@ -1243,19 +1547,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);
   }
@@ -1265,16 +1570,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);
   }
@@ -1285,17 +1591,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);
   }
@@ -1305,25 +1612,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);
     }
@@ -1336,27 +1644,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);
@@ -1369,16 +1685,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
         {
@@ -1394,7 +1711,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);
     }
@@ -1408,7 +1725,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::resize(size_type __s
   if (__cs < __sz)
     this->__append(__sz - __cs);
   else if (__cs > __sz)
-    this->__destruct_at_end(this->__begin_ + __sz);
+    this->__destruct_at_end(__raw_begin() + __sz);
 }
 
 template <class _Tp, class _Allocator>
@@ -1417,49 +1734,15 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::resize(size_type __s
   if (__cs < __sz)
     this->__append(__sz - __cs, __x);
   else if (__cs > __sz)
-    this->__destruct_at_end(this->__begin_ + __sz);
-}
-
-template <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;
+    this->__destruct_at_end(__raw_begin() + __sz);
 }
 
 #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):



More information about the libcxx-commits mailing list