[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