1 | // -*- C++ -*- |
2 | //===----------------------------------------------------------------------===// |
3 | // |
4 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
5 | // See https://llvm.org/LICENSE.txt for license information. |
6 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
7 | // |
8 | //===----------------------------------------------------------------------===// |
9 | |
10 | #ifndef _LIBCPP___SPLIT_BUFFER |
11 | #define _LIBCPP___SPLIT_BUFFER |
12 | |
13 | #include <__algorithm/max.h> |
14 | #include <__algorithm/move.h> |
15 | #include <__algorithm/move_backward.h> |
16 | #include <__config> |
17 | #include <__iterator/distance.h> |
18 | #include <__iterator/iterator_traits.h> |
19 | #include <__iterator/move_iterator.h> |
20 | #include <__memory/allocate_at_least.h> |
21 | #include <__memory/allocator.h> |
22 | #include <__memory/allocator_traits.h> |
23 | #include <__memory/compressed_pair.h> |
24 | #include <__memory/pointer_traits.h> |
25 | #include <__memory/swap_allocator.h> |
26 | #include <__type_traits/add_lvalue_reference.h> |
27 | #include <__type_traits/conditional.h> |
28 | #include <__type_traits/enable_if.h> |
29 | #include <__type_traits/integral_constant.h> |
30 | #include <__type_traits/is_nothrow_assignable.h> |
31 | #include <__type_traits/is_nothrow_constructible.h> |
32 | #include <__type_traits/is_swappable.h> |
33 | #include <__type_traits/is_trivially_destructible.h> |
34 | #include <__type_traits/is_trivially_relocatable.h> |
35 | #include <__type_traits/remove_reference.h> |
36 | #include <__utility/forward.h> |
37 | #include <__utility/move.h> |
38 | #include <cstddef> |
39 | |
40 | #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) |
41 | # pragma GCC system_header |
42 | #endif |
43 | |
44 | _LIBCPP_PUSH_MACROS |
45 | #include <__undef_macros> |
46 | |
47 | _LIBCPP_BEGIN_NAMESPACE_STD |
48 | |
49 | // __split_buffer allocates a contiguous chunk of memory and stores objects in the range [__begin_, __end_). |
50 | // It has uninitialized memory in the ranges [__first_, __begin_) and [__end_, __end_cap_.first()). That allows |
51 | // it to grow both in the front and back without having to move the data. |
52 | |
53 | template <class _Tp, class _Allocator = allocator<_Tp> > |
54 | struct __split_buffer { |
55 | public: |
56 | using value_type = _Tp; |
57 | using allocator_type = _Allocator; |
58 | using __alloc_rr = __libcpp_remove_reference_t<allocator_type>; |
59 | using __alloc_traits = allocator_traits<__alloc_rr>; |
60 | using reference = value_type&; |
61 | using const_reference = const value_type&; |
62 | using size_type = typename __alloc_traits::size_type; |
63 | using difference_type = typename __alloc_traits::difference_type; |
64 | using pointer = typename __alloc_traits::pointer; |
65 | using const_pointer = typename __alloc_traits::const_pointer; |
66 | using iterator = pointer; |
67 | using const_iterator = const_pointer; |
68 | |
69 | // A __split_buffer contains the following members which may be trivially relocatable: |
70 | // - pointer: may be trivially relocatable, so it's checked |
71 | // - allocator_type: may be trivially relocatable, so it's checked |
72 | // __split_buffer doesn't have any self-references, so it's trivially relocatable if its members are. |
73 | using __trivially_relocatable = __conditional_t< |
74 | __libcpp_is_trivially_relocatable<pointer>::value && __libcpp_is_trivially_relocatable<allocator_type>::value, |
75 | __split_buffer, |
76 | void>; |
77 | |
78 | pointer __first_; |
79 | pointer __begin_; |
80 | pointer __end_; |
81 | __compressed_pair<pointer, allocator_type> __end_cap_; |
82 | |
83 | using __alloc_ref = __add_lvalue_reference_t<allocator_type>; |
84 | using __alloc_const_ref = __add_lvalue_reference_t<allocator_type>; |
85 | |
86 | __split_buffer(const __split_buffer&) = delete; |
87 | __split_buffer& operator=(const __split_buffer&) = delete; |
88 | |
89 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __split_buffer() |
90 | _NOEXCEPT_(is_nothrow_default_constructible<allocator_type>::value) |
91 | : __first_(nullptr), __begin_(nullptr), __end_(nullptr), __end_cap_(nullptr, __default_init_tag()) {} |
92 | |
93 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __split_buffer(__alloc_rr& __a) |
94 | : __first_(nullptr), __begin_(nullptr), __end_(nullptr), __end_cap_(nullptr, __a) {} |
95 | |
96 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __split_buffer(const __alloc_rr& __a) |
97 | : __first_(nullptr), __begin_(nullptr), __end_(nullptr), __end_cap_(nullptr, __a) {} |
98 | |
99 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI |
100 | __split_buffer(size_type __cap, size_type __start, __alloc_rr& __a); |
101 | |
102 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __split_buffer(__split_buffer&& __c) |
103 | _NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value); |
104 | |
105 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __split_buffer(__split_buffer&& __c, const __alloc_rr& __a); |
106 | |
107 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __split_buffer& operator=(__split_buffer&& __c) |
108 | _NOEXCEPT_((__alloc_traits::propagate_on_container_move_assignment::value && |
109 | is_nothrow_move_assignable<allocator_type>::value) || |
110 | !__alloc_traits::propagate_on_container_move_assignment::value); |
111 | |
112 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI ~__split_buffer(); |
113 | |
114 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __alloc_rr& __alloc() _NOEXCEPT { return __end_cap_.second(); } |
115 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const __alloc_rr& __alloc() const _NOEXCEPT { |
116 | return __end_cap_.second(); |
117 | } |
118 | |
119 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer& __end_cap() _NOEXCEPT { return __end_cap_.first(); } |
120 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const pointer& __end_cap() const _NOEXCEPT { |
121 | return __end_cap_.first(); |
122 | } |
123 | |
124 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { return __begin_; } |
125 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { return __begin_; } |
126 | |
127 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT { return __end_; } |
128 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT { return __end_; } |
129 | |
130 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void clear() _NOEXCEPT { __destruct_at_end(__begin_); } |
131 | |
132 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type size() const { |
133 | return static_cast<size_type>(__end_ - __begin_); |
134 | } |
135 | |
136 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool empty() const { return __end_ == __begin_; } |
137 | |
138 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type capacity() const { |
139 | return static_cast<size_type>(__end_cap() - __first_); |
140 | } |
141 | |
142 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __front_spare() const { |
143 | return static_cast<size_type>(__begin_ - __first_); |
144 | } |
145 | |
146 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __back_spare() const { |
147 | return static_cast<size_type>(__end_cap() - __end_); |
148 | } |
149 | |
150 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference front() { return *__begin_; } |
151 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference front() const { return *__begin_; } |
152 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference back() { return *(__end_ - 1); } |
153 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference back() const { return *(__end_ - 1); } |
154 | |
155 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void reserve(size_type __n); |
156 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void shrink_to_fit() _NOEXCEPT; |
157 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void push_front(const_reference __x); |
158 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void push_back(const_reference __x); |
159 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void push_front(value_type&& __x); |
160 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void push_back(value_type&& __x); |
161 | |
162 | template <class... _Args> |
163 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void emplace_back(_Args&&... __args); |
164 | |
165 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void pop_front() { __destruct_at_begin(__begin_ + 1); } |
166 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void pop_back() { __destruct_at_end(__end_ - 1); } |
167 | |
168 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __construct_at_end(size_type __n); |
169 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __construct_at_end(size_type __n, const_reference __x); |
170 | |
171 | template <class _InputIter, __enable_if_t<__has_exactly_input_iterator_category<_InputIter>::value, int> = 0> |
172 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __construct_at_end(_InputIter __first, _InputIter __last); |
173 | |
174 | template <class _ForwardIterator, __enable_if_t<__has_forward_iterator_category<_ForwardIterator>::value, int> = 0> |
175 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void |
176 | __construct_at_end(_ForwardIterator __first, _ForwardIterator __last); |
177 | |
178 | template <class _Iterator, class _Sentinel> |
179 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void |
180 | __construct_at_end_with_sentinel(_Iterator __first, _Sentinel __last); |
181 | |
182 | template <class _Iterator> |
183 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void |
184 | __construct_at_end_with_size(_Iterator __first, size_type __n); |
185 | |
186 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __destruct_at_begin(pointer __new_begin) { |
187 | __destruct_at_begin(__new_begin, is_trivially_destructible<value_type>()); |
188 | } |
189 | |
190 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __destruct_at_begin(pointer __new_begin, false_type); |
191 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __destruct_at_begin(pointer __new_begin, true_type); |
192 | |
193 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __destruct_at_end(pointer __new_last) _NOEXCEPT { |
194 | __destruct_at_end(__new_last, false_type()); |
195 | } |
196 | |
197 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __destruct_at_end(pointer __new_last, false_type) _NOEXCEPT; |
198 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __destruct_at_end(pointer __new_last, true_type) _NOEXCEPT; |
199 | |
200 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void swap(__split_buffer& __x) |
201 | _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || __is_nothrow_swappable_v<__alloc_rr>); |
202 | |
203 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __invariants() const; |
204 | |
205 | private: |
206 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __move_assign_alloc(__split_buffer& __c, true_type) |
207 | _NOEXCEPT_(is_nothrow_move_assignable<allocator_type>::value) { |
208 | __alloc() = std::move(__c.__alloc()); |
209 | } |
210 | |
211 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __move_assign_alloc(__split_buffer&, false_type) _NOEXCEPT {} |
212 | |
213 | struct _ConstructTransaction { |
214 | _LIBCPP_CONSTEXPR_SINCE_CXX20 |
215 | _LIBCPP_HIDE_FROM_ABI explicit _ConstructTransaction(pointer* __p, size_type __n) _NOEXCEPT |
216 | : __pos_(*__p), |
217 | __end_(*__p + __n), |
218 | __dest_(__p) {} |
219 | |
220 | _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI ~_ConstructTransaction() { *__dest_ = __pos_; } |
221 | |
222 | pointer __pos_; |
223 | const pointer __end_; |
224 | |
225 | private: |
226 | pointer* __dest_; |
227 | }; |
228 | }; |
229 | |
230 | template <class _Tp, class _Allocator> |
231 | _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __split_buffer<_Tp, _Allocator>::__invariants() const { |
232 | if (__first_ == nullptr) { |
233 | if (__begin_ != nullptr) |
234 | return false; |
235 | if (__end_ != nullptr) |
236 | return false; |
237 | if (__end_cap() != nullptr) |
238 | return false; |
239 | } else { |
240 | if (__begin_ < __first_) |
241 | return false; |
242 | if (__end_ < __begin_) |
243 | return false; |
244 | if (__end_cap() < __end_) |
245 | return false; |
246 | } |
247 | return true; |
248 | } |
249 | |
250 | // Default constructs __n objects starting at __end_ |
251 | // throws if construction throws |
252 | // Precondition: __n > 0 |
253 | // Precondition: size() + __n <= capacity() |
254 | // Postcondition: size() == size() + __n |
255 | template <class _Tp, class _Allocator> |
256 | _LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator>::__construct_at_end(size_type __n) { |
257 | _ConstructTransaction __tx(&this->__end_, __n); |
258 | for (; __tx.__pos_ != __tx.__end_; ++__tx.__pos_) { |
259 | __alloc_traits::construct(this->__alloc(), std::__to_address(__tx.__pos_)); |
260 | } |
261 | } |
262 | |
263 | // Copy constructs __n objects starting at __end_ from __x |
264 | // throws if construction throws |
265 | // Precondition: __n > 0 |
266 | // Precondition: size() + __n <= capacity() |
267 | // Postcondition: size() == old size() + __n |
268 | // Postcondition: [i] == __x for all i in [size() - __n, __n) |
269 | template <class _Tp, class _Allocator> |
270 | _LIBCPP_CONSTEXPR_SINCE_CXX20 void |
271 | __split_buffer<_Tp, _Allocator>::__construct_at_end(size_type __n, const_reference __x) { |
272 | _ConstructTransaction __tx(&this->__end_, __n); |
273 | for (; __tx.__pos_ != __tx.__end_; ++__tx.__pos_) { |
274 | __alloc_traits::construct(this->__alloc(), std::__to_address(__tx.__pos_), __x); |
275 | } |
276 | } |
277 | |
278 | template <class _Tp, class _Allocator> |
279 | template <class _InputIter, __enable_if_t<__has_exactly_input_iterator_category<_InputIter>::value, int> > |
280 | _LIBCPP_CONSTEXPR_SINCE_CXX20 void |
281 | __split_buffer<_Tp, _Allocator>::__construct_at_end(_InputIter __first, _InputIter __last) { |
282 | __construct_at_end_with_sentinel(__first, __last); |
283 | } |
284 | |
285 | template <class _Tp, class _Allocator> |
286 | template <class _Iterator, class _Sentinel> |
287 | _LIBCPP_CONSTEXPR_SINCE_CXX20 void |
288 | __split_buffer<_Tp, _Allocator>::__construct_at_end_with_sentinel(_Iterator __first, _Sentinel __last) { |
289 | __alloc_rr& __a = this->__alloc(); |
290 | for (; __first != __last; ++__first) { |
291 | if (__end_ == __end_cap()) { |
292 | size_type __old_cap = __end_cap() - __first_; |
293 | size_type __new_cap = std::max<size_type>(2 * __old_cap, 8); |
294 | __split_buffer __buf(__new_cap, 0, __a); |
295 | for (pointer __p = __begin_; __p != __end_; ++__p, (void)++__buf.__end_) |
296 | __alloc_traits::construct(__buf.__alloc(), std::__to_address(__buf.__end_), std::move(*__p)); |
297 | swap(__buf); |
298 | } |
299 | __alloc_traits::construct(__a, std::__to_address(this->__end_), *__first); |
300 | ++this->__end_; |
301 | } |
302 | } |
303 | template <class _Tp, class _Allocator> |
304 | template <class _ForwardIterator, __enable_if_t<__has_forward_iterator_category<_ForwardIterator>::value, int> > |
305 | _LIBCPP_CONSTEXPR_SINCE_CXX20 void |
306 | __split_buffer<_Tp, _Allocator>::__construct_at_end(_ForwardIterator __first, _ForwardIterator __last) { |
307 | __construct_at_end_with_size(__first, std::distance(__first, __last)); |
308 | } |
309 | |
310 | template <class _Tp, class _Allocator> |
311 | template <class _ForwardIterator> |
312 | _LIBCPP_CONSTEXPR_SINCE_CXX20 void |
313 | __split_buffer<_Tp, _Allocator>::__construct_at_end_with_size(_ForwardIterator __first, size_type __n) { |
314 | _ConstructTransaction __tx(&this->__end_, __n); |
315 | for (; __tx.__pos_ != __tx.__end_; ++__tx.__pos_, (void)++__first) { |
316 | __alloc_traits::construct(this->__alloc(), std::__to_address(__tx.__pos_), *__first); |
317 | } |
318 | } |
319 | |
320 | template <class _Tp, class _Allocator> |
321 | _LIBCPP_CONSTEXPR_SINCE_CXX20 inline void |
322 | __split_buffer<_Tp, _Allocator>::__destruct_at_begin(pointer __new_begin, false_type) { |
323 | while (__begin_ != __new_begin) |
324 | __alloc_traits::destroy(__alloc(), std::__to_address(__begin_++)); |
325 | } |
326 | |
327 | template <class _Tp, class _Allocator> |
328 | _LIBCPP_CONSTEXPR_SINCE_CXX20 inline void |
329 | __split_buffer<_Tp, _Allocator>::__destruct_at_begin(pointer __new_begin, true_type) { |
330 | __begin_ = __new_begin; |
331 | } |
332 | |
333 | template <class _Tp, class _Allocator> |
334 | _LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI void |
335 | __split_buffer<_Tp, _Allocator>::__destruct_at_end(pointer __new_last, false_type) _NOEXCEPT { |
336 | while (__new_last != __end_) |
337 | __alloc_traits::destroy(__alloc(), std::__to_address(--__end_)); |
338 | } |
339 | |
340 | template <class _Tp, class _Allocator> |
341 | _LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI void |
342 | __split_buffer<_Tp, _Allocator>::__destruct_at_end(pointer __new_last, true_type) _NOEXCEPT { |
343 | __end_ = __new_last; |
344 | } |
345 | |
346 | template <class _Tp, class _Allocator> |
347 | _LIBCPP_CONSTEXPR_SINCE_CXX20 |
348 | __split_buffer<_Tp, _Allocator>::__split_buffer(size_type __cap, size_type __start, __alloc_rr& __a) |
349 | : __end_cap_(nullptr, __a) { |
350 | if (__cap == 0) { |
351 | __first_ = nullptr; |
352 | } else { |
353 | auto __allocation = std::__allocate_at_least(__alloc(), __cap); |
354 | __first_ = __allocation.ptr; |
355 | __cap = __allocation.count; |
356 | } |
357 | __begin_ = __end_ = __first_ + __start; |
358 | __end_cap() = __first_ + __cap; |
359 | } |
360 | |
361 | template <class _Tp, class _Allocator> |
362 | _LIBCPP_CONSTEXPR_SINCE_CXX20 __split_buffer<_Tp, _Allocator>::~__split_buffer() { |
363 | clear(); |
364 | if (__first_) |
365 | __alloc_traits::deallocate(__alloc(), __first_, capacity()); |
366 | } |
367 | |
368 | template <class _Tp, class _Allocator> |
369 | _LIBCPP_CONSTEXPR_SINCE_CXX20 __split_buffer<_Tp, _Allocator>::__split_buffer(__split_buffer&& __c) |
370 | _NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value) |
371 | : __first_(std::move(__c.__first_)), |
372 | __begin_(std::move(__c.__begin_)), |
373 | __end_(std::move(__c.__end_)), |
374 | __end_cap_(std::move(__c.__end_cap_)) { |
375 | __c.__first_ = nullptr; |
376 | __c.__begin_ = nullptr; |
377 | __c.__end_ = nullptr; |
378 | __c.__end_cap() = nullptr; |
379 | } |
380 | |
381 | template <class _Tp, class _Allocator> |
382 | _LIBCPP_CONSTEXPR_SINCE_CXX20 |
383 | __split_buffer<_Tp, _Allocator>::__split_buffer(__split_buffer&& __c, const __alloc_rr& __a) |
384 | : __end_cap_(nullptr, __a) { |
385 | if (__a == __c.__alloc()) { |
386 | __first_ = __c.__first_; |
387 | __begin_ = __c.__begin_; |
388 | __end_ = __c.__end_; |
389 | __end_cap() = __c.__end_cap(); |
390 | __c.__first_ = nullptr; |
391 | __c.__begin_ = nullptr; |
392 | __c.__end_ = nullptr; |
393 | __c.__end_cap() = nullptr; |
394 | } else { |
395 | auto __allocation = std::__allocate_at_least(__alloc(), __c.size()); |
396 | __first_ = __allocation.ptr; |
397 | __begin_ = __end_ = __first_; |
398 | __end_cap() = __first_ + __allocation.count; |
399 | typedef move_iterator<iterator> _Ip; |
400 | __construct_at_end(_Ip(__c.begin()), _Ip(__c.end())); |
401 | } |
402 | } |
403 | |
404 | template <class _Tp, class _Allocator> |
405 | _LIBCPP_CONSTEXPR_SINCE_CXX20 __split_buffer<_Tp, _Allocator>& |
406 | __split_buffer<_Tp, _Allocator>::operator=(__split_buffer&& __c) |
407 | _NOEXCEPT_((__alloc_traits::propagate_on_container_move_assignment::value && |
408 | is_nothrow_move_assignable<allocator_type>::value) || |
409 | !__alloc_traits::propagate_on_container_move_assignment::value) { |
410 | clear(); |
411 | shrink_to_fit(); |
412 | __first_ = __c.__first_; |
413 | __begin_ = __c.__begin_; |
414 | __end_ = __c.__end_; |
415 | __end_cap() = __c.__end_cap(); |
416 | __move_assign_alloc(__c, integral_constant<bool, __alloc_traits::propagate_on_container_move_assignment::value>()); |
417 | __c.__first_ = __c.__begin_ = __c.__end_ = __c.__end_cap() = nullptr; |
418 | return *this; |
419 | } |
420 | |
421 | template <class _Tp, class _Allocator> |
422 | _LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator>::swap(__split_buffer& __x) |
423 | _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || __is_nothrow_swappable_v<__alloc_rr>) { |
424 | std::swap(__first_, __x.__first_); |
425 | std::swap(__begin_, __x.__begin_); |
426 | std::swap(__end_, __x.__end_); |
427 | std::swap(__end_cap(), __x.__end_cap()); |
428 | std::__swap_allocator(__alloc(), __x.__alloc()); |
429 | } |
430 | |
431 | template <class _Tp, class _Allocator> |
432 | _LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator>::reserve(size_type __n) { |
433 | if (__n < capacity()) { |
434 | __split_buffer<value_type, __alloc_rr&> __t(__n, 0, __alloc()); |
435 | __t.__construct_at_end(move_iterator<pointer>(__begin_), move_iterator<pointer>(__end_)); |
436 | std::swap(__first_, __t.__first_); |
437 | std::swap(__begin_, __t.__begin_); |
438 | std::swap(__end_, __t.__end_); |
439 | std::swap(__end_cap(), __t.__end_cap()); |
440 | } |
441 | } |
442 | |
443 | template <class _Tp, class _Allocator> |
444 | _LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator>::shrink_to_fit() _NOEXCEPT { |
445 | if (capacity() > size()) { |
446 | #ifndef _LIBCPP_HAS_NO_EXCEPTIONS |
447 | try { |
448 | #endif // _LIBCPP_HAS_NO_EXCEPTIONS |
449 | __split_buffer<value_type, __alloc_rr&> __t(size(), 0, __alloc()); |
450 | __t.__construct_at_end(move_iterator<pointer>(__begin_), move_iterator<pointer>(__end_)); |
451 | __t.__end_ = __t.__begin_ + (__end_ - __begin_); |
452 | std::swap(__first_, __t.__first_); |
453 | std::swap(__begin_, __t.__begin_); |
454 | std::swap(__end_, __t.__end_); |
455 | std::swap(__end_cap(), __t.__end_cap()); |
456 | #ifndef _LIBCPP_HAS_NO_EXCEPTIONS |
457 | } catch (...) { |
458 | } |
459 | #endif // _LIBCPP_HAS_NO_EXCEPTIONS |
460 | } |
461 | } |
462 | |
463 | template <class _Tp, class _Allocator> |
464 | _LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator>::push_front(const_reference __x) { |
465 | if (__begin_ == __first_) { |
466 | if (__end_ < __end_cap()) { |
467 | difference_type __d = __end_cap() - __end_; |
468 | __d = (__d + 1) / 2; |
469 | __begin_ = std::move_backward(__begin_, __end_, __end_ + __d); |
470 | __end_ += __d; |
471 | } else { |
472 | size_type __c = std::max<size_type>(2 * static_cast<size_t>(__end_cap() - __first_), 1); |
473 | __split_buffer<value_type, __alloc_rr&> __t(__c, (__c + 3) / 4, __alloc()); |
474 | __t.__construct_at_end(move_iterator<pointer>(__begin_), move_iterator<pointer>(__end_)); |
475 | std::swap(__first_, __t.__first_); |
476 | std::swap(__begin_, __t.__begin_); |
477 | std::swap(__end_, __t.__end_); |
478 | std::swap(__end_cap(), __t.__end_cap()); |
479 | } |
480 | } |
481 | __alloc_traits::construct(__alloc(), std::__to_address(__begin_ - 1), __x); |
482 | --__begin_; |
483 | } |
484 | |
485 | template <class _Tp, class _Allocator> |
486 | _LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator>::push_front(value_type&& __x) { |
487 | if (__begin_ == __first_) { |
488 | if (__end_ < __end_cap()) { |
489 | difference_type __d = __end_cap() - __end_; |
490 | __d = (__d + 1) / 2; |
491 | __begin_ = std::move_backward(__begin_, __end_, __end_ + __d); |
492 | __end_ += __d; |
493 | } else { |
494 | size_type __c = std::max<size_type>(2 * static_cast<size_t>(__end_cap() - __first_), 1); |
495 | __split_buffer<value_type, __alloc_rr&> __t(__c, (__c + 3) / 4, __alloc()); |
496 | __t.__construct_at_end(move_iterator<pointer>(__begin_), move_iterator<pointer>(__end_)); |
497 | std::swap(__first_, __t.__first_); |
498 | std::swap(__begin_, __t.__begin_); |
499 | std::swap(__end_, __t.__end_); |
500 | std::swap(__end_cap(), __t.__end_cap()); |
501 | } |
502 | } |
503 | __alloc_traits::construct(__alloc(), std::__to_address(__begin_ - 1), std::move(__x)); |
504 | --__begin_; |
505 | } |
506 | |
507 | template <class _Tp, class _Allocator> |
508 | _LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI void |
509 | __split_buffer<_Tp, _Allocator>::push_back(const_reference __x) { |
510 | if (__end_ == __end_cap()) { |
511 | if (__begin_ > __first_) { |
512 | difference_type __d = __begin_ - __first_; |
513 | __d = (__d + 1) / 2; |
514 | __end_ = std::move(__begin_, __end_, __begin_ - __d); |
515 | __begin_ -= __d; |
516 | } else { |
517 | size_type __c = std::max<size_type>(2 * static_cast<size_t>(__end_cap() - __first_), 1); |
518 | __split_buffer<value_type, __alloc_rr&> __t(__c, __c / 4, __alloc()); |
519 | __t.__construct_at_end(move_iterator<pointer>(__begin_), move_iterator<pointer>(__end_)); |
520 | std::swap(__first_, __t.__first_); |
521 | std::swap(__begin_, __t.__begin_); |
522 | std::swap(__end_, __t.__end_); |
523 | std::swap(__end_cap(), __t.__end_cap()); |
524 | } |
525 | } |
526 | __alloc_traits::construct(__alloc(), std::__to_address(__end_), __x); |
527 | ++__end_; |
528 | } |
529 | |
530 | template <class _Tp, class _Allocator> |
531 | _LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator>::push_back(value_type&& __x) { |
532 | if (__end_ == __end_cap()) { |
533 | if (__begin_ > __first_) { |
534 | difference_type __d = __begin_ - __first_; |
535 | __d = (__d + 1) / 2; |
536 | __end_ = std::move(__begin_, __end_, __begin_ - __d); |
537 | __begin_ -= __d; |
538 | } else { |
539 | size_type __c = std::max<size_type>(2 * static_cast<size_t>(__end_cap() - __first_), 1); |
540 | __split_buffer<value_type, __alloc_rr&> __t(__c, __c / 4, __alloc()); |
541 | __t.__construct_at_end(move_iterator<pointer>(__begin_), move_iterator<pointer>(__end_)); |
542 | std::swap(__first_, __t.__first_); |
543 | std::swap(__begin_, __t.__begin_); |
544 | std::swap(__end_, __t.__end_); |
545 | std::swap(__end_cap(), __t.__end_cap()); |
546 | } |
547 | } |
548 | __alloc_traits::construct(__alloc(), std::__to_address(__end_), std::move(__x)); |
549 | ++__end_; |
550 | } |
551 | |
552 | template <class _Tp, class _Allocator> |
553 | template <class... _Args> |
554 | _LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator>::emplace_back(_Args&&... __args) { |
555 | if (__end_ == __end_cap()) { |
556 | if (__begin_ > __first_) { |
557 | difference_type __d = __begin_ - __first_; |
558 | __d = (__d + 1) / 2; |
559 | __end_ = std::move(__begin_, __end_, __begin_ - __d); |
560 | __begin_ -= __d; |
561 | } else { |
562 | size_type __c = std::max<size_type>(2 * static_cast<size_t>(__end_cap() - __first_), 1); |
563 | __split_buffer<value_type, __alloc_rr&> __t(__c, __c / 4, __alloc()); |
564 | __t.__construct_at_end(move_iterator<pointer>(__begin_), move_iterator<pointer>(__end_)); |
565 | std::swap(__first_, __t.__first_); |
566 | std::swap(__begin_, __t.__begin_); |
567 | std::swap(__end_, __t.__end_); |
568 | std::swap(__end_cap(), __t.__end_cap()); |
569 | } |
570 | } |
571 | __alloc_traits::construct(__alloc(), std::__to_address(__end_), std::forward<_Args>(__args)...); |
572 | ++__end_; |
573 | } |
574 | |
575 | template <class _Tp, class _Allocator> |
576 | _LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI void |
577 | swap(__split_buffer<_Tp, _Allocator>& __x, __split_buffer<_Tp, _Allocator>& __y) _NOEXCEPT_(_NOEXCEPT_(__x.swap(__y))) { |
578 | __x.swap(__y); |
579 | } |
580 | |
581 | _LIBCPP_END_NAMESPACE_STD |
582 | |
583 | _LIBCPP_POP_MACROS |
584 | |
585 | #endif // _LIBCPP___SPLIT_BUFFER |
586 | |