1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef _LIBCPP___VECTOR_LAYOUT_H
10#define _LIBCPP___VECTOR_LAYOUT_H
11
12#include <__assert>
13#include <__config>
14#include <__debug_utils/sanitizers.h>
15#include <__memory/allocator_traits.h>
16#include <__memory/compressed_pair.h>
17#include <__memory/pointer_traits.h>
18#include <__memory/swap_allocator.h>
19#include <__memory/uninitialized_algorithms.h>
20#include <__split_buffer>
21#include <__type_traits/is_nothrow_constructible.h>
22#include <__utility/assume.h>
23#include <__utility/exchange.h>
24#include <__utility/move.h>
25#include <__utility/swap.h>
26
27#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
28# pragma GCC system_header
29#endif
30
31_LIBCPP_PUSH_MACROS
32#include <__undef_macros>
33
34_LIBCPP_BEGIN_NAMESPACE_STD
35
36/// Defines `std::vector`'s storage layout and any operations that are affected by a change in the
37/// layout.
38///
39/// `std::vector` can be represented in a variety of ways. Each representation strongly influences
40/// the codegen when calling vector operations, which can significantly impact runtime performance
41/// and memory utilisation. libc++ provides two alternative layouts for `std::vector`, although only
42/// one can be active for an entire binary:
43///
44/// * pointer-based layout (stable ABI default)
45/// * size-based layout (unstable ABI alternative)
46//
47/// We describe these layouts below. All vector representations have a pointer that points to where
48/// the memory is allocated (called `__begin_`).
49///
50/// **Pointer-based layout**
51///
52/// The pointer-based layout uses two more pointers in addition to `__begin_`. The second pointer
53/// (called `__end_`) points past the end of the part of the buffer that holds valid elements.
54/// Another pointer (called `__capacity_`) points past the end of the allocated buffer. The original
55/// libc++ `std::vector` implementation only provided the pointer-based layout. libc++ continues to
56/// use the pointer-based layout, by default, in order to maintain binary compatibility with
57/// existing software.
58///
59/// The `__end_` pointer has three primary use-cases:
60/// * to compute the size of the vector; and
61/// * to construct the past-the-end iterator; and
62/// * to indicate where the next element should be appended.
63///
64/// The `__capacity_` is used to compute the capacity of the vector, which lets the vector know how
65/// many elements can be added to the vector before a reallocation is necessary.
66///
67/// __begin_ = 0xE4FD0, __end_ = 0xE4FF0, __capacity_ = 0xE5000
68/// 0xE4FD0 0xE4FF0 0xE5000
69/// v v v
70/// +---------------+--------+--------+--------+--------+--------+--------+---------------------+
71/// | ????????????? | 3174 | 5656 | 648 | 489 | ------ | ------ | ??????????????????? |
72/// +---------------+--------+--------+--------+--------+--------+--------+---------------------+
73/// ^ ^ ^
74/// __begin_ __end_ __capacity_
75///
76/// Figure 1: A visual representation of a pointer-based `std::vector<short>`. This vector has
77/// four elements, with the capacity to store six. Boxes with numbers are valid elements within
78/// the vector, and boxes with `xx` have been allocated, but aren't being used as elements right
79/// now.
80///
81/// This is the default layout for libc++.
82///
83/// **Size-based layout**
84///
85/// The size-based layout uses integers to track its size and capacity, and computes pointers to
86/// past-the-end of the valid range and the whole buffer only when it's necessary. Programs using
87/// the size-based layout have been measured to yield improved compute and memory performance over
88/// the pointer-based layout. Despite these promising measurements, the size-based layout is opt-in,
89/// to preserve ABI compatibility with prebuilt binaries. Given the improved performance, we
90/// recommend preferring the size-based layout in the absence of such ABI constraints.
91///
92/// __begin_ = 0xE4FD0, __size_ = 4, __capacity_ = 6
93/// 0xE4FD0
94/// v
95/// +---------------+--------+--------+--------+--------+--------+--------+---------------------+
96/// | ????????????? | 3174 | 5656 | 648 | 489 | ------ | ------ | ??????????????????? |
97/// +---------------+--------+--------+--------+--------+--------+--------+---------------------+
98/// ^
99/// __begin_
100///
101/// Figure 2: A visual representation of this a size-based layout. Blank boxes are not a part
102/// of the vector's allocated buffer.
103///
104/// **Class design**
105///
106/// __vector_layout was designed with the following goals:
107/// 1. to abstractly represent the buffer's boundaries; and
108/// 2. to limit the number of `#ifdef` blocks that a reader needs to pass through; and
109/// 3. given (1) and (2), to have no logically identical components in multiple `#ifdef` clauses.
110///
111/// To facilitate these goals, there is a single `__vector_layout` definition. Users must choose
112/// their vector's layout when libc++ is being configured, so there is no need to manage multiple
113/// vector layout types (e.g. `__vector_size_layout`, `__vector_pointer_layout`, etc.). In doing so,
114/// we reduce a significant portion of duplicate code.
115template <class _Tp, class _Allocator>
116class __vector_layout {
117public:
118 using value_type _LIBCPP_NODEBUG = _Tp;
119 using allocator_type _LIBCPP_NODEBUG = _Allocator;
120 using __alloc_traits _LIBCPP_NODEBUG = allocator_traits<allocator_type>;
121 using size_type _LIBCPP_NODEBUG = typename __alloc_traits::size_type;
122 using pointer _LIBCPP_NODEBUG = typename __alloc_traits::pointer;
123 using const_pointer _LIBCPP_NODEBUG = typename __alloc_traits::const_pointer;
124#ifdef _LIBCPP_ABI_VECTOR_LAYOUT_SIZE_BASED
125 using _SplitBuffer _LIBCPP_NODEBUG = __split_buffer<_Tp, _Allocator, __split_buffer_size_layout>;
126 using __bound_type _LIBCPP_NODEBUG = size_type;
127#else
128 using _SplitBuffer _LIBCPP_NODEBUG = __split_buffer<_Tp, _Allocator, __split_buffer_pointer_layout>;
129 using __bound_type _LIBCPP_NODEBUG = pointer;
130#endif
131
132 // Cannot be defaulted, since `_LIBCPP_COMPRESSED_PAIR` isn't an aggregate before C++14.
133 _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __vector_layout()
134 _NOEXCEPT_(is_nothrow_default_constructible<allocator_type>::value)
135 : __capacity_() {}
136
137 _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __vector_layout(allocator_type const& __a)
138 _NOEXCEPT_(is_nothrow_copy_constructible<allocator_type>::value)
139 : __capacity_(), __alloc_(__a) {}
140
141 _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __vector_layout(allocator_type&& __a)
142 _NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value)
143 : __capacity_(), __alloc_(std::move(__a)) {}
144
145 _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __vector_layout(__vector_layout&& __other)
146 _NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value);
147
148 /// Returns a reference to the stored allocator.
149 [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI allocator_type& __alloc() _NOEXCEPT {
150 return __alloc_;
151 }
152
153 [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI allocator_type const&
154 __alloc() const _NOEXCEPT {
155 return __alloc_;
156 }
157
158 /// Returns a pointer to the beginning of the buffer.
159 ///
160 /// `__begin_ptr()` is not called `data()` because `vector::data()` returns `T*`, but `__begin_`
161 /// is allowed to be a fancy pointer.
162 [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer __begin_ptr() _NOEXCEPT {
163 if _LIBCPP_CONSTEXPR (__is_std_allocator_v<allocator_type>)
164 std::__assume_separate_storage(a: this, b: std::__to_address(__begin_));
165 return __begin_;
166 }
167
168 [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_pointer __begin_ptr() const _NOEXCEPT {
169 if _LIBCPP_CONSTEXPR (__is_std_allocator_v<allocator_type>)
170 std::__assume_separate_storage(a: this, b: std::__to_address(__begin_));
171 return __begin_;
172 }
173
174 /// Returns a built-in pointer to the beginning of the buffer.
175 [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI _Tp* __data() _NOEXCEPT {
176 if _LIBCPP_CONSTEXPR (__is_std_allocator_v<allocator_type>)
177 std::__assume_separate_storage(a: this, b: std::__to_address(__begin_));
178 return std::__to_address(__begin_);
179 }
180
181 [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI _Tp const* __data() const _NOEXCEPT {
182 if _LIBCPP_CONSTEXPR (__is_std_allocator_v<allocator_type>)
183 std::__assume_separate_storage(a: this, b: std::__to_address(__begin_));
184 return std::__to_address(__begin_);
185 }
186
187 /// Returns how many elements can be added before a reallocation occurs.
188 [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type
189 __remaining_capacity() const _NOEXCEPT;
190
191 /// Sets the member pointing to the first element in the vector to `__new_begin`, the member used
192 /// to obtain the vector's bound to the equivalent of `__new_size`, and the member that represents
193 /// the vector's capacity to the equivalent to `__new_capacity`.
194 _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
195 __set_layout(pointer __new_begin, size_type __new_size, size_type __new_capacity) _NOEXCEPT;
196
197 /// Sets the member used to obtain the vector's bound to the equivalent of `__ptr`.
198 _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_bound_using_pointer(pointer __ptr) _NOEXCEPT;
199
200 _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __reset_without_allocator() _NOEXCEPT;
201 _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __swap(__vector_layout& __other) _NOEXCEPT;
202 _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
203 __move_assign_without_allocator(__vector_layout& __other) _NOEXCEPT;
204
205 _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __relocate(_SplitBuffer& __buffer);
206 _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer
207 __relocate_with_pivot(_SplitBuffer& __buffer, pointer __pivot);
208
209 [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __size() const _NOEXCEPT;
210 [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __capacity() const _NOEXCEPT;
211 [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __empty() const _NOEXCEPT;
212 [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer __end_ptr() _NOEXCEPT;
213 [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_pointer __end_ptr() const _NOEXCEPT;
214 [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer __capacity_ptr() _NOEXCEPT;
215 [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_pointer __capacity_ptr() const _NOEXCEPT;
216 [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __invariants() const _NOEXCEPT;
217
218private:
219 pointer __begin_ = nullptr;
220
221#ifdef _LIBCPP_ABI_VECTOR_LAYOUT_SIZE_BASED
222 size_type __size_ = 0;
223 size_type __capacity_ = 0;
224 _LIBCPP_NO_UNIQUE_ADDRESS allocator_type __alloc_;
225#else
226 pointer __end_ = nullptr;
227 _LIBCPP_COMPRESSED_PAIR(pointer, __capacity_ = nullptr, allocator_type, __alloc_);
228#endif
229
230 _LIBCPP_CONSTEXPR_SINCE_CXX20
231 _LIBCPP_HIDE_FROM_ABI void __annotate_contiguous_container(const void* __old_mid, const void* __new_mid) const {
232 std::__annotate_contiguous_container<_Allocator>(__data(), __data() + __capacity(), __old_mid, __new_mid);
233 }
234
235 _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __annotate_new(size_type __current_size) const _NOEXCEPT {
236 __annotate_contiguous_container(old_mid: __data() + __capacity(), new_mid: __data() + __current_size);
237 }
238
239 _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __annotate_delete() const _NOEXCEPT {
240 __annotate_contiguous_container(old_mid: __data() + __size(), new_mid: __data() + __capacity());
241 }
242};
243
244#ifdef _LIBCPP_ABI_VECTOR_LAYOUT_SIZE_BASED
245template <class _Tp, class _Alloc>
246_LIBCPP_CONSTEXPR_SINCE_CXX20 __vector_layout<_Tp, _Alloc>::__vector_layout(__vector_layout&& __other)
247 _NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value)
248 : __begin_(std::__exchange(__other.__begin_, nullptr)),
249 __size_(std::__exchange(__other.__size_, 0)),
250 __capacity_(std::__exchange(__other.__capacity_, 0)),
251 __alloc_(std::move(__other.__alloc_)) {}
252
253template <class _Tp, class _Alloc>
254_LIBCPP_CONSTEXPR_SINCE_CXX20 typename __vector_layout<_Tp, _Alloc>::size_type
255__vector_layout<_Tp, _Alloc>::__remaining_capacity() const _NOEXCEPT {
256 return __capacity_ - __size_;
257}
258
259template <class _Tp, class _Alloc>
260_LIBCPP_CONSTEXPR_SINCE_CXX20 void __vector_layout<_Tp, _Alloc>::__set_layout(
261 pointer __new_begin, size_type __new_size, size_type __new_capacity) _NOEXCEPT {
262 __begin_ = __new_begin;
263 __size_ = __new_size;
264 __capacity_ = __new_capacity;
265}
266
267template <class _Tp, class _Alloc>
268_LIBCPP_CONSTEXPR_SINCE_CXX20 void __vector_layout<_Tp, _Alloc>::__set_bound_using_pointer(pointer __ptr) _NOEXCEPT {
269 __size_ = static_cast<size_type>(__ptr - __begin_);
270}
271
272template <class _Tp, class _Alloc>
273_LIBCPP_CONSTEXPR_SINCE_CXX20 void __vector_layout<_Tp, _Alloc>::__reset_without_allocator() _NOEXCEPT {
274 __begin_ = nullptr;
275 __size_ = 0;
276 __capacity_ = 0;
277}
278
279template <class _Tp, class _Alloc>
280_LIBCPP_CONSTEXPR_SINCE_CXX20 void __vector_layout<_Tp, _Alloc>::__swap(__vector_layout& __other) _NOEXCEPT {
281 using std::swap;
282 swap(__begin_, __other.__begin_);
283 swap(__size_, __other.__size_);
284 swap(__capacity_, __other.__capacity_);
285 std::__swap_allocator(__alloc_, __other.__alloc_);
286}
287
288template <class _Tp, class _Alloc>
289_LIBCPP_CONSTEXPR_SINCE_CXX20 void
290__vector_layout<_Tp, _Alloc>::__move_assign_without_allocator(__vector_layout& __other) _NOEXCEPT {
291 __begin_ = __other.__begin_;
292 __size_ = __other.__size_;
293 __capacity_ = __other.__capacity_;
294
295 __other.__reset_without_allocator();
296}
297
298template <class _Tp, class _Alloc>
299_LIBCPP_CONSTEXPR_SINCE_CXX20 void __vector_layout<_Tp, _Alloc>::__relocate(_SplitBuffer& __buffer) {
300 __annotate_delete();
301 __buffer.__relocate(__begin_, __size_, __capacity_);
302 __annotate_new(__size_);
303}
304
305template <class _Tp, class _Alloc>
306_LIBCPP_CONSTEXPR_SINCE_CXX20 typename __vector_layout<_Tp, _Alloc>::pointer
307__vector_layout<_Tp, _Alloc>::__relocate_with_pivot(_SplitBuffer& __buffer, pointer __pivot) {
308 __annotate_delete();
309 auto __result = __buffer.__relocate_with_pivot(__pivot, __begin_, __size_, __capacity_);
310 __annotate_new(__size_);
311 return __result;
312}
313
314template <class _Tp, class _Alloc>
315_LIBCPP_CONSTEXPR_SINCE_CXX20 typename __vector_layout<_Tp, _Alloc>::size_type
316__vector_layout<_Tp, _Alloc>::__size() const _NOEXCEPT {
317 return __size_;
318}
319
320template <class _Tp, class _Alloc>
321_LIBCPP_CONSTEXPR_SINCE_CXX20 typename __vector_layout<_Tp, _Alloc>::size_type
322__vector_layout<_Tp, _Alloc>::__capacity() const _NOEXCEPT {
323 return __capacity_;
324}
325
326template <class _Tp, class _Alloc>
327_LIBCPP_CONSTEXPR_SINCE_CXX20 bool __vector_layout<_Tp, _Alloc>::__empty() const _NOEXCEPT {
328 return __size_ == 0;
329}
330
331template <class _Tp, class _Alloc>
332_LIBCPP_CONSTEXPR_SINCE_CXX20 typename __vector_layout<_Tp, _Alloc>::pointer
333__vector_layout<_Tp, _Alloc>::__end_ptr() _NOEXCEPT {
334 return __begin_ + __size_;
335}
336
337template <class _Tp, class _Alloc>
338_LIBCPP_CONSTEXPR_SINCE_CXX20 typename __vector_layout<_Tp, _Alloc>::const_pointer
339__vector_layout<_Tp, _Alloc>::__end_ptr() const _NOEXCEPT {
340 return __begin_ + __size_;
341}
342
343template <class _Tp, class _Alloc>
344_LIBCPP_CONSTEXPR_SINCE_CXX20 typename __vector_layout<_Tp, _Alloc>::pointer
345__vector_layout<_Tp, _Alloc>::__capacity_ptr() _NOEXCEPT {
346 return __begin_ + __capacity_;
347}
348
349template <class _Tp, class _Alloc>
350_LIBCPP_CONSTEXPR_SINCE_CXX20 typename __vector_layout<_Tp, _Alloc>::const_pointer
351__vector_layout<_Tp, _Alloc>::__capacity_ptr() const _NOEXCEPT {
352 return __begin_ + __capacity_;
353}
354
355template <class _Tp, class _Alloc>
356_LIBCPP_CONSTEXPR_SINCE_CXX20 bool __vector_layout<_Tp, _Alloc>::__invariants() const _NOEXCEPT {
357 if (__begin_ == nullptr)
358 return __size_ == 0 && __capacity_ == 0;
359 return __size_ <= __capacity_;
360}
361#else // !defined(_LIBCPP_ABI_VECTOR_LAYOUT_SIZE_BASED)
362template <class _Tp, class _Alloc>
363_LIBCPP_CONSTEXPR_SINCE_CXX20 __vector_layout<_Tp, _Alloc>::__vector_layout(__vector_layout&& __other)
364 _NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value)
365 : __begin_(std::__exchange(__other.__begin_, nullptr)),
366 __end_(std::__exchange(__other.__end_, nullptr)),
367 __capacity_(std::__exchange(__other.__capacity_, nullptr)),
368 __alloc_(std::move(__other.__alloc_)) {}
369
370template <class _Tp, class _Alloc>
371_LIBCPP_CONSTEXPR_SINCE_CXX20 typename __vector_layout<_Tp, _Alloc>::size_type
372__vector_layout<_Tp, _Alloc>::__remaining_capacity() const _NOEXCEPT {
373 return __capacity_ - __end_;
374}
375
376template <class _Tp, class _Alloc>
377_LIBCPP_CONSTEXPR_SINCE_CXX20 void __vector_layout<_Tp, _Alloc>::__set_layout(
378 pointer __new_begin, size_type __new_size, size_type __new_capacity) _NOEXCEPT {
379 __begin_ = __new_begin;
380 __end_ = __new_begin + __new_size;
381 __capacity_ = __new_begin + __new_capacity;
382}
383
384template <class _Tp, class _Alloc>
385_LIBCPP_CONSTEXPR_SINCE_CXX20 void __vector_layout<_Tp, _Alloc>::__set_bound_using_pointer(pointer __ptr) _NOEXCEPT {
386 __end_ = __ptr;
387}
388
389template <class _Tp, class _Alloc>
390_LIBCPP_CONSTEXPR_SINCE_CXX20 void __vector_layout<_Tp, _Alloc>::__reset_without_allocator() _NOEXCEPT {
391 __begin_ = nullptr;
392 __end_ = nullptr;
393 __capacity_ = nullptr;
394}
395
396template <class _Tp, class _Alloc>
397_LIBCPP_CONSTEXPR_SINCE_CXX20 void __vector_layout<_Tp, _Alloc>::__swap(__vector_layout& __other) _NOEXCEPT {
398 using std::swap;
399 swap(__begin_, __other.__begin_);
400 swap(__end_, __other.__end_);
401 swap(__capacity_, __other.__capacity_);
402 std::__swap_allocator(__alloc_, __other.__alloc_);
403}
404
405template <class _Tp, class _Alloc>
406_LIBCPP_CONSTEXPR_SINCE_CXX20 void
407__vector_layout<_Tp, _Alloc>::__move_assign_without_allocator(__vector_layout& __other) _NOEXCEPT {
408 __begin_ = __other.__begin_;
409 __end_ = __other.__end_;
410 __capacity_ = __other.__capacity_;
411
412 __other.__reset_without_allocator();
413}
414
415template <class _Tp, class _Alloc>
416_LIBCPP_CONSTEXPR_SINCE_CXX20 void __vector_layout<_Tp, _Alloc>::__relocate(_SplitBuffer& __buffer) {
417 __annotate_delete();
418 __buffer.__relocate(__begin_, __end_, __capacity_);
419 __annotate_new(current_size: __size());
420}
421
422template <class _Tp, class _Alloc>
423_LIBCPP_CONSTEXPR_SINCE_CXX20 typename __vector_layout<_Tp, _Alloc>::pointer
424__vector_layout<_Tp, _Alloc>::__relocate_with_pivot(_SplitBuffer& __buffer, pointer __pivot) {
425 __annotate_delete();
426 auto __result = __buffer.__relocate_with_pivot(__pivot, __begin_, __end_, __capacity_);
427 __annotate_new(current_size: __size());
428 return __result;
429}
430
431template <class _Tp, class _Alloc>
432_LIBCPP_CONSTEXPR_SINCE_CXX20 typename __vector_layout<_Tp, _Alloc>::size_type
433__vector_layout<_Tp, _Alloc>::__size() const _NOEXCEPT {
434 return static_cast<size_type>(__end_ - __begin_);
435}
436
437template <class _Tp, class _Alloc>
438_LIBCPP_CONSTEXPR_SINCE_CXX20 typename __vector_layout<_Tp, _Alloc>::size_type
439__vector_layout<_Tp, _Alloc>::__capacity() const _NOEXCEPT {
440 return static_cast<size_type>(__capacity_ - __begin_);
441}
442
443template <class _Tp, class _Alloc>
444_LIBCPP_CONSTEXPR_SINCE_CXX20 bool __vector_layout<_Tp, _Alloc>::__empty() const _NOEXCEPT {
445 return __begin_ == __end_;
446}
447
448template <class _Tp, class _Alloc>
449_LIBCPP_CONSTEXPR_SINCE_CXX20 typename __vector_layout<_Tp, _Alloc>::pointer
450__vector_layout<_Tp, _Alloc>::__end_ptr() _NOEXCEPT {
451 return __end_;
452}
453
454template <class _Tp, class _Alloc>
455_LIBCPP_CONSTEXPR_SINCE_CXX20 typename __vector_layout<_Tp, _Alloc>::const_pointer
456__vector_layout<_Tp, _Alloc>::__end_ptr() const _NOEXCEPT {
457 return __end_;
458}
459
460template <class _Tp, class _Alloc>
461_LIBCPP_CONSTEXPR_SINCE_CXX20 typename __vector_layout<_Tp, _Alloc>::pointer
462__vector_layout<_Tp, _Alloc>::__capacity_ptr() _NOEXCEPT {
463 return __capacity_;
464}
465
466template <class _Tp, class _Alloc>
467_LIBCPP_CONSTEXPR_SINCE_CXX20 typename __vector_layout<_Tp, _Alloc>::const_pointer
468__vector_layout<_Tp, _Alloc>::__capacity_ptr() const _NOEXCEPT {
469 return __capacity_;
470}
471
472template <class _Tp, class _Alloc>
473_LIBCPP_CONSTEXPR_SINCE_CXX20 bool __vector_layout<_Tp, _Alloc>::__invariants() const _NOEXCEPT {
474 if (__begin_ == nullptr)
475 return __end_ == nullptr && __capacity_ == nullptr;
476 if (__begin_ > __end_)
477 return false;
478 if (__begin_ == __capacity_)
479 return false;
480 return __end_ <= __capacity_;
481}
482#endif // _LIBCPP_ABI_VECTOR_LAYOUT_SIZE_BASED
483
484_LIBCPP_END_NAMESPACE_STD
485
486_LIBCPP_POP_MACROS
487
488#endif // _LIBCPP___VECTOR_LAYOUT_H
489