[libcxx-commits] [libcxx] [libcxx] adds size-based `__split_buffer` representation to unstable ABI (PR #139632)

Christopher Di Bella via libcxx-commits libcxx-commits at lists.llvm.org
Tue May 27 11:09:28 PDT 2025


================
@@ -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;
+    }
----------------
cjdb wrote:

Braces have been removed. I generally agree with the [LLVM style guide](https://llvm.org/docs/CodingStandards.html#don-t-use-else-after-a-return)'s position on not using else-clauses after unconditional returns, so I've left that as-is.

https://github.com/llvm/llvm-project/pull/139632


More information about the libcxx-commits mailing list