• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/enable_if.h>
28#include <__type_traits/integral_constant.h>
29#include <__type_traits/is_nothrow_default_constructible.h>
30#include <__type_traits/is_nothrow_move_assignable.h>
31#include <__type_traits/is_nothrow_move_constructible.h>
32#include <__type_traits/is_swappable.h>
33#include <__type_traits/is_trivially_destructible.h>
34#include <__type_traits/remove_reference.h>
35#include <__utility/forward.h>
36#include <__utility/move.h>
37#include <cstddef>
38
39#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
40#  pragma GCC system_header
41#endif
42
43_LIBCPP_PUSH_MACROS
44#include <__undef_macros>
45
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
53template <class _Tp, class _Allocator = allocator<_Tp> >
54struct __split_buffer
55{
56public:
57  using value_type      = _Tp;
58  using allocator_type  = _Allocator;
59  using __alloc_rr      = __libcpp_remove_reference_t<allocator_type>;
60  using __alloc_traits  = allocator_traits<__alloc_rr>;
61  using reference       = value_type&;
62  using const_reference = const value_type&;
63  using size_type       = typename __alloc_traits::size_type;
64  using difference_type = typename __alloc_traits::difference_type;
65  using pointer         = typename __alloc_traits::pointer;
66  using const_pointer   = typename __alloc_traits::const_pointer;
67  using iterator        = pointer;
68  using const_iterator  = const_pointer;
69
70  pointer __first_;
71  pointer __begin_;
72  pointer __end_;
73  __compressed_pair<pointer, allocator_type> __end_cap_;
74
75  using __alloc_ref       = __add_lvalue_reference_t<allocator_type>;
76  using __alloc_const_ref = __add_lvalue_reference_t<allocator_type>;
77
78  __split_buffer(const __split_buffer&) = delete;
79  __split_buffer& operator=(const __split_buffer&) = delete;
80
81  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __split_buffer()
82      _NOEXCEPT_(is_nothrow_default_constructible<allocator_type>::value)
83      : __first_(nullptr), __begin_(nullptr), __end_(nullptr), __end_cap_(nullptr, __default_init_tag()) {}
84
85  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __split_buffer(__alloc_rr& __a)
86      : __first_(nullptr), __begin_(nullptr), __end_(nullptr), __end_cap_(nullptr, __a) {}
87
88  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __split_buffer(const __alloc_rr& __a)
89      : __first_(nullptr), __begin_(nullptr), __end_(nullptr), __end_cap_(nullptr, __a) {}
90
91  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
92  __split_buffer(size_type __cap, size_type __start, __alloc_rr& __a);
93
94  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __split_buffer(__split_buffer&& __c)
95      _NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value);
96
97  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __split_buffer(__split_buffer&& __c, const __alloc_rr& __a);
98
99  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __split_buffer& operator=(__split_buffer&& __c)
100      _NOEXCEPT_((__alloc_traits::propagate_on_container_move_assignment::value &&
101                  is_nothrow_move_assignable<allocator_type>::value) ||
102                 !__alloc_traits::propagate_on_container_move_assignment::value);
103
104  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI ~__split_buffer();
105
106  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __alloc_rr& __alloc() _NOEXCEPT { return __end_cap_.second(); }
107  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const __alloc_rr& __alloc() const _NOEXCEPT {
108    return __end_cap_.second();
109  }
110
111  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer& __end_cap() _NOEXCEPT { return __end_cap_.first(); }
112  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const pointer& __end_cap() const _NOEXCEPT {
113    return __end_cap_.first();
114  }
115
116  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { return __begin_; }
117  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { return __begin_; }
118
119  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT { return __end_; }
120  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT { return __end_; }
121
122  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void clear() _NOEXCEPT { __destruct_at_end(__begin_); }
123
124  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type size() const {
125    return static_cast<size_type>(__end_ - __begin_);
126  }
127
128  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool empty() const { return __end_ == __begin_; }
129
130  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type capacity() const {
131    return static_cast<size_type>(__end_cap() - __first_);
132  }
133
134  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __front_spare() const {
135    return static_cast<size_type>(__begin_ - __first_);
136  }
137
138  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __back_spare() const {
139    return static_cast<size_type>(__end_cap() - __end_);
140  }
141
142  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference front() { return *__begin_; }
143  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference front() const { return *__begin_; }
144  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference back() { return *(__end_ - 1); }
145  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference back() const { return *(__end_ - 1); }
146
147  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void reserve(size_type __n);
148  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void shrink_to_fit() _NOEXCEPT;
149  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void push_front(const_reference __x);
150  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void push_back(const_reference __x);
151  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void push_front(value_type&& __x);
152  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void push_back(value_type&& __x);
153
154  template <class... _Args>
155  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void emplace_back(_Args&&... __args);
156
157  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void pop_front() { __destruct_at_begin(__begin_ + 1); }
158  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void pop_back() { __destruct_at_end(__end_ - 1); }
159
160  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __construct_at_end(size_type __n);
161  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __construct_at_end(size_type __n, const_reference __x);
162
163  template <class _InputIter>
164  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
165      __enable_if_t<__is_exactly_cpp17_input_iterator<_InputIter>::value>
166      __construct_at_end(_InputIter __first, _InputIter __last);
167
168  template <class _ForwardIterator>
169  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
170      __enable_if_t<__is_cpp17_forward_iterator<_ForwardIterator>::value>
171      __construct_at_end(_ForwardIterator __first, _ForwardIterator __last);
172
173  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __destruct_at_begin(pointer __new_begin) {
174    __destruct_at_begin(__new_begin, is_trivially_destructible<value_type>());
175  }
176
177  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __destruct_at_begin(pointer __new_begin, false_type);
178  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __destruct_at_begin(pointer __new_begin, true_type);
179
180  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __destruct_at_end(pointer __new_last) _NOEXCEPT {
181    __destruct_at_end(__new_last, false_type());
182  }
183
184  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __destruct_at_end(pointer __new_last, false_type) _NOEXCEPT;
185  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __destruct_at_end(pointer __new_last, true_type) _NOEXCEPT;
186
187  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void swap(__split_buffer& __x)
188      _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || __is_nothrow_swappable<__alloc_rr>::value);
189
190  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __invariants() const;
191
192private:
193  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __move_assign_alloc(__split_buffer& __c, true_type)
194      _NOEXCEPT_(is_nothrow_move_assignable<allocator_type>::value) {
195    __alloc() = _VSTD::move(__c.__alloc());
196  }
197
198  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __move_assign_alloc(__split_buffer&, false_type) _NOEXCEPT {}
199
200  struct _ConstructTransaction {
201    _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit _ConstructTransaction(
202        pointer* __p, size_type __n) _NOEXCEPT
203        : __pos_(*__p),
204          __end_(*__p + __n),
205          __dest_(__p) {}
206
207    _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI ~_ConstructTransaction() { *__dest_ = __pos_; }
208
209    pointer __pos_;
210    const pointer __end_;
211
212  private:
213    pointer* __dest_;
214  };
215};
216
217template <class _Tp, class _Allocator>
218_LIBCPP_CONSTEXPR_SINCE_CXX20
219bool
220__split_buffer<_Tp, _Allocator>::__invariants() const
221{
222    if (__first_ == nullptr)
223    {
224        if (__begin_ != nullptr)
225            return false;
226        if (__end_ != nullptr)
227            return false;
228        if (__end_cap() != nullptr)
229            return false;
230    }
231    else
232    {
233        if (__begin_ < __first_)
234            return false;
235        if (__end_ < __begin_)
236            return false;
237        if (__end_cap() < __end_)
238            return false;
239    }
240    return true;
241}
242
243//  Default constructs __n objects starting at __end_
244//  throws if construction throws
245//  Precondition:  __n > 0
246//  Precondition:  size() + __n <= capacity()
247//  Postcondition:  size() == size() + __n
248template <class _Tp, class _Allocator>
249_LIBCPP_CONSTEXPR_SINCE_CXX20
250void
251__split_buffer<_Tp, _Allocator>::__construct_at_end(size_type __n)
252{
253    _ConstructTransaction __tx(&this->__end_, __n);
254    for (; __tx.__pos_ != __tx.__end_; ++__tx.__pos_) {
255        __alloc_traits::construct(this->__alloc(), _VSTD::__to_address(__tx.__pos_));
256    }
257}
258
259//  Copy constructs __n objects starting at __end_ from __x
260//  throws if construction throws
261//  Precondition:  __n > 0
262//  Precondition:  size() + __n <= capacity()
263//  Postcondition:  size() == old size() + __n
264//  Postcondition:  [i] == __x for all i in [size() - __n, __n)
265template <class _Tp, class _Allocator>
266_LIBCPP_CONSTEXPR_SINCE_CXX20
267void
268__split_buffer<_Tp, _Allocator>::__construct_at_end(size_type __n, const_reference __x)
269{
270    _ConstructTransaction __tx(&this->__end_, __n);
271    for (; __tx.__pos_ != __tx.__end_; ++__tx.__pos_) {
272        __alloc_traits::construct(this->__alloc(),
273            _VSTD::__to_address(__tx.__pos_), __x);
274    }
275}
276
277template <class _Tp, class _Allocator>
278template <class _InputIter>
279_LIBCPP_CONSTEXPR_SINCE_CXX20 __enable_if_t<__is_exactly_cpp17_input_iterator<_InputIter>::value>
280__split_buffer<_Tp, _Allocator>::__construct_at_end(_InputIter __first, _InputIter __last)
281{
282    __alloc_rr& __a = this->__alloc();
283    for (; __first != __last; ++__first)
284    {
285        if (__end_ == __end_cap())
286        {
287            size_type __old_cap = __end_cap() - __first_;
288            size_type __new_cap = _VSTD::max<size_type>(2 * __old_cap, 8);
289            __split_buffer __buf(__new_cap, 0, __a);
290            for (pointer __p = __begin_; __p != __end_; ++__p, (void) ++__buf.__end_)
291                __alloc_traits::construct(__buf.__alloc(),
292                        _VSTD::__to_address(__buf.__end_), _VSTD::move(*__p));
293            swap(__buf);
294        }
295        __alloc_traits::construct(__a, _VSTD::__to_address(this->__end_), *__first);
296        ++this->__end_;
297    }
298}
299
300template <class _Tp, class _Allocator>
301template <class _ForwardIterator>
302_LIBCPP_CONSTEXPR_SINCE_CXX20 __enable_if_t<__is_cpp17_forward_iterator<_ForwardIterator>::value>
303__split_buffer<_Tp, _Allocator>::__construct_at_end(_ForwardIterator __first, _ForwardIterator __last)
304{
305    _ConstructTransaction __tx(&this->__end_, _VSTD::distance(__first, __last));
306    for (; __tx.__pos_ != __tx.__end_; ++__tx.__pos_, (void) ++__first) {
307        __alloc_traits::construct(this->__alloc(),
308            _VSTD::__to_address(__tx.__pos_), *__first);
309    }
310}
311
312template <class _Tp, class _Allocator>
313_LIBCPP_CONSTEXPR_SINCE_CXX20
314inline
315void
316__split_buffer<_Tp, _Allocator>::__destruct_at_begin(pointer __new_begin, false_type)
317{
318    while (__begin_ != __new_begin)
319        __alloc_traits::destroy(__alloc(), _VSTD::__to_address(__begin_++));
320}
321
322template <class _Tp, class _Allocator>
323_LIBCPP_CONSTEXPR_SINCE_CXX20
324inline
325void
326__split_buffer<_Tp, _Allocator>::__destruct_at_begin(pointer __new_begin, true_type)
327{
328    __begin_ = __new_begin;
329}
330
331template <class _Tp, class _Allocator>
332_LIBCPP_CONSTEXPR_SINCE_CXX20
333inline _LIBCPP_HIDE_FROM_ABI
334void
335__split_buffer<_Tp, _Allocator>::__destruct_at_end(pointer __new_last, false_type) _NOEXCEPT
336{
337    while (__new_last != __end_)
338        __alloc_traits::destroy(__alloc(), _VSTD::__to_address(--__end_));
339}
340
341template <class _Tp, class _Allocator>
342_LIBCPP_CONSTEXPR_SINCE_CXX20
343inline _LIBCPP_HIDE_FROM_ABI
344void
345__split_buffer<_Tp, _Allocator>::__destruct_at_end(pointer __new_last, true_type) _NOEXCEPT
346{
347    __end_ = __new_last;
348}
349
350template <class _Tp, class _Allocator>
351_LIBCPP_CONSTEXPR_SINCE_CXX20
352__split_buffer<_Tp, _Allocator>::__split_buffer(size_type __cap, size_type __start, __alloc_rr& __a)
353    : __end_cap_(nullptr, __a)
354{
355    if (__cap == 0) {
356        __first_ = nullptr;
357    } else {
358        auto __allocation = std::__allocate_at_least(__alloc(), __cap);
359        __first_ = __allocation.ptr;
360        __cap = __allocation.count;
361    }
362    __begin_ = __end_ = __first_ + __start;
363    __end_cap() = __first_ + __cap;
364}
365
366template <class _Tp, class _Allocator>
367_LIBCPP_CONSTEXPR_SINCE_CXX20
368__split_buffer<_Tp, _Allocator>::~__split_buffer()
369{
370    clear();
371    if (__first_)
372        __alloc_traits::deallocate(__alloc(), __first_, capacity());
373}
374
375template <class _Tp, class _Allocator>
376_LIBCPP_CONSTEXPR_SINCE_CXX20
377__split_buffer<_Tp, _Allocator>::__split_buffer(__split_buffer&& __c)
378    _NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value)
379    : __first_(_VSTD::move(__c.__first_)),
380      __begin_(_VSTD::move(__c.__begin_)),
381      __end_(_VSTD::move(__c.__end_)),
382      __end_cap_(_VSTD::move(__c.__end_cap_))
383{
384    __c.__first_ = nullptr;
385    __c.__begin_ = nullptr;
386    __c.__end_ = nullptr;
387    __c.__end_cap() = nullptr;
388}
389
390template <class _Tp, class _Allocator>
391_LIBCPP_CONSTEXPR_SINCE_CXX20
392__split_buffer<_Tp, _Allocator>::__split_buffer(__split_buffer&& __c, const __alloc_rr& __a)
393    : __end_cap_(nullptr, __a)
394{
395    if (__a == __c.__alloc())
396    {
397        __first_ = __c.__first_;
398        __begin_ = __c.__begin_;
399        __end_ = __c.__end_;
400        __end_cap() = __c.__end_cap();
401        __c.__first_ = nullptr;
402        __c.__begin_ = nullptr;
403        __c.__end_ = nullptr;
404        __c.__end_cap() = nullptr;
405    }
406    else
407    {
408        auto __allocation = std::__allocate_at_least(__alloc(), __c.size());
409        __first_ = __allocation.ptr;
410        __begin_ = __end_ = __first_;
411        __end_cap() = __first_ + __allocation.count;
412        typedef move_iterator<iterator> _Ip;
413        __construct_at_end(_Ip(__c.begin()), _Ip(__c.end()));
414    }
415}
416
417template <class _Tp, class _Allocator>
418_LIBCPP_CONSTEXPR_SINCE_CXX20
419__split_buffer<_Tp, _Allocator>&
420__split_buffer<_Tp, _Allocator>::operator=(__split_buffer&& __c)
421    _NOEXCEPT_((__alloc_traits::propagate_on_container_move_assignment::value &&
422                is_nothrow_move_assignable<allocator_type>::value) ||
423               !__alloc_traits::propagate_on_container_move_assignment::value)
424{
425    clear();
426    shrink_to_fit();
427    __first_ = __c.__first_;
428    __begin_ = __c.__begin_;
429    __end_ = __c.__end_;
430    __end_cap() = __c.__end_cap();
431    __move_assign_alloc(__c,
432        integral_constant<bool,
433                          __alloc_traits::propagate_on_container_move_assignment::value>());
434    __c.__first_ = __c.__begin_ = __c.__end_ = __c.__end_cap() = nullptr;
435    return *this;
436}
437
438template <class _Tp, class _Allocator>
439_LIBCPP_CONSTEXPR_SINCE_CXX20
440void
441__split_buffer<_Tp, _Allocator>::swap(__split_buffer& __x)
442        _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value||
443                   __is_nothrow_swappable<__alloc_rr>::value)
444{
445    _VSTD::swap(__first_, __x.__first_);
446    _VSTD::swap(__begin_, __x.__begin_);
447    _VSTD::swap(__end_, __x.__end_);
448    _VSTD::swap(__end_cap(), __x.__end_cap());
449    _VSTD::__swap_allocator(__alloc(), __x.__alloc());
450}
451
452template <class _Tp, class _Allocator>
453_LIBCPP_CONSTEXPR_SINCE_CXX20
454void
455__split_buffer<_Tp, _Allocator>::reserve(size_type __n)
456{
457    if (__n < capacity())
458    {
459        __split_buffer<value_type, __alloc_rr&> __t(__n, 0, __alloc());
460        __t.__construct_at_end(move_iterator<pointer>(__begin_),
461                               move_iterator<pointer>(__end_));
462        _VSTD::swap(__first_, __t.__first_);
463        _VSTD::swap(__begin_, __t.__begin_);
464        _VSTD::swap(__end_, __t.__end_);
465        _VSTD::swap(__end_cap(), __t.__end_cap());
466    }
467}
468
469template <class _Tp, class _Allocator>
470_LIBCPP_CONSTEXPR_SINCE_CXX20
471void
472__split_buffer<_Tp, _Allocator>::shrink_to_fit() _NOEXCEPT
473{
474    if (capacity() > size())
475    {
476#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
477        try
478        {
479#endif // _LIBCPP_HAS_NO_EXCEPTIONS
480            __split_buffer<value_type, __alloc_rr&> __t(size(), 0, __alloc());
481            __t.__construct_at_end(move_iterator<pointer>(__begin_),
482                                   move_iterator<pointer>(__end_));
483            __t.__end_ = __t.__begin_ + (__end_ - __begin_);
484            _VSTD::swap(__first_, __t.__first_);
485            _VSTD::swap(__begin_, __t.__begin_);
486            _VSTD::swap(__end_, __t.__end_);
487            _VSTD::swap(__end_cap(), __t.__end_cap());
488#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
489        }
490        catch (...)
491        {
492        }
493#endif // _LIBCPP_HAS_NO_EXCEPTIONS
494    }
495}
496
497template <class _Tp, class _Allocator>
498_LIBCPP_CONSTEXPR_SINCE_CXX20
499void
500__split_buffer<_Tp, _Allocator>::push_front(const_reference __x)
501{
502    if (__begin_ == __first_)
503    {
504        if (__end_ < __end_cap())
505        {
506            difference_type __d = __end_cap() - __end_;
507            __d = (__d + 1) / 2;
508            __begin_ = _VSTD::move_backward(__begin_, __end_, __end_ + __d);
509            __end_ += __d;
510        }
511        else
512        {
513            size_type __c = std::max<size_type>(2 * static_cast<size_t>(__end_cap() - __first_), 1);
514            __split_buffer<value_type, __alloc_rr&> __t(__c, (__c + 3) / 4, __alloc());
515            __t.__construct_at_end(move_iterator<pointer>(__begin_),
516                                   move_iterator<pointer>(__end_));
517            _VSTD::swap(__first_, __t.__first_);
518            _VSTD::swap(__begin_, __t.__begin_);
519            _VSTD::swap(__end_, __t.__end_);
520            _VSTD::swap(__end_cap(), __t.__end_cap());
521        }
522    }
523    __alloc_traits::construct(__alloc(), _VSTD::__to_address(__begin_-1), __x);
524    --__begin_;
525}
526
527template <class _Tp, class _Allocator>
528_LIBCPP_CONSTEXPR_SINCE_CXX20
529void
530__split_buffer<_Tp, _Allocator>::push_front(value_type&& __x)
531{
532    if (__begin_ == __first_)
533    {
534        if (__end_ < __end_cap())
535        {
536            difference_type __d = __end_cap() - __end_;
537            __d = (__d + 1) / 2;
538            __begin_ = _VSTD::move_backward(__begin_, __end_, __end_ + __d);
539            __end_ += __d;
540        }
541        else
542        {
543            size_type __c = std::max<size_type>(2 * static_cast<size_t>(__end_cap() - __first_), 1);
544            __split_buffer<value_type, __alloc_rr&> __t(__c, (__c + 3) / 4, __alloc());
545            __t.__construct_at_end(move_iterator<pointer>(__begin_),
546                                   move_iterator<pointer>(__end_));
547            _VSTD::swap(__first_, __t.__first_);
548            _VSTD::swap(__begin_, __t.__begin_);
549            _VSTD::swap(__end_, __t.__end_);
550            _VSTD::swap(__end_cap(), __t.__end_cap());
551        }
552    }
553    __alloc_traits::construct(__alloc(), _VSTD::__to_address(__begin_-1),
554            _VSTD::move(__x));
555    --__begin_;
556}
557
558template <class _Tp, class _Allocator>
559_LIBCPP_CONSTEXPR_SINCE_CXX20
560inline _LIBCPP_HIDE_FROM_ABI
561void
562__split_buffer<_Tp, _Allocator>::push_back(const_reference __x)
563{
564    if (__end_ == __end_cap())
565    {
566        if (__begin_ > __first_)
567        {
568            difference_type __d = __begin_ - __first_;
569            __d = (__d + 1) / 2;
570            __end_ = _VSTD::move(__begin_, __end_, __begin_ - __d);
571            __begin_ -= __d;
572        }
573        else
574        {
575            size_type __c = std::max<size_type>(2 * static_cast<size_t>(__end_cap() - __first_), 1);
576            __split_buffer<value_type, __alloc_rr&> __t(__c, __c / 4, __alloc());
577            __t.__construct_at_end(move_iterator<pointer>(__begin_),
578                                   move_iterator<pointer>(__end_));
579            _VSTD::swap(__first_, __t.__first_);
580            _VSTD::swap(__begin_, __t.__begin_);
581            _VSTD::swap(__end_, __t.__end_);
582            _VSTD::swap(__end_cap(), __t.__end_cap());
583        }
584    }
585    __alloc_traits::construct(__alloc(), _VSTD::__to_address(__end_), __x);
586    ++__end_;
587}
588
589template <class _Tp, class _Allocator>
590_LIBCPP_CONSTEXPR_SINCE_CXX20
591void
592__split_buffer<_Tp, _Allocator>::push_back(value_type&& __x)
593{
594    if (__end_ == __end_cap())
595    {
596        if (__begin_ > __first_)
597        {
598            difference_type __d = __begin_ - __first_;
599            __d = (__d + 1) / 2;
600            __end_ = _VSTD::move(__begin_, __end_, __begin_ - __d);
601            __begin_ -= __d;
602        }
603        else
604        {
605            size_type __c = std::max<size_type>(2 * static_cast<size_t>(__end_cap() - __first_), 1);
606            __split_buffer<value_type, __alloc_rr&> __t(__c, __c / 4, __alloc());
607            __t.__construct_at_end(move_iterator<pointer>(__begin_),
608                                   move_iterator<pointer>(__end_));
609            _VSTD::swap(__first_, __t.__first_);
610            _VSTD::swap(__begin_, __t.__begin_);
611            _VSTD::swap(__end_, __t.__end_);
612            _VSTD::swap(__end_cap(), __t.__end_cap());
613        }
614    }
615    __alloc_traits::construct(__alloc(), _VSTD::__to_address(__end_),
616            _VSTD::move(__x));
617    ++__end_;
618}
619
620template <class _Tp, class _Allocator>
621template <class... _Args>
622_LIBCPP_CONSTEXPR_SINCE_CXX20
623void
624__split_buffer<_Tp, _Allocator>::emplace_back(_Args&&... __args)
625{
626    if (__end_ == __end_cap())
627    {
628        if (__begin_ > __first_)
629        {
630            difference_type __d = __begin_ - __first_;
631            __d = (__d + 1) / 2;
632            __end_ = _VSTD::move(__begin_, __end_, __begin_ - __d);
633            __begin_ -= __d;
634        }
635        else
636        {
637            size_type __c = std::max<size_type>(2 * static_cast<size_t>(__end_cap() - __first_), 1);
638            __split_buffer<value_type, __alloc_rr&> __t(__c, __c / 4, __alloc());
639            __t.__construct_at_end(move_iterator<pointer>(__begin_),
640                                   move_iterator<pointer>(__end_));
641            _VSTD::swap(__first_, __t.__first_);
642            _VSTD::swap(__begin_, __t.__begin_);
643            _VSTD::swap(__end_, __t.__end_);
644            _VSTD::swap(__end_cap(), __t.__end_cap());
645        }
646    }
647    __alloc_traits::construct(__alloc(), _VSTD::__to_address(__end_),
648                              _VSTD::forward<_Args>(__args)...);
649    ++__end_;
650}
651
652template <class _Tp, class _Allocator>
653_LIBCPP_CONSTEXPR_SINCE_CXX20
654inline _LIBCPP_HIDE_FROM_ABI
655void
656swap(__split_buffer<_Tp, _Allocator>& __x, __split_buffer<_Tp, _Allocator>& __y)
657        _NOEXCEPT_(_NOEXCEPT_(__x.swap(__y)))
658{
659    __x.swap(__y);
660}
661
662_LIBCPP_END_NAMESPACE_STD
663
664_LIBCPP_POP_MACROS
665
666#endif // _LIBCPP___SPLIT_BUFFER
667