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