[libcxx-commits] [libcxx] [lldb] [libcxx] adds size-based `__split_buffer` representation to unstable ABI (PR #139632)
Christopher Di Bella via libcxx-commits
libcxx-commits at lists.llvm.org
Fri Jun 6 10:21:38 PDT 2025
https://github.com/cjdb updated https://github.com/llvm/llvm-project/pull/139632
>From 88bc35049f774c8c3a5c35ff22470a0670ee3e9d Mon Sep 17 00:00:00 2001
From: Christopher Di Bella <cjdb at google.com>
Date: Wed, 7 May 2025 20:41:56 +0000
Subject: [PATCH 1/5] [libcxx] adds size-based `__split_buffer` representation
to 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.
`vector` depends on `__split_buffer` for inserting elements. Changing
`__split_buffer` to match `vector`'s representation simplifies the
model, as it eliminates the need to convert between two different
representations of a contiguous buffer in the same configuration of
libc++.
[RFC]: TODO
---
libcxx/include/__split_buffer | 549 +++++++++++++++++++++----------
libcxx/include/__vector/vector.h | 48 +--
libcxx/include/deque | 40 +--
3 files changed, 416 insertions(+), 221 deletions(-)
diff --git a/libcxx/include/__split_buffer b/libcxx/include/__split_buffer
index 21e58f4abc6b3..9710dfec774f7 100644
--- a/libcxx/include/__split_buffer
+++ b/libcxx/include/__split_buffer
@@ -13,10 +13,12 @@
#include <__algorithm/max.h>
#include <__algorithm/move.h>
#include <__algorithm/move_backward.h>
+#include <__assert>
#include <__config>
#include <__iterator/distance.h>
#include <__iterator/iterator_traits.h>
#include <__iterator/move_iterator.h>
+#include <__memory/addressof.h>
#include <__memory/allocate_at_least.h>
#include <__memory/allocator.h>
#include <__memory/allocator_traits.h>
@@ -78,23 +80,260 @@ public:
__split_buffer,
void>;
- pointer __first_;
- pointer __begin_;
- pointer __end_;
- _LIBCPP_COMPRESSED_PAIR(pointer, __cap_, allocator_type, __alloc_);
+ struct __data {
+ pointer __first_ = nullptr;
+ pointer __begin_ = nullptr;
+#ifndef _LIBCPP_ABI_SIZE_BASED_VECTOR
+ pointer __end_ = nullptr;
+ _LIBCPP_COMPRESSED_PAIR(pointer, __cap_ = nullptr, allocator_type, __alloc_);
+#else
+ size_type __size_ = 0;
+ _LIBCPP_COMPRESSED_PAIR(size_type, __cap_ = 0, allocator_type, __alloc_);
+#endif
+
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __data() = default;
+
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __data(const allocator_type& __alloc)
+ : __alloc_(__alloc)
+ {}
+
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer first() noexcept {
+ return __first_;
+ }
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_pointer first() const noexcept {
+ return __first_;
+ }
+
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer begin() noexcept {
+ return __begin_;
+ }
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_pointer begin() const noexcept {
+ return __begin_;
+ }
+
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer end() noexcept {
+#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+ return __begin_ + __size_;
+#else
+ return __end_;
+#endif
+ }
+
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer end() const noexcept {
+#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+ return __begin_ + __size_;
+#else
+ return __end_;
+#endif
+ }
+
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type size() const noexcept {
+#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+ return __size_;
+#else
+ return static_cast<size_type>(__end_ - __begin_);
+#endif
+ }
+
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool empty() const noexcept {
+#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+ return __size_ == 0;
+#else
+ return __begin_ == __end_;
+#endif
+ }
+
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type capacity() const noexcept {
+#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+ return __cap_;
+#else
+ return static_cast<size_type>(__cap_ - __first_);
+#endif
+ }
+
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer __capacity_as_pointer() noexcept {
+#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+ return __first_ + __cap_;
+#else
+ return __cap_;
+#endif
+ }
+
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer __capacity_as_pointer() const noexcept {
+#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+ return __first_ + __cap_;
+#else
+ return __cap_;
+#endif
+ }
+
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __update_begin(pointer __new_begin) noexcept {
+#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+ __size_ -= __new_begin - __begin_;
+#else
+ // TODO: explain why there isn't a pointer-based analogue
+#endif
+
+ __begin_ = __new_begin;
+ }
+
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __front_spare() const noexcept {
+ return static_cast<size_type>(__begin_ - __first_);
+ }
+
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __update_sentinel(pointer __new_end) noexcept {
+ _LIBCPP_ASSERT(__first_ <= __new_end, "__new_end cannot precede __first_");
+#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+ __size_ += __new_end - end();
+#else
+ __end_ = __new_end;
+#endif
+ }
+
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __update_sentinel(size_type __new_size) noexcept {
+#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+ __size_ = __new_size;
+#else
+ __end_ = __begin_ + __new_size;
+#endif
+ }
- __split_buffer(const __split_buffer&) = delete;
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __update_capacity(size_type __new_capacity) noexcept {
+#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+ __cap_ = __new_capacity;
+#else
+ __cap_ = __first_ + __new_capacity;
+#endif
+ }
+
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __back_spare() const noexcept {
+#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+ // `__cap_ - __end_` tells us the total number of spares when in size-mode. We need to remove
+ // the __front_spare from the count.
+ return __cap_ - __size_ - __front_spare();
+#else
+ return static_cast<size_type>(__cap_ - __end_);
+#endif
+ }
+
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference back() noexcept {
+#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+ return __begin_[__size_ - 1];
+#else
+ return *(__end_ - 1);
+#endif
+ }
+
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference back() const noexcept {
+#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+ return __begin_[__size_ - 1];
+#else
+ return *(__end_ - 1);
+#endif
+ }
+
+ template<class _Data2>
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __swap_without_allocator(_Data2& __other) noexcept {
+ std::swap(__first_, __other.__first_);
+ std::swap(__begin_, __other.__begin_);
+ std::swap(__cap_, __other.__cap_);
+#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+ std::swap(__size_, __other.__size_);
+#else
+ std::swap(__end_, __other.__end_);
+#endif
+ }
+
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void swap(__data& __other) noexcept {
+ __swap_without_allocator(__other);
+ std::__swap_allocator(__alloc_, __other.__alloc_);
+ }
+
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __invariants() const noexcept {
+ if (__first_ == nullptr) {
+ if (__begin_ != nullptr) {
+ return false;
+ }
+
+ if (!empty()) {
+ return false;
+ }
+
+ if (capacity() != 0) {
+ return false;
+ }
+
+ return true;
+ }
+
+ if (__begin_ < __first_) {
+ return false;
+ }
+
+ if (capacity() < size()) {
+ return false;
+ }
+
+ if (end() < __begin_) {
+ return false;
+ }
+
+ return true;
+ }
+
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __is_full() const noexcept {
+#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+ return __size_ == __cap_;
+#else
+ return __end_ == __cap_;
+#endif
+ }
+
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __reset() noexcept {
+ __first_ = nullptr;
+ __begin_ = nullptr;
+#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+ __size_ = 0;
+ __cap_ = 0;
+#else
+ __end_ = nullptr;
+ __cap_ = nullptr;
+#endif
+ }
+
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __copy_without_alloc(__data const& __other)
+ noexcept(is_nothrow_copy_assignable<pointer>::value)
+ {
+ __first_ = __other.__first_;
+ __begin_ = __other.__begin_;
+ __cap_ = __other.__cap_;
+#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+ __size_ = __other.__size_;
+#else
+ __end_ = __other.__end_;
+#endif
+ }
+ };
+
+ __data __data_;
+
+ __split_buffer(const __split_buffer&) = delete;
__split_buffer& operator=(const __split_buffer&) = delete;
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __split_buffer()
- _NOEXCEPT_(is_nothrow_default_constructible<allocator_type>::value)
- : __first_(nullptr), __begin_(nullptr), __end_(nullptr), __cap_(nullptr) {}
+ _NOEXCEPT_(is_nothrow_default_constructible<allocator_type>::value)
+ : __data_{}
+ {}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __split_buffer(__alloc_rr& __a)
- : __first_(nullptr), __begin_(nullptr), __end_(nullptr), __cap_(nullptr), __alloc_(__a) {}
+ _NOEXCEPT_(is_nothrow_default_constructible<allocator_type>::value)
+ : __data_(__a)
+ {}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __split_buffer(const __alloc_rr& __a)
- : __first_(nullptr), __begin_(nullptr), __end_(nullptr), __cap_(nullptr), __alloc_(__a) {}
+ _NOEXCEPT_(is_nothrow_default_constructible<allocator_type>::value)
+ : __data_(__a)
+ {}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
__split_buffer(size_type __cap, size_type __start, __alloc_rr& __a);
@@ -111,36 +350,22 @@ public:
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI ~__split_buffer();
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { return __begin_; }
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { return __begin_; }
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { return __data_.begin(); }
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { return __data_.begin(); }
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT { return __data_.end(); }
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT { return __data_.end(); }
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT { return __end_; }
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT { return __end_; }
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void clear() _NOEXCEPT { __destruct_at_end(__data_.__begin_); }
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type size() const { return __data_.size(); }
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool empty() const { return __data_.empty(); }
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void clear() _NOEXCEPT { __destruct_at_end(__begin_); }
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type capacity() const { return __data_.capacity(); }
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type size() const {
- return static_cast<size_type>(__end_ - __begin_);
- }
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference front() { return *__data_.__begin_; }
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference front() const { return *__data_.__begin_; }
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool empty() const { return __end_ == __begin_; }
-
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type capacity() const {
- return static_cast<size_type>(__cap_ - __first_);
- }
-
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __front_spare() const {
- return static_cast<size_type>(__begin_ - __first_);
- }
-
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __back_spare() const {
- return static_cast<size_type>(__cap_ - __end_);
- }
-
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference front() { return *__begin_; }
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference front() const { return *__begin_; }
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference back() { return *(__end_ - 1); }
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference back() const { return *(__end_ - 1); }
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference back() { return __data_.back(); }
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference back() const { return __data_.back(); }
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void shrink_to_fit() _NOEXCEPT;
@@ -149,8 +374,8 @@ public:
template <class... _Args>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void emplace_back(_Args&&... __args);
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void pop_front() { __destruct_at_begin(__begin_ + 1); }
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void pop_back() { __destruct_at_end(__end_ - 1); }
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void pop_front() { __destruct_at_begin(__data_.begin() + 1); }
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void pop_back() { __destruct_at_end(__data_.end() - 1); }
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __construct_at_end(size_type __n);
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __construct_at_end(size_type __n, const_reference __x);
@@ -185,66 +410,52 @@ public:
_NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || __is_nothrow_swappable_v<__alloc_rr>);
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __invariants() const;
-
private:
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __move_assign_alloc(__split_buffer& __c, true_type)
_NOEXCEPT_(is_nothrow_move_assignable<allocator_type>::value) {
- __alloc_ = std::move(__c.__alloc_);
+ __data_.__alloc_ = std::move(__c.__data_.__alloc_);
}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __move_assign_alloc(__split_buffer&, false_type) _NOEXCEPT {}
struct _ConstructTransaction {
_LIBCPP_CONSTEXPR_SINCE_CXX20
- _LIBCPP_HIDE_FROM_ABI explicit _ConstructTransaction(pointer* __p, size_type __n) _NOEXCEPT
- : __pos_(*__p),
- __end_(*__p + __n),
- __dest_(__p) {}
+ _LIBCPP_HIDE_FROM_ABI explicit _ConstructTransaction(__split_buffer* __parent, pointer __p, size_type __n) noexcept
+ : __pos_(__p),
+ __end_(__p + __n),
+ __parent_(__parent) {}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI ~_ConstructTransaction() { *__dest_ = __pos_; }
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI ~_ConstructTransaction() {
+ __parent_->__data_.__update_sentinel(__pos_);
+ }
pointer __pos_;
const pointer __end_;
private:
- pointer* __dest_;
+ __split_buffer* __parent_;
};
};
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 bool __split_buffer<_Tp, _Allocator>::__invariants() const {
- if (__first_ == nullptr) {
- if (__begin_ != nullptr)
- return false;
- if (__end_ != nullptr)
- return false;
- if (__cap_ != nullptr)
- return false;
- } else {
- if (__begin_ < __first_)
- return false;
- if (__end_ < __begin_)
- return false;
- if (__cap_ < __end_)
- return false;
- }
- return true;
+ return __data_.__invariants();
}
-// Default constructs __n objects starting at __end_
+// Default constructs __n objects starting at `__begin_ + size()`
// throws if construction throws
// Precondition: __n > 0
// Precondition: size() + __n <= capacity()
// Postcondition: size() == size() + __n
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator>::__construct_at_end(size_type __n) {
- _ConstructTransaction __tx(std::addressof(this->__end_), __n);
+ _ConstructTransaction __tx(this, __data_.end(), __n);
for (; __tx.__pos_ != __tx.__end_; ++__tx.__pos_) {
- __alloc_traits::construct(__alloc_, std::__to_address(__tx.__pos_));
+ __alloc_traits::construct(__data_.__alloc_, std::__to_address(__tx.__pos_));
}
}
-// Copy constructs __n objects starting at __end_ from __x
+// Copy constructs __n objects starting at `__begin_ + size()` from __x
// throws if construction throws
// Precondition: __n > 0
// Precondition: size() + __n <= capacity()
@@ -253,30 +464,35 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator>::__construct_
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 void
__split_buffer<_Tp, _Allocator>::__construct_at_end(size_type __n, const_reference __x) {
- _ConstructTransaction __tx(std::addressof(this->__end_), __n);
+ _ConstructTransaction __tx(this, __data_.end(), __n);
for (; __tx.__pos_ != __tx.__end_; ++__tx.__pos_) {
- __alloc_traits::construct(__alloc_, std::__to_address(__tx.__pos_), __x);
+ __alloc_traits::construct(__data_.__alloc_, std::__to_address(__tx.__pos_), __x);
}
}
-template <class _Tp, class _Allocator>
-template <class _Iterator, class _Sentinel>
+template<class _Tp, class _Allocator>
+template<class _Iterator, class _Sentinel>
_LIBCPP_CONSTEXPR_SINCE_CXX20 void
__split_buffer<_Tp, _Allocator>::__construct_at_end_with_sentinel(_Iterator __first, _Sentinel __last) {
- __alloc_rr& __a = __alloc_;
+ __alloc_rr& __a = __data_.__alloc_;
for (; __first != __last; ++__first) {
- if (__end_ == __cap_) {
- size_type __old_cap = __cap_ - __first_;
+ if (__data_.__back_spare() == 0) {
+ size_type __old_cap = __data_.capacity();
size_type __new_cap = std::max<size_type>(2 * __old_cap, 8);
__split_buffer __buf(__new_cap, 0, __a);
- for (pointer __p = __begin_; __p != __end_; ++__p, (void)++__buf.__end_)
- __alloc_traits::construct(__buf.__alloc_, std::__to_address(__buf.__end_), std::move(*__p));
+ pointer __buf_end = __buf.__data_.end();
+ pointer __end = __data_.end();
+ for (pointer __p = __data_.__begin_; __p != __end; ++__p, (void)++__buf_end)
+ __alloc_traits::construct(__buf.__data_.__alloc_, std::__to_address(__buf_end), std::move(*__p));
+ __buf.__data_.__update_sentinel(__buf_end);
swap(__buf);
}
- __alloc_traits::construct(__a, std::__to_address(this->__end_), *__first);
- ++this->__end_;
+
+ __alloc_traits::construct(__a, std::__to_address(__data_.end()), *__first);
+ __data_.__update_sentinel(size() + 1);
}
}
+
template <class _Tp, class _Allocator>
template <class _ForwardIterator, __enable_if_t<__has_forward_iterator_category<_ForwardIterator>::value, int> >
_LIBCPP_CONSTEXPR_SINCE_CXX20 void
@@ -288,92 +504,82 @@ template <class _Tp, class _Allocator>
template <class _ForwardIterator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 void
__split_buffer<_Tp, _Allocator>::__construct_at_end_with_size(_ForwardIterator __first, size_type __n) {
- _ConstructTransaction __tx(std::addressof(this->__end_), __n);
+ _ConstructTransaction __tx(this, __data_.end(), __n);
for (; __tx.__pos_ != __tx.__end_; ++__tx.__pos_, (void)++__first) {
- __alloc_traits::construct(__alloc_, std::__to_address(__tx.__pos_), *__first);
+ __alloc_traits::construct(__data_.__alloc_, std::__to_address(__tx.__pos_), *__first);
}
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 inline void
__split_buffer<_Tp, _Allocator>::__destruct_at_begin(pointer __new_begin, false_type) {
- while (__begin_ != __new_begin)
- __alloc_traits::destroy(__alloc_, std::__to_address(__begin_++));
+ pointer __begin = __data_.__begin_;
+ while (__begin != __new_begin)
+ __alloc_traits::destroy(__data_.__alloc_, std::__to_address(__begin++));
+ __data_.__update_begin(__begin);
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 inline void
__split_buffer<_Tp, _Allocator>::__destruct_at_begin(pointer __new_begin, true_type) {
- __begin_ = __new_begin;
+ __data_.__update_begin(__new_begin);
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI void
__split_buffer<_Tp, _Allocator>::__destruct_at_end(pointer __new_last, false_type) _NOEXCEPT {
- while (__new_last != __end_)
- __alloc_traits::destroy(__alloc_, std::__to_address(--__end_));
-}
-
-template <class _Tp, class _Allocator>
-_LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI void
-__split_buffer<_Tp, _Allocator>::__destruct_at_end(pointer __new_last, true_type) _NOEXCEPT {
- __end_ = __new_last;
+ pointer __end = __data_.end();
+ while (__new_last != __end)
+ __alloc_traits::destroy(__data_.__alloc_, std::__to_address(--__end));
+ __data_.__update_sentinel(__end);
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20
__split_buffer<_Tp, _Allocator>::__split_buffer(size_type __cap, size_type __start, __alloc_rr& __a)
- : __cap_(nullptr), __alloc_(__a) {
- if (__cap == 0) {
- __first_ = nullptr;
- } else {
- auto __allocation = std::__allocate_at_least(__alloc_, __cap);
- __first_ = __allocation.ptr;
- __cap = __allocation.count;
+ : __data_(__a) {
+ _LIBCPP_ASSERT(__cap >= __start, "can't have a start point outside the capacity");
+ if (__cap > 0) {
+ auto __allocation = std::__allocate_at_least(__data_.__alloc_, __cap);
+ __data_.__first_ = __allocation.ptr;
+ __cap = __allocation.count;
}
- __begin_ = __end_ = __first_ + __start;
- __cap_ = __first_ + __cap;
+
+ __data_.__begin_ = __data_.__first_ + __start;
+ __data_.__update_sentinel(__data_.__begin_);
+ __data_.__update_capacity(__cap);
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 __split_buffer<_Tp, _Allocator>::~__split_buffer() {
clear();
- if (__first_)
- __alloc_traits::deallocate(__alloc_, __first_, capacity());
+ if (__data_.__first_)
+ __alloc_traits::deallocate(__data_.__alloc_, __data_.__first_, capacity());
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 __split_buffer<_Tp, _Allocator>::__split_buffer(__split_buffer&& __c)
_NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value)
- : __first_(std::move(__c.__first_)),
- __begin_(std::move(__c.__begin_)),
- __end_(std::move(__c.__end_)),
- __cap_(std::move(__c.__cap_)),
- __alloc_(std::move(__c.__alloc_)) {
- __c.__first_ = nullptr;
- __c.__begin_ = nullptr;
- __c.__end_ = nullptr;
- __c.__cap_ = nullptr;
+ : __data_(std::move(__c.__data_)) {
+ __c.__data_.__reset();
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20
__split_buffer<_Tp, _Allocator>::__split_buffer(__split_buffer&& __c, const __alloc_rr& __a)
- : __cap_(nullptr), __alloc_(__a) {
- if (__a == __c.__alloc_) {
- __first_ = __c.__first_;
- __begin_ = __c.__begin_;
- __end_ = __c.__end_;
- __cap_ = __c.__cap_;
- __c.__first_ = nullptr;
- __c.__begin_ = nullptr;
- __c.__end_ = nullptr;
- __c.__cap_ = nullptr;
+ : __data_(__a) {
+ if (__a == __c.__data_.__alloc_) {
+ __data_.__first_ = __c.__data_.__first_;
+ __data_.__begin_ = __c.__data_.__begin_;
+ __data_.__update_sentinel(__c.__data_.end());
+ __data_.__update_capacity(__c.__data_.capacity());
+ __c.__data_.__reset();
} else {
- auto __allocation = std::__allocate_at_least(__alloc_, __c.size());
- __first_ = __allocation.ptr;
- __begin_ = __end_ = __first_;
- __cap_ = __first_ + __allocation.count;
+ auto __allocation = std::__allocate_at_least(__data_.__alloc_, __c.size());
+ __data_.__first_ = __allocation.ptr;
+ __data_.__begin_ = __data_.__first_;
+ __data_.__update_sentinel(__data_.__first_);
+ __data_.__update_capacity(__allocation.count);
typedef move_iterator<iterator> _Ip;
__construct_at_end(_Ip(__c.begin()), _Ip(__c.end()));
}
@@ -387,23 +593,16 @@ __split_buffer<_Tp, _Allocator>::operator=(__split_buffer&& __c)
!__alloc_traits::propagate_on_container_move_assignment::value) {
clear();
shrink_to_fit();
- __first_ = __c.__first_;
- __begin_ = __c.__begin_;
- __end_ = __c.__end_;
- __cap_ = __c.__cap_;
+ __data_.__copy_without_alloc(__c.__data_);
__move_assign_alloc(__c, integral_constant<bool, __alloc_traits::propagate_on_container_move_assignment::value>());
- __c.__first_ = __c.__begin_ = __c.__end_ = __c.__cap_ = nullptr;
+ __c.__data_.__reset();
return *this;
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator>::swap(__split_buffer& __x)
_NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || __is_nothrow_swappable_v<__alloc_rr>) {
- std::swap(__first_, __x.__first_);
- std::swap(__begin_, __x.__begin_);
- std::swap(__end_, __x.__end_);
- std::swap(__cap_, __x.__cap_);
- std::__swap_allocator(__alloc_, __x.__alloc_);
+ __data_.swap(__x.__data_);
}
template <class _Tp, class _Allocator>
@@ -412,14 +611,11 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator>::shrink_to_fi
#if _LIBCPP_HAS_EXCEPTIONS
try {
#endif // _LIBCPP_HAS_EXCEPTIONS
- __split_buffer<value_type, __alloc_rr&> __t(size(), 0, __alloc_);
+ __split_buffer<value_type, __alloc_rr&> __t(size(), 0, __data_.__alloc_);
if (__t.capacity() < capacity()) {
- __t.__construct_at_end(move_iterator<pointer>(__begin_), move_iterator<pointer>(__end_));
- __t.__end_ = __t.__begin_ + (__end_ - __begin_);
- std::swap(__first_, __t.__first_);
- std::swap(__begin_, __t.__begin_);
- std::swap(__end_, __t.__end_);
- std::swap(__cap_, __t.__cap_);
+ __t.__construct_at_end(move_iterator<pointer>(__data_.__begin_), move_iterator<pointer>(__data_.end()));
+ __t.__data_.__update_sentinel(__data_.size());
+ __data_.__swap_without_allocator(__t.__data_);
}
#if _LIBCPP_HAS_EXCEPTIONS
} catch (...) {
@@ -431,52 +627,61 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator>::shrink_to_fi
template <class _Tp, class _Allocator>
template <class... _Args>
_LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator>::emplace_front(_Args&&... __args) {
- if (__begin_ == __first_) {
- if (__end_ < __cap_) {
- difference_type __d = __cap_ - __end_;
+ if (__data_.__begin_ == __data_.__first_) {
+ pointer __end = __data_.end();
+ if (__data_.__front_spare() != 0) {
+ difference_type __d = __data_.__back_spare();
__d = (__d + 1) / 2;
- __begin_ = std::move_backward(__begin_, __end_, __end_ + __d);
- __end_ += __d;
+ __data_.__begin_ = std::move_backward(__data_.__begin_, __end, __end + __d);
+#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+ // TODO: explain why there isn't a size-based analogue
+#else
+ __data_.__end_ += __d;
+#endif
} else {
- size_type __c = std::max<size_type>(2 * static_cast<size_type>(__cap_ - __first_), 1);
- __split_buffer<value_type, __alloc_rr&> __t(__c, (__c + 3) / 4, __alloc_);
- __t.__construct_at_end(move_iterator<pointer>(__begin_), move_iterator<pointer>(__end_));
- std::swap(__first_, __t.__first_);
- std::swap(__begin_, __t.__begin_);
- std::swap(__end_, __t.__end_);
- std::swap(__cap_, __t.__cap_);
+ size_type __c = std::max<size_type>(2 * capacity(), 1);
+ __split_buffer<value_type, __alloc_rr&> __t(__c, (__c + 3) / 4, __data_.__alloc_);
+ __t.__construct_at_end(move_iterator<pointer>(__data_.__begin_), move_iterator<pointer>(__end));
+ __data_.__swap_without_allocator(__t.__data_);
}
}
- __alloc_traits::construct(__alloc_, std::__to_address(__begin_ - 1), std::forward<_Args>(__args)...);
- --__begin_;
+
+ __alloc_traits::construct(__data_.__alloc_, std::__to_address(__data_.__begin_ - 1), std::forward<_Args>(__args)...);
+ --__data_.__begin_;
+#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+ __data_.__update_sentinel(__data_.end() + 1);
+#else
+ // TODO: explain why there isn't a pointer-based analogue
+#endif
}
-template <class _Tp, class _Allocator>
-template <class... _Args>
+template<class _Tp, class _Allocator>
+template<class... _Args>
_LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator>::emplace_back(_Args&&... __args) {
- if (__end_ == __cap_) {
- if (__begin_ > __first_) {
- difference_type __d = __begin_ - __first_;
+ pointer __end = __data_.end();
+ if (__data_.__back_spare() == 0) {
+ if (__data_.__begin_ > __data_.__first_) {
+ difference_type __d = __data_.__begin_ - __data_.__first_;
__d = (__d + 1) / 2;
- __end_ = std::move(__begin_, __end_, __begin_ - __d);
- __begin_ -= __d;
+ __end = std::move(__data_.__begin_, __end, __data_.__begin_ - __d);
+ __data_.__begin_ -= __d;
+ __data_.__update_sentinel(__end);
} else {
- size_type __c = std::max<size_type>(2 * static_cast<size_type>(__cap_ - __first_), 1);
- __split_buffer<value_type, __alloc_rr&> __t(__c, __c / 4, __alloc_);
- __t.__construct_at_end(move_iterator<pointer>(__begin_), move_iterator<pointer>(__end_));
- std::swap(__first_, __t.__first_);
- std::swap(__begin_, __t.__begin_);
- std::swap(__end_, __t.__end_);
- std::swap(__cap_, __t.__cap_);
+ size_type __c = std::max<size_type>(2 * capacity(), 1);
+ __split_buffer<value_type, __alloc_rr&> __t(__c, __c / 4, __data_.__alloc_);
+ __t.__construct_at_end(move_iterator<pointer>(__data_.__begin_), move_iterator<pointer>(__end));
+ __data_.__swap_without_allocator(__t.__data_);
}
}
- __alloc_traits::construct(__alloc_, std::__to_address(__end_), std::forward<_Args>(__args)...);
- ++__end_;
+
+ __alloc_traits::construct(__data_.__alloc_, std::__to_address(__end), std::forward<_Args>(__args)...);
+ __data_.__update_sentinel(++__end);
}
-template <class _Tp, class _Allocator>
+template<class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI void
-swap(__split_buffer<_Tp, _Allocator>& __x, __split_buffer<_Tp, _Allocator>& __y) _NOEXCEPT_(_NOEXCEPT_(__x.swap(__y))) {
+swap(__split_buffer<_Tp, _Allocator>& __x, __split_buffer<_Tp, _Allocator>& __y) _NOEXCEPT_(_NOEXCEPT_(__x.swap(__y)))
+{
__x.swap(__y);
}
diff --git a/libcxx/include/__vector/vector.h b/libcxx/include/__vector/vector.h
index 4e0d76fbbe3de..0aec0e21cdece 100644
--- a/libcxx/include/__vector/vector.h
+++ b/libcxx/include/__vector/vector.h
@@ -841,15 +841,16 @@ template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 void
vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer<value_type, allocator_type&>& __v) {
__annotate_delete();
- auto __new_begin = __v.__begin_ - (__end_ - __begin_);
+ auto __new_begin = __v.begin() - size();
std::__uninitialized_allocator_relocate(
this->__alloc_, std::__to_address(__begin_), std::__to_address(__end_), std::__to_address(__new_begin));
- __v.__begin_ = __new_begin;
+ __v.__data_.__begin_ = __new_begin;
__end_ = __begin_; // All the objects have been destroyed by relocating them.
- std::swap(this->__begin_, __v.__begin_);
- std::swap(this->__end_, __v.__end_);
- std::swap(this->__cap_, __v.__cap_);
- __v.__first_ = __v.__begin_;
+
+ std::swap(this->__begin_, __v.__data_.__begin_);
+ std::swap(this->__end_, __v.__data_.__end_);
+ std::swap(this->__cap_, __v.__data_.__cap_);
+ __v.__data_.__first_ = __v.begin();
__annotate_new(size());
}
@@ -861,25 +862,25 @@ 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) {
__annotate_delete();
- pointer __ret = __v.__begin_;
+ pointer __ret = __v.begin();
// Relocate [__p, __end_) first to avoid having a hole in [__begin_, __end_)
// in case something in [__begin_, __p) throws.
std::__uninitialized_allocator_relocate(
- this->__alloc_, std::__to_address(__p), std::__to_address(__end_), std::__to_address(__v.__end_));
- __v.__end_ += (__end_ - __p);
+ this->__alloc_, std::__to_address(__p), std::__to_address(__end_), std::__to_address(__v.end()));
+ auto __relocated_so_far = __end_ - __p;
+ __v.__data_.__update_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_);
+ auto __new_begin = __v.begin() - (__p - __begin_);
std::__uninitialized_allocator_relocate(
this->__alloc_, std::__to_address(__begin_), std::__to_address(__p), std::__to_address(__new_begin));
- __v.__begin_ = __new_begin;
+ __v.__data_.__begin_ = __new_begin;
__end_ = __begin_; // All the objects have been destroyed by relocating them.
-
- std::swap(this->__begin_, __v.__begin_);
- std::swap(this->__end_, __v.__end_);
- std::swap(this->__cap_, __v.__cap_);
- __v.__first_ = __v.__begin_;
+ std::swap(this->__begin_, __v.__data_.__begin_);
+ std::swap(this->__end_, __v.__data_.__end_);
+ std::swap(this->__cap_, __v.__data_.__cap_);
+ __v.__data_.__first_ = __v.begin();
__annotate_new(size());
return __ret;
}
@@ -1127,8 +1128,9 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::pointer
vector<_Tp, _Allocator>::__emplace_back_slow_path(_Args&&... __args) {
__split_buffer<value_type, allocator_type&> __v(__recommend(size() + 1), size(), this->__alloc_);
// __v.emplace_back(std::forward<_Args>(__args)...);
- __alloc_traits::construct(this->__alloc_, std::__to_address(__v.__end_), std::forward<_Args>(__args)...);
- __v.__end_++;
+ pointer __end = __v.end();
+ __alloc_traits::construct(this->__alloc_, std::__to_address(__end), std::forward<_Args>(__args)...);
+ __v.__data_.__update_sentinel(++__end);
__swap_out_circular_buffer(__v);
return this->__end_;
}
@@ -1303,14 +1305,14 @@ vector<_Tp, _Allocator>::__insert_with_sentinel(const_iterator __position, _Inpu
__split_buffer<value_type, allocator_type&> __merged(
__recommend(size() + __v.size()), __off, __alloc_); // has `__off` positions available at the front
std::__uninitialized_allocator_relocate(
- __alloc_, std::__to_address(__old_last), std::__to_address(this->__end_), std::__to_address(__merged.__end_));
+ __alloc_, std::__to_address(__old_last), std::__to_address(this->__end_), std::__to_address(__merged.end()));
__guard.__complete(); // Release the guard once objects in [__old_last_, __end_) have been successfully relocated.
- __merged.__end_ += this->__end_ - __old_last;
+ __merged.__data_.__update_sentinel(__merged.end() + (this->__end_ - __old_last));
this->__end_ = __old_last;
std::__uninitialized_allocator_relocate(
- __alloc_, std::__to_address(__v.__begin_), std::__to_address(__v.__end_), std::__to_address(__merged.__end_));
- __merged.__end_ += __v.size();
- __v.__end_ = __v.__begin_;
+ __alloc_, std::__to_address(__v.begin()), std::__to_address(__v.end()), std::__to_address(__merged.end()));
+ __merged.__data_.__update_sentinel(__merged.size() + __v.size());
+ __v.__data_.__update_sentinel(__v.begin());
__p = __swap_out_circular_buffer(__merged, __p);
}
return __make_iter(__p);
diff --git a/libcxx/include/deque b/libcxx/include/deque
index d8645d06ae59e..2545622f53740 100644
--- a/libcxx/include/deque
+++ b/libcxx/include/deque
@@ -1240,7 +1240,7 @@ private:
shrink_to_fit();
}
__alloc() = __c.__alloc();
- __map_.__alloc_ = __c.__map_.__alloc_;
+ __map_.__data_.__alloc_ = __c.__map_.__data_.__alloc_;
}
_LIBCPP_HIDE_FROM_ABI void __copy_assign_alloc(const deque&, false_type) {}
@@ -1319,7 +1319,7 @@ deque<_Tp, _Allocator>::deque(const deque& __c)
: __map_(__pointer_allocator(__alloc_traits::select_on_container_copy_construction(__c.__alloc()))),
__start_(0),
__size_(0),
- __alloc_(__map_.__alloc_) {
+ __alloc_(__map_.__data_.__alloc_) {
__annotate_new(0);
__append(__c.begin(), __c.end());
}
@@ -2058,7 +2058,7 @@ void deque<_Tp, _Allocator>::__add_front_capacity() {
else if (__map_.size() < __map_.capacity()) { // we can put the new buffer into the map, but don't shift things around
// until all buffers are allocated. If we throw, we don't need to fix
// anything up (any added buffers are undetectible)
- if (__map_.__front_spare() > 0)
+ if (__map_.__data_.__front_spare() > 0)
__map_.emplace_front(__alloc_traits::allocate(__a, __block_size));
else {
__map_.emplace_back(__alloc_traits::allocate(__a, __block_size));
@@ -2072,7 +2072,7 @@ void deque<_Tp, _Allocator>::__add_front_capacity() {
// Else need to allocate 1 buffer, *and* we need to reallocate __map_.
else {
__split_buffer<pointer, __pointer_allocator&> __buf(
- std::max<size_type>(2 * __map_.capacity(), 1), 0, __map_.__alloc_);
+ std::max<size_type>(2 * __map_.capacity(), 1), 0, __map_.__data_.__alloc_);
typedef __allocator_destructor<_Allocator> _Dp;
unique_ptr<pointer, _Dp> __hold(__alloc_traits::allocate(__a, __block_size), _Dp(__a, __block_size));
@@ -2081,10 +2081,7 @@ void deque<_Tp, _Allocator>::__add_front_capacity() {
for (__map_pointer __i = __map_.begin(); __i != __map_.end(); ++__i)
__buf.emplace_back(*__i);
- std::swap(__map_.__first_, __buf.__first_);
- std::swap(__map_.__begin_, __buf.__begin_);
- std::swap(__map_.__end_, __buf.__end_);
- std::swap(__map_.__cap_, __buf.__cap_);
+ __map_.__data_.__swap_without_allocator(__buf.__data_);
__start_ = __map_.size() == 1 ? __block_size / 2 : __start_ + __block_size;
}
__annotate_whole_block(0, __asan_poison);
@@ -2115,7 +2112,7 @@ void deque<_Tp, _Allocator>::__add_front_capacity(size_type __n) {
// until all buffers are allocated. If we throw, we don't need to fix
// anything up (any added buffers are undetectible)
for (; __nb > 0; --__nb, __start_ += __block_size - (__map_.size() == 1)) {
- if (__map_.__front_spare() == 0)
+ if (__map_.__data_.__front_spare() == 0)
break;
__map_.emplace_front(__alloc_traits::allocate(__a, __block_size));
__annotate_whole_block(0, __asan_poison);
@@ -2135,7 +2132,7 @@ void deque<_Tp, _Allocator>::__add_front_capacity(size_type __n) {
else {
size_type __ds = (__nb + __back_capacity) * __block_size - __map_.empty();
__split_buffer<pointer, __pointer_allocator&> __buf(
- std::max<size_type>(2 * __map_.capacity(), __nb + __map_.size()), 0, __map_.__alloc_);
+ std::max<size_type>(2 * __map_.capacity(), __nb + __map_.size()), 0, __map_.__data_.__alloc_);
# if _LIBCPP_HAS_EXCEPTIONS
try {
# endif // _LIBCPP_HAS_EXCEPTIONS
@@ -2158,10 +2155,7 @@ void deque<_Tp, _Allocator>::__add_front_capacity(size_type __n) {
}
for (__map_pointer __i = __map_.begin(); __i != __map_.end(); ++__i)
__buf.emplace_back(*__i);
- std::swap(__map_.__first_, __buf.__first_);
- std::swap(__map_.__begin_, __buf.__begin_);
- std::swap(__map_.__end_, __buf.__end_);
- std::swap(__map_.__cap_, __buf.__cap_);
+ __map_.__data_.__swap_without_allocator(__buf.__data_);
__start_ += __ds;
}
}
@@ -2181,7 +2175,7 @@ void deque<_Tp, _Allocator>::__add_back_capacity() {
else if (__map_.size() < __map_.capacity()) { // we can put the new buffer into the map, but don't shift things around
// until it is allocated. If we throw, we don't need to fix
// anything up (any added buffers are undetectible)
- if (__map_.__back_spare() != 0)
+ if (__map_.__data_.__back_spare() != 0)
__map_.emplace_back(__alloc_traits::allocate(__a, __block_size));
else {
__map_.emplace_front(__alloc_traits::allocate(__a, __block_size));
@@ -2195,7 +2189,7 @@ void deque<_Tp, _Allocator>::__add_back_capacity() {
// Else need to allocate 1 buffer, *and* we need to reallocate __map_.
else {
__split_buffer<pointer, __pointer_allocator&> __buf(
- std::max<size_type>(2 * __map_.capacity(), 1), __map_.size(), __map_.__alloc_);
+ std::max<size_type>(2 * __map_.capacity(), 1), __map_.size(), __map_.__data_.__alloc_);
typedef __allocator_destructor<_Allocator> _Dp;
unique_ptr<pointer, _Dp> __hold(__alloc_traits::allocate(__a, __block_size), _Dp(__a, __block_size));
@@ -2204,10 +2198,7 @@ void deque<_Tp, _Allocator>::__add_back_capacity() {
for (__map_pointer __i = __map_.end(); __i != __map_.begin();)
__buf.emplace_front(*--__i);
- std::swap(__map_.__first_, __buf.__first_);
- std::swap(__map_.__begin_, __buf.__begin_);
- std::swap(__map_.__end_, __buf.__end_);
- std::swap(__map_.__cap_, __buf.__cap_);
+ __map_.__data_.__swap_without_allocator(__buf.__data_);
__annotate_whole_block(__map_.size() - 1, __asan_poison);
}
}
@@ -2237,7 +2228,7 @@ void deque<_Tp, _Allocator>::__add_back_capacity(size_type __n) {
// until all buffers are allocated. If we throw, we don't need to fix
// anything up (any added buffers are undetectible)
for (; __nb > 0; --__nb) {
- if (__map_.__back_spare() == 0)
+ if (__map_.__data_.__back_spare() == 0)
break;
__map_.emplace_back(__alloc_traits::allocate(__a, __block_size));
__annotate_whole_block(__map_.size() - 1, __asan_poison);
@@ -2260,7 +2251,7 @@ void deque<_Tp, _Allocator>::__add_back_capacity(size_type __n) {
__split_buffer<pointer, __pointer_allocator&> __buf(
std::max<size_type>(2 * __map_.capacity(), __nb + __map_.size()),
__map_.size() - __front_capacity,
- __map_.__alloc_);
+ __map_.__data_.__alloc_);
# if _LIBCPP_HAS_EXCEPTIONS
try {
# endif // _LIBCPP_HAS_EXCEPTIONS
@@ -2283,10 +2274,7 @@ void deque<_Tp, _Allocator>::__add_back_capacity(size_type __n) {
}
for (__map_pointer __i = __map_.end(); __i != __map_.begin();)
__buf.emplace_front(*--__i);
- std::swap(__map_.__first_, __buf.__first_);
- std::swap(__map_.__begin_, __buf.__begin_);
- std::swap(__map_.__end_, __buf.__end_);
- std::swap(__map_.__cap_, __buf.__cap_);
+ __map_.__data_.__swap_without_allocator(__buf.__data_);
__start_ -= __ds;
}
}
>From 13551cb4f2fa16c6322b9acb67e5b201c6f70af3 Mon Sep 17 00:00:00 2001
From: Christopher Di Bella <cjdb at google.com>
Date: Tue, 13 May 2025 18:31:30 +0000
Subject: [PATCH 2/5] fixes CI issues
---
libcxx/include/__split_buffer | 54 ++++++++++++++---------------
libcxx/utils/gdb/libcxx/printers.py | 2 +-
2 files changed, 28 insertions(+), 28 deletions(-)
diff --git a/libcxx/include/__split_buffer b/libcxx/include/__split_buffer
index 9710dfec774f7..0cd1a0e360c59 100644
--- a/libcxx/include/__split_buffer
+++ b/libcxx/include/__split_buffer
@@ -97,21 +97,21 @@ public:
: __alloc_(__alloc)
{}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer first() noexcept {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer first() _NOEXCEPT {
return __first_;
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_pointer first() const noexcept {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_pointer first() const _NOEXCEPT {
return __first_;
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer begin() noexcept {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer begin() _NOEXCEPT {
return __begin_;
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_pointer begin() const noexcept {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_pointer begin() const _NOEXCEPT {
return __begin_;
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer end() noexcept {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer end() _NOEXCEPT {
#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
return __begin_ + __size_;
#else
@@ -119,7 +119,7 @@ public:
#endif
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer end() const noexcept {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer end() const _NOEXCEPT {
#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
return __begin_ + __size_;
#else
@@ -127,7 +127,7 @@ public:
#endif
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type size() const noexcept {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT {
#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
return __size_;
#else
@@ -135,7 +135,7 @@ public:
#endif
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool empty() const noexcept {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool empty() const _NOEXCEPT {
#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
return __size_ == 0;
#else
@@ -143,7 +143,7 @@ public:
#endif
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type capacity() const noexcept {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type capacity() const _NOEXCEPT {
#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
return __cap_;
#else
@@ -151,7 +151,7 @@ public:
#endif
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer __capacity_as_pointer() noexcept {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer __capacity_as_pointer() _NOEXCEPT {
#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
return __first_ + __cap_;
#else
@@ -159,7 +159,7 @@ public:
#endif
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer __capacity_as_pointer() const noexcept {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer __capacity_as_pointer() const _NOEXCEPT {
#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
return __first_ + __cap_;
#else
@@ -167,7 +167,7 @@ public:
#endif
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __update_begin(pointer __new_begin) noexcept {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __update_begin(pointer __new_begin) _NOEXCEPT {
#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
__size_ -= __new_begin - __begin_;
#else
@@ -177,11 +177,11 @@ public:
__begin_ = __new_begin;
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __front_spare() const noexcept {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __front_spare() const _NOEXCEPT {
return static_cast<size_type>(__begin_ - __first_);
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __update_sentinel(pointer __new_end) noexcept {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __update_sentinel(pointer __new_end) _NOEXCEPT {
_LIBCPP_ASSERT(__first_ <= __new_end, "__new_end cannot precede __first_");
#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
__size_ += __new_end - end();
@@ -190,7 +190,7 @@ public:
#endif
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __update_sentinel(size_type __new_size) noexcept {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __update_sentinel(size_type __new_size) _NOEXCEPT {
#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
__size_ = __new_size;
#else
@@ -198,7 +198,7 @@ public:
#endif
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __update_capacity(size_type __new_capacity) noexcept {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __update_capacity(size_type __new_capacity) _NOEXCEPT {
#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
__cap_ = __new_capacity;
#else
@@ -206,7 +206,7 @@ public:
#endif
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __back_spare() const noexcept {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __back_spare() const _NOEXCEPT {
#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
// `__cap_ - __end_` tells us the total number of spares when in size-mode. We need to remove
// the __front_spare from the count.
@@ -216,7 +216,7 @@ public:
#endif
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference back() noexcept {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference back() _NOEXCEPT {
#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
return __begin_[__size_ - 1];
#else
@@ -224,7 +224,7 @@ public:
#endif
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference back() const noexcept {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference back() const _NOEXCEPT {
#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
return __begin_[__size_ - 1];
#else
@@ -233,7 +233,7 @@ public:
}
template<class _Data2>
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __swap_without_allocator(_Data2& __other) noexcept {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __swap_without_allocator(_Data2& __other) _NOEXCEPT {
std::swap(__first_, __other.__first_);
std::swap(__begin_, __other.__begin_);
std::swap(__cap_, __other.__cap_);
@@ -244,12 +244,12 @@ public:
#endif
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void swap(__data& __other) noexcept {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void swap(__data& __other) _NOEXCEPT {
__swap_without_allocator(__other);
std::__swap_allocator(__alloc_, __other.__alloc_);
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __invariants() const noexcept {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __invariants() const _NOEXCEPT {
if (__first_ == nullptr) {
if (__begin_ != nullptr) {
return false;
@@ -281,7 +281,7 @@ public:
return true;
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __is_full() const noexcept {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __is_full() const _NOEXCEPT {
#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
return __size_ == __cap_;
#else
@@ -289,7 +289,7 @@ public:
#endif
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __reset() noexcept {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __reset() _NOEXCEPT {
__first_ = nullptr;
__begin_ = nullptr;
#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
@@ -302,7 +302,7 @@ public:
}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __copy_without_alloc(__data const& __other)
- noexcept(is_nothrow_copy_assignable<pointer>::value)
+ _NOEXCEPT_(is_nothrow_copy_assignable<pointer>::value)
{
__first_ = __other.__first_;
__begin_ = __other.__begin_;
@@ -322,7 +322,7 @@ public:
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __split_buffer()
_NOEXCEPT_(is_nothrow_default_constructible<allocator_type>::value)
- : __data_{}
+ : __data_()
{}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __split_buffer(__alloc_rr& __a)
@@ -420,7 +420,7 @@ private:
struct _ConstructTransaction {
_LIBCPP_CONSTEXPR_SINCE_CXX20
- _LIBCPP_HIDE_FROM_ABI explicit _ConstructTransaction(__split_buffer* __parent, pointer __p, size_type __n) noexcept
+ _LIBCPP_HIDE_FROM_ABI explicit _ConstructTransaction(__split_buffer* __parent, pointer __p, size_type __n) _NOEXCEPT
: __pos_(__p),
__end_(__p + __n),
__parent_(__parent) {}
diff --git a/libcxx/utils/gdb/libcxx/printers.py b/libcxx/utils/gdb/libcxx/printers.py
index 31c27a1959cb2..8194f584ea137 100644
--- a/libcxx/utils/gdb/libcxx/printers.py
+++ b/libcxx/utils/gdb/libcxx/printers.py
@@ -426,7 +426,7 @@ class StdDequePrinter(object):
def __init__(self, val):
self.val = val
self.size = int(val["__size_"])
- self.start_ptr = self.val["__map_"]["__begin_"]
+ self.start_ptr = self.val["__map_"]["__data_"]["__begin_"]
self.first_block_start_index = int(self.val["__start_"])
self.node_type = self.start_ptr.type
self.block_size = self._calculate_block_size(val.type.template_argument(0))
>From 6d3ec2b72a51d032fa81f52e29066f274b31fc5b Mon Sep 17 00:00:00 2001
From: Christopher Di Bella <cjdb at google.com>
Date: Tue, 27 May 2025 17:51:55 +0000
Subject: [PATCH 3/5] applies suggestions
---
libcxx/include/__split_buffer | 86 ++++++++++++-----------------------
1 file changed, 29 insertions(+), 57 deletions(-)
diff --git a/libcxx/include/__split_buffer b/libcxx/include/__split_buffer
index 0cd1a0e360c59..e9bad689992c0 100644
--- a/libcxx/include/__split_buffer
+++ b/libcxx/include/__split_buffer
@@ -83,12 +83,13 @@ public:
struct __data {
pointer __first_ = nullptr;
pointer __begin_ = nullptr;
-#ifndef _LIBCPP_ABI_SIZE_BASED_VECTOR
+#ifdef _LIBCPP_ABI_SIZE_BASED_CONTAINERS
+ size_type __size_ = 0;
+ size_type __cap_ = 0;
+ allocator_type __alloc_;
+#else
pointer __end_ = nullptr;
_LIBCPP_COMPRESSED_PAIR(pointer, __cap_ = nullptr, allocator_type, __alloc_);
-#else
- size_type __size_ = 0;
- _LIBCPP_COMPRESSED_PAIR(size_type, __cap_ = 0, allocator_type, __alloc_);
#endif
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __data() = default;
@@ -97,13 +98,6 @@ public:
: __alloc_(__alloc)
{}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer first() _NOEXCEPT {
- return __first_;
- }
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_pointer first() const _NOEXCEPT {
- return __first_;
- }
-
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer begin() _NOEXCEPT {
return __begin_;
}
@@ -112,7 +106,7 @@ public:
}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer end() _NOEXCEPT {
-#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+#ifdef _LIBCPP_ABI_SIZE_BASED_CONTAINERS
return __begin_ + __size_;
#else
return __end_;
@@ -120,7 +114,7 @@ public:
}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer end() const _NOEXCEPT {
-#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+#ifdef _LIBCPP_ABI_SIZE_BASED_CONTAINERS
return __begin_ + __size_;
#else
return __end_;
@@ -128,7 +122,7 @@ public:
}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT {
-#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+#ifdef _LIBCPP_ABI_SIZE_BASED_CONTAINERS
return __size_;
#else
return static_cast<size_type>(__end_ - __begin_);
@@ -136,7 +130,7 @@ public:
}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool empty() const _NOEXCEPT {
-#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+#ifdef _LIBCPP_ABI_SIZE_BASED_CONTAINERS
return __size_ == 0;
#else
return __begin_ == __end_;
@@ -144,31 +138,15 @@ public:
}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type capacity() const _NOEXCEPT {
-#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+#ifdef _LIBCPP_ABI_SIZE_BASED_CONTAINERS
return __cap_;
#else
return static_cast<size_type>(__cap_ - __first_);
#endif
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer __capacity_as_pointer() _NOEXCEPT {
-#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
- return __first_ + __cap_;
-#else
- return __cap_;
-#endif
- }
-
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer __capacity_as_pointer() const _NOEXCEPT {
-#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
- return __first_ + __cap_;
-#else
- return __cap_;
-#endif
- }
-
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __update_begin(pointer __new_begin) _NOEXCEPT {
-#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+#ifdef _LIBCPP_ABI_SIZE_BASED_CONTAINERS
__size_ -= __new_begin - __begin_;
#else
// TODO: explain why there isn't a pointer-based analogue
@@ -183,7 +161,7 @@ public:
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __update_sentinel(pointer __new_end) _NOEXCEPT {
_LIBCPP_ASSERT(__first_ <= __new_end, "__new_end cannot precede __first_");
-#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+#ifdef _LIBCPP_ABI_SIZE_BASED_CONTAINERS
__size_ += __new_end - end();
#else
__end_ = __new_end;
@@ -191,7 +169,7 @@ public:
}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __update_sentinel(size_type __new_size) _NOEXCEPT {
-#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+#ifdef _LIBCPP_ABI_SIZE_BASED_CONTAINERS
__size_ = __new_size;
#else
__end_ = __begin_ + __new_size;
@@ -199,7 +177,7 @@ public:
}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __update_capacity(size_type __new_capacity) _NOEXCEPT {
-#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+#ifdef _LIBCPP_ABI_SIZE_BASED_CONTAINERS
__cap_ = __new_capacity;
#else
__cap_ = __first_ + __new_capacity;
@@ -207,7 +185,7 @@ public:
}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __back_spare() const _NOEXCEPT {
-#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+#ifdef _LIBCPP_ABI_SIZE_BASED_CONTAINERS
// `__cap_ - __end_` tells us the total number of spares when in size-mode. We need to remove
// the __front_spare from the count.
return __cap_ - __size_ - __front_spare();
@@ -217,7 +195,7 @@ public:
}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference back() _NOEXCEPT {
-#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+#ifdef _LIBCPP_ABI_SIZE_BASED_CONTAINERS
return __begin_[__size_ - 1];
#else
return *(__end_ - 1);
@@ -225,7 +203,7 @@ public:
}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference back() const _NOEXCEPT {
-#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+#ifdef _LIBCPP_ABI_SIZE_BASED_CONTAINERS
return __begin_[__size_ - 1];
#else
return *(__end_ - 1);
@@ -237,7 +215,7 @@ public:
std::swap(__first_, __other.__first_);
std::swap(__begin_, __other.__begin_);
std::swap(__cap_, __other.__cap_);
-#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+#ifdef _LIBCPP_ABI_SIZE_BASED_CONTAINERS
std::swap(__size_, __other.__size_);
#else
std::swap(__end_, __other.__end_);
@@ -251,38 +229,32 @@ public:
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __invariants() const _NOEXCEPT {
if (__first_ == nullptr) {
- if (__begin_ != nullptr) {
+ if (__begin_ != nullptr)
return false;
- }
- if (!empty()) {
+ if (!empty())
return false;
- }
- if (capacity() != 0) {
+ if (capacity() != 0)
return false;
- }
return true;
}
- if (__begin_ < __first_) {
+ if (__begin_ < __first_)
return false;
- }
- if (capacity() < size()) {
+ if (capacity() < size())
return false;
- }
- if (end() < __begin_) {
+ if (end() < __begin_)
return false;
- }
return true;
}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __is_full() const _NOEXCEPT {
-#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+#ifdef _LIBCPP_ABI_SIZE_BASED_CONTAINERS
return __size_ == __cap_;
#else
return __end_ == __cap_;
@@ -292,7 +264,7 @@ public:
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __reset() _NOEXCEPT {
__first_ = nullptr;
__begin_ = nullptr;
-#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+#ifdef _LIBCPP_ABI_SIZE_BASED_CONTAINERS
__size_ = 0;
__cap_ = 0;
#else
@@ -307,7 +279,7 @@ public:
__first_ = __other.__first_;
__begin_ = __other.__begin_;
__cap_ = __other.__cap_;
-#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+#ifdef _LIBCPP_ABI_SIZE_BASED_CONTAINERS
__size_ = __other.__size_;
#else
__end_ = __other.__end_;
@@ -633,7 +605,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator>::emplace_fron
difference_type __d = __data_.__back_spare();
__d = (__d + 1) / 2;
__data_.__begin_ = std::move_backward(__data_.__begin_, __end, __end + __d);
-#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+#ifdef _LIBCPP_ABI_SIZE_BASED_CONTAINERS
// TODO: explain why there isn't a size-based analogue
#else
__data_.__end_ += __d;
@@ -648,7 +620,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator>::emplace_fron
__alloc_traits::construct(__data_.__alloc_, std::__to_address(__data_.__begin_ - 1), std::forward<_Args>(__args)...);
--__data_.__begin_;
-#ifdef _LIBCPP_ABI_SIZE_BASED_VECTOR
+#ifdef _LIBCPP_ABI_SIZE_BASED_CONTAINERS
__data_.__update_sentinel(__data_.end() + 1);
#else
// TODO: explain why there isn't a pointer-based analogue
>From 7084c96db07cb60f2e63ca973730f85f09870d00 Mon Sep 17 00:00:00 2001
From: Christopher Di Bella <cjdb at google.com>
Date: Thu, 29 May 2025 21:57:15 +0000
Subject: [PATCH 4/5] updates formatting
---
libcxx/include/__split_buffer | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/libcxx/include/__split_buffer b/libcxx/include/__split_buffer
index e9bad689992c0..1e7d33fd433da 100644
--- a/libcxx/include/__split_buffer
+++ b/libcxx/include/__split_buffer
@@ -239,18 +239,18 @@ public:
return false;
return true;
- }
-
- if (__begin_ < __first_)
- return false;
+ } else {
+ if (__begin_ < __first_)
+ return false;
- if (capacity() < size())
- return false;
+ if (capacity() < size())
+ return false;
- if (end() < __begin_)
- return false;
+ if (end() < __begin_)
+ return false;
- return true;
+ return true;
+ }
}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __is_full() const _NOEXCEPT {
>From af7c901f6a457cef23677cdc82ce6d3950a4c00b Mon Sep 17 00:00:00 2001
From: Jorge Gorbe Moya <jgorbe at google.com>
Date: Tue, 3 Jun 2025 19:39:38 +0000
Subject: [PATCH 5/5] changes deque's pretty-printer to work with new
__split_buffer
---
lldb/examples/synthetic/libcxx.py | 54 ++++++++++++++++++++++++-------
1 file changed, 42 insertions(+), 12 deletions(-)
diff --git a/lldb/examples/synthetic/libcxx.py b/lldb/examples/synthetic/libcxx.py
index 5abeb3061f4f5..521bd06af5b3f 100644
--- a/lldb/examples/synthetic/libcxx.py
+++ b/lldb/examples/synthetic/libcxx.py
@@ -1,3 +1,6 @@
+from enum import Enum
+from sys import stderr
+import sys
import lldb
import lldb.formatters.Logger
@@ -74,6 +77,40 @@ def stdstring_SummaryProvider(valobj, dict):
return '"' + strval + '"'
+def get_buffer_data(parent):
+ map_valobj = parent.valobj.GetChildMemberWithName("__map_")
+ map_data = map_valobj.GetChildMemberWithName("__data_")
+ if map_data.IsValid():
+ return map_data
+
+ return map_valobj
+
+
+def get_buffer_end(buffer, begin):
+ map_end = buffer.GetChildMemberWithName("__end_")
+ if map_end.IsValid():
+ return map_end.GetValueAsUnsigned(0)
+ map_size = buffer.GetChildMemberWithName("__size_").GetValueAsUnsigned(0)
+ return begin + map_size
+
+
+def get_buffer_endcap(parent, buffer, begin, has_compressed_pair_layout, is_size_based):
+ if has_compressed_pair_layout:
+ map_endcap = parent._get_value_of_compressed_pair(
+ buffer.GetChildMemberWithName("__end_cap_")
+ )
+ else:
+ map_endcap = buffer.GetChildMemberWithName("__cap_")
+ if not map_endcap.IsValid():
+ map_endcap = buffer.GetChildMemberWithName("__end_cap_")
+ map_endcap = map_endcap.GetValueAsUnsigned(0)
+
+ if is_size_based:
+ return begin + map_endcap
+
+ return map_endcap
+
+
class stdvector_SynthProvider:
def __init__(self, valobj, dict):
logger = lldb.formatters.Logger.Logger()
@@ -755,23 +792,16 @@ def update(self):
if self.block_size < 0:
logger.write("block_size < 0")
return
- map_ = self.valobj.GetChildMemberWithName("__map_")
start = self.valobj.GetChildMemberWithName("__start_").GetValueAsUnsigned(0)
+
+ map_ = get_buffer_data(self)
+ is_size_based = map_.GetChildMemberWithName("__size_").IsValid()
first = map_.GetChildMemberWithName("__first_")
map_first = first.GetValueAsUnsigned(0)
self.map_begin = map_.GetChildMemberWithName("__begin_")
map_begin = self.map_begin.GetValueAsUnsigned(0)
- map_end = map_.GetChildMemberWithName("__end_").GetValueAsUnsigned(0)
-
- if has_compressed_pair_layout:
- map_endcap = self._get_value_of_compressed_pair(
- map_.GetChildMemberWithName("__end_cap_")
- )
- else:
- map_endcap = map_.GetChildMemberWithName("__cap_")
- if not map_endcap.IsValid():
- map_endcap = map_.GetChildMemberWithName("__end_cap_")
- map_endcap = map_endcap.GetValueAsUnsigned(0)
+ map_end = get_buffer_end(map_, map_begin)
+ map_endcap = get_buffer_endcap(self, map_, map_begin, has_compressed_pair_layout, is_size_based)
# check consistency
if not map_first <= map_begin <= map_end <= map_endcap:
More information about the libcxx-commits
mailing list