
This significantly simplifies the code, improves compile times and improves the object layout of types using `__compressed_pair` in the unstable ABI. The only downside is that this is extremely ABI sensitive and pedantically breaks the ABI for empty final types, since the address of the subobject may change. The ABI of the whole object should not be affected. Fixes #91266 Fixes #93069
583 lines
24 KiB
C++
583 lines
24 KiB
C++
// -*- C++ -*-
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef _LIBCPP___SPLIT_BUFFER
|
|
#define _LIBCPP___SPLIT_BUFFER
|
|
|
|
#include <__algorithm/max.h>
|
|
#include <__algorithm/move.h>
|
|
#include <__algorithm/move_backward.h>
|
|
#include <__config>
|
|
#include <__iterator/distance.h>
|
|
#include <__iterator/iterator_traits.h>
|
|
#include <__iterator/move_iterator.h>
|
|
#include <__memory/allocate_at_least.h>
|
|
#include <__memory/allocator.h>
|
|
#include <__memory/allocator_traits.h>
|
|
#include <__memory/compressed_pair.h>
|
|
#include <__memory/pointer_traits.h>
|
|
#include <__memory/swap_allocator.h>
|
|
#include <__type_traits/add_lvalue_reference.h>
|
|
#include <__type_traits/conditional.h>
|
|
#include <__type_traits/enable_if.h>
|
|
#include <__type_traits/integral_constant.h>
|
|
#include <__type_traits/is_nothrow_assignable.h>
|
|
#include <__type_traits/is_nothrow_constructible.h>
|
|
#include <__type_traits/is_swappable.h>
|
|
#include <__type_traits/is_trivially_destructible.h>
|
|
#include <__type_traits/is_trivially_relocatable.h>
|
|
#include <__type_traits/remove_reference.h>
|
|
#include <__utility/forward.h>
|
|
#include <__utility/move.h>
|
|
#include <cstddef>
|
|
|
|
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
|
# pragma GCC system_header
|
|
#endif
|
|
|
|
_LIBCPP_PUSH_MACROS
|
|
#include <__undef_macros>
|
|
|
|
_LIBCPP_BEGIN_NAMESPACE_STD
|
|
|
|
// __split_buffer allocates a contiguous chunk of memory and stores objects in the range [__begin_, __end_).
|
|
// It has uninitialized memory in the ranges [__first_, __begin_) and [__end_, __end_cap_.first()). That allows
|
|
// it to grow both in the front and back without having to move the data.
|
|
|
|
template <class _Tp, class _Allocator = allocator<_Tp> >
|
|
struct __split_buffer {
|
|
public:
|
|
using value_type = _Tp;
|
|
using allocator_type = _Allocator;
|
|
using __alloc_rr = __libcpp_remove_reference_t<allocator_type>;
|
|
using __alloc_traits = allocator_traits<__alloc_rr>;
|
|
using reference = value_type&;
|
|
using const_reference = const value_type&;
|
|
using size_type = typename __alloc_traits::size_type;
|
|
using difference_type = typename __alloc_traits::difference_type;
|
|
using pointer = typename __alloc_traits::pointer;
|
|
using const_pointer = typename __alloc_traits::const_pointer;
|
|
using iterator = pointer;
|
|
using const_iterator = const_pointer;
|
|
|
|
// A __split_buffer contains the following members which may be trivially relocatable:
|
|
// - pointer: may be trivially relocatable, so it's checked
|
|
// - allocator_type: may be trivially relocatable, so it's checked
|
|
// __split_buffer doesn't have any self-references, so it's trivially relocatable if its members are.
|
|
using __trivially_relocatable = __conditional_t<
|
|
__libcpp_is_trivially_relocatable<pointer>::value && __libcpp_is_trivially_relocatable<allocator_type>::value,
|
|
__split_buffer,
|
|
void>;
|
|
|
|
pointer __first_;
|
|
pointer __begin_;
|
|
pointer __end_;
|
|
_LIBCPP_COMPRESSED_PAIR(pointer, __end_cap_, allocator_type, __alloc_);
|
|
|
|
using __alloc_ref = __add_lvalue_reference_t<allocator_type>;
|
|
using __alloc_const_ref = __add_lvalue_reference_t<allocator_type>;
|
|
|
|
__split_buffer(const __split_buffer&) = delete;
|
|
__split_buffer& operator=(const __split_buffer&) = delete;
|
|
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __split_buffer()
|
|
_NOEXCEPT_(is_nothrow_default_constructible<allocator_type>::value)
|
|
: __first_(nullptr), __begin_(nullptr), __end_(nullptr), __end_cap_(nullptr) {}
|
|
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __split_buffer(__alloc_rr& __a)
|
|
: __first_(nullptr), __begin_(nullptr), __end_(nullptr), __end_cap_(nullptr), __alloc_(__a) {}
|
|
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __split_buffer(const __alloc_rr& __a)
|
|
: __first_(nullptr), __begin_(nullptr), __end_(nullptr), __end_cap_(nullptr), __alloc_(__a) {}
|
|
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
|
|
__split_buffer(size_type __cap, size_type __start, __alloc_rr& __a);
|
|
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __split_buffer(__split_buffer&& __c)
|
|
_NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value);
|
|
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __split_buffer(__split_buffer&& __c, const __alloc_rr& __a);
|
|
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __split_buffer& operator=(__split_buffer&& __c)
|
|
_NOEXCEPT_((__alloc_traits::propagate_on_container_move_assignment::value &&
|
|
is_nothrow_move_assignable<allocator_type>::value) ||
|
|
!__alloc_traits::propagate_on_container_move_assignment::value);
|
|
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI ~__split_buffer();
|
|
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __alloc_rr& __alloc() _NOEXCEPT { return __alloc_; }
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const __alloc_rr& __alloc() const _NOEXCEPT { return __alloc_; }
|
|
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer& __end_cap() _NOEXCEPT { return __end_cap_; }
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const pointer& __end_cap() const _NOEXCEPT { return __end_cap_; }
|
|
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { return __begin_; }
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { return __begin_; }
|
|
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT { return __end_; }
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT { return __end_; }
|
|
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void clear() _NOEXCEPT { __destruct_at_end(__begin_); }
|
|
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type size() const {
|
|
return static_cast<size_type>(__end_ - __begin_);
|
|
}
|
|
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool empty() const { return __end_ == __begin_; }
|
|
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type capacity() const {
|
|
return static_cast<size_type>(__end_cap() - __first_);
|
|
}
|
|
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __front_spare() const {
|
|
return static_cast<size_type>(__begin_ - __first_);
|
|
}
|
|
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __back_spare() const {
|
|
return static_cast<size_type>(__end_cap() - __end_);
|
|
}
|
|
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference front() { return *__begin_; }
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference front() const { return *__begin_; }
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference back() { return *(__end_ - 1); }
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference back() const { return *(__end_ - 1); }
|
|
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void reserve(size_type __n);
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void shrink_to_fit() _NOEXCEPT;
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void push_front(const_reference __x);
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void push_back(const_reference __x);
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void push_front(value_type&& __x);
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void push_back(value_type&& __x);
|
|
|
|
template <class... _Args>
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void emplace_back(_Args&&... __args);
|
|
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void pop_front() { __destruct_at_begin(__begin_ + 1); }
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void pop_back() { __destruct_at_end(__end_ - 1); }
|
|
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __construct_at_end(size_type __n);
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __construct_at_end(size_type __n, const_reference __x);
|
|
|
|
template <class _InputIter, __enable_if_t<__has_exactly_input_iterator_category<_InputIter>::value, int> = 0>
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __construct_at_end(_InputIter __first, _InputIter __last);
|
|
|
|
template <class _ForwardIterator, __enable_if_t<__has_forward_iterator_category<_ForwardIterator>::value, int> = 0>
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
|
|
__construct_at_end(_ForwardIterator __first, _ForwardIterator __last);
|
|
|
|
template <class _Iterator, class _Sentinel>
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
|
|
__construct_at_end_with_sentinel(_Iterator __first, _Sentinel __last);
|
|
|
|
template <class _Iterator>
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
|
|
__construct_at_end_with_size(_Iterator __first, size_type __n);
|
|
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __destruct_at_begin(pointer __new_begin) {
|
|
__destruct_at_begin(__new_begin, is_trivially_destructible<value_type>());
|
|
}
|
|
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __destruct_at_begin(pointer __new_begin, false_type);
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __destruct_at_begin(pointer __new_begin, true_type);
|
|
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __destruct_at_end(pointer __new_last) _NOEXCEPT {
|
|
__destruct_at_end(__new_last, false_type());
|
|
}
|
|
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __destruct_at_end(pointer __new_last, false_type) _NOEXCEPT;
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __destruct_at_end(pointer __new_last, true_type) _NOEXCEPT;
|
|
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void swap(__split_buffer& __x)
|
|
_NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || __is_nothrow_swappable_v<__alloc_rr>);
|
|
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __invariants() const;
|
|
|
|
private:
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __move_assign_alloc(__split_buffer& __c, true_type)
|
|
_NOEXCEPT_(is_nothrow_move_assignable<allocator_type>::value) {
|
|
__alloc() = std::move(__c.__alloc());
|
|
}
|
|
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __move_assign_alloc(__split_buffer&, false_type) _NOEXCEPT {}
|
|
|
|
struct _ConstructTransaction {
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20
|
|
_LIBCPP_HIDE_FROM_ABI explicit _ConstructTransaction(pointer* __p, size_type __n) _NOEXCEPT
|
|
: __pos_(*__p),
|
|
__end_(*__p + __n),
|
|
__dest_(__p) {}
|
|
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI ~_ConstructTransaction() { *__dest_ = __pos_; }
|
|
|
|
pointer __pos_;
|
|
const pointer __end_;
|
|
|
|
private:
|
|
pointer* __dest_;
|
|
};
|
|
};
|
|
|
|
template <class _Tp, class _Allocator>
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 bool __split_buffer<_Tp, _Allocator>::__invariants() const {
|
|
if (__first_ == nullptr) {
|
|
if (__begin_ != nullptr)
|
|
return false;
|
|
if (__end_ != nullptr)
|
|
return false;
|
|
if (__end_cap() != nullptr)
|
|
return false;
|
|
} else {
|
|
if (__begin_ < __first_)
|
|
return false;
|
|
if (__end_ < __begin_)
|
|
return false;
|
|
if (__end_cap() < __end_)
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Default constructs __n objects starting at __end_
|
|
// throws if construction throws
|
|
// Precondition: __n > 0
|
|
// Precondition: size() + __n <= capacity()
|
|
// Postcondition: size() == size() + __n
|
|
template <class _Tp, class _Allocator>
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator>::__construct_at_end(size_type __n) {
|
|
_ConstructTransaction __tx(&this->__end_, __n);
|
|
for (; __tx.__pos_ != __tx.__end_; ++__tx.__pos_) {
|
|
__alloc_traits::construct(this->__alloc(), std::__to_address(__tx.__pos_));
|
|
}
|
|
}
|
|
|
|
// Copy constructs __n objects starting at __end_ from __x
|
|
// throws if construction throws
|
|
// Precondition: __n > 0
|
|
// Precondition: size() + __n <= capacity()
|
|
// Postcondition: size() == old size() + __n
|
|
// Postcondition: [i] == __x for all i in [size() - __n, __n)
|
|
template <class _Tp, class _Allocator>
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 void
|
|
__split_buffer<_Tp, _Allocator>::__construct_at_end(size_type __n, const_reference __x) {
|
|
_ConstructTransaction __tx(&this->__end_, __n);
|
|
for (; __tx.__pos_ != __tx.__end_; ++__tx.__pos_) {
|
|
__alloc_traits::construct(this->__alloc(), std::__to_address(__tx.__pos_), __x);
|
|
}
|
|
}
|
|
|
|
template <class _Tp, class _Allocator>
|
|
template <class _InputIter, __enable_if_t<__has_exactly_input_iterator_category<_InputIter>::value, int> >
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 void
|
|
__split_buffer<_Tp, _Allocator>::__construct_at_end(_InputIter __first, _InputIter __last) {
|
|
__construct_at_end_with_sentinel(__first, __last);
|
|
}
|
|
|
|
template <class _Tp, class _Allocator>
|
|
template <class _Iterator, class _Sentinel>
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 void
|
|
__split_buffer<_Tp, _Allocator>::__construct_at_end_with_sentinel(_Iterator __first, _Sentinel __last) {
|
|
__alloc_rr& __a = this->__alloc();
|
|
for (; __first != __last; ++__first) {
|
|
if (__end_ == __end_cap()) {
|
|
size_type __old_cap = __end_cap() - __first_;
|
|
size_type __new_cap = std::max<size_type>(2 * __old_cap, 8);
|
|
__split_buffer __buf(__new_cap, 0, __a);
|
|
for (pointer __p = __begin_; __p != __end_; ++__p, (void)++__buf.__end_)
|
|
__alloc_traits::construct(__buf.__alloc(), std::__to_address(__buf.__end_), std::move(*__p));
|
|
swap(__buf);
|
|
}
|
|
__alloc_traits::construct(__a, std::__to_address(this->__end_), *__first);
|
|
++this->__end_;
|
|
}
|
|
}
|
|
template <class _Tp, class _Allocator>
|
|
template <class _ForwardIterator, __enable_if_t<__has_forward_iterator_category<_ForwardIterator>::value, int> >
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 void
|
|
__split_buffer<_Tp, _Allocator>::__construct_at_end(_ForwardIterator __first, _ForwardIterator __last) {
|
|
__construct_at_end_with_size(__first, std::distance(__first, __last));
|
|
}
|
|
|
|
template <class _Tp, class _Allocator>
|
|
template <class _ForwardIterator>
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 void
|
|
__split_buffer<_Tp, _Allocator>::__construct_at_end_with_size(_ForwardIterator __first, size_type __n) {
|
|
_ConstructTransaction __tx(&this->__end_, __n);
|
|
for (; __tx.__pos_ != __tx.__end_; ++__tx.__pos_, (void)++__first) {
|
|
__alloc_traits::construct(this->__alloc(), std::__to_address(__tx.__pos_), *__first);
|
|
}
|
|
}
|
|
|
|
template <class _Tp, class _Allocator>
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 inline void
|
|
__split_buffer<_Tp, _Allocator>::__destruct_at_begin(pointer __new_begin, false_type) {
|
|
while (__begin_ != __new_begin)
|
|
__alloc_traits::destroy(__alloc(), std::__to_address(__begin_++));
|
|
}
|
|
|
|
template <class _Tp, class _Allocator>
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 inline void
|
|
__split_buffer<_Tp, _Allocator>::__destruct_at_begin(pointer __new_begin, true_type) {
|
|
__begin_ = __new_begin;
|
|
}
|
|
|
|
template <class _Tp, class _Allocator>
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI void
|
|
__split_buffer<_Tp, _Allocator>::__destruct_at_end(pointer __new_last, false_type) _NOEXCEPT {
|
|
while (__new_last != __end_)
|
|
__alloc_traits::destroy(__alloc(), std::__to_address(--__end_));
|
|
}
|
|
|
|
template <class _Tp, class _Allocator>
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI void
|
|
__split_buffer<_Tp, _Allocator>::__destruct_at_end(pointer __new_last, true_type) _NOEXCEPT {
|
|
__end_ = __new_last;
|
|
}
|
|
|
|
template <class _Tp, class _Allocator>
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20
|
|
__split_buffer<_Tp, _Allocator>::__split_buffer(size_type __cap, size_type __start, __alloc_rr& __a)
|
|
: __end_cap_(nullptr), __alloc_(__a) {
|
|
if (__cap == 0) {
|
|
__first_ = nullptr;
|
|
} else {
|
|
auto __allocation = std::__allocate_at_least(__alloc(), __cap);
|
|
__first_ = __allocation.ptr;
|
|
__cap = __allocation.count;
|
|
}
|
|
__begin_ = __end_ = __first_ + __start;
|
|
__end_cap() = __first_ + __cap;
|
|
}
|
|
|
|
template <class _Tp, class _Allocator>
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 __split_buffer<_Tp, _Allocator>::~__split_buffer() {
|
|
clear();
|
|
if (__first_)
|
|
__alloc_traits::deallocate(__alloc(), __first_, capacity());
|
|
}
|
|
|
|
template <class _Tp, class _Allocator>
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 __split_buffer<_Tp, _Allocator>::__split_buffer(__split_buffer&& __c)
|
|
_NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value)
|
|
: __first_(std::move(__c.__first_)),
|
|
__begin_(std::move(__c.__begin_)),
|
|
__end_(std::move(__c.__end_)),
|
|
__end_cap_(std::move(__c.__end_cap_)),
|
|
__alloc_(std::move(__c.__alloc_)) {
|
|
__c.__first_ = nullptr;
|
|
__c.__begin_ = nullptr;
|
|
__c.__end_ = nullptr;
|
|
__c.__end_cap() = nullptr;
|
|
}
|
|
|
|
template <class _Tp, class _Allocator>
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20
|
|
__split_buffer<_Tp, _Allocator>::__split_buffer(__split_buffer&& __c, const __alloc_rr& __a)
|
|
: __end_cap_(nullptr), __alloc_(__a) {
|
|
if (__a == __c.__alloc()) {
|
|
__first_ = __c.__first_;
|
|
__begin_ = __c.__begin_;
|
|
__end_ = __c.__end_;
|
|
__end_cap() = __c.__end_cap();
|
|
__c.__first_ = nullptr;
|
|
__c.__begin_ = nullptr;
|
|
__c.__end_ = nullptr;
|
|
__c.__end_cap() = nullptr;
|
|
} else {
|
|
auto __allocation = std::__allocate_at_least(__alloc(), __c.size());
|
|
__first_ = __allocation.ptr;
|
|
__begin_ = __end_ = __first_;
|
|
__end_cap() = __first_ + __allocation.count;
|
|
typedef move_iterator<iterator> _Ip;
|
|
__construct_at_end(_Ip(__c.begin()), _Ip(__c.end()));
|
|
}
|
|
}
|
|
|
|
template <class _Tp, class _Allocator>
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 __split_buffer<_Tp, _Allocator>&
|
|
__split_buffer<_Tp, _Allocator>::operator=(__split_buffer&& __c)
|
|
_NOEXCEPT_((__alloc_traits::propagate_on_container_move_assignment::value &&
|
|
is_nothrow_move_assignable<allocator_type>::value) ||
|
|
!__alloc_traits::propagate_on_container_move_assignment::value) {
|
|
clear();
|
|
shrink_to_fit();
|
|
__first_ = __c.__first_;
|
|
__begin_ = __c.__begin_;
|
|
__end_ = __c.__end_;
|
|
__end_cap() = __c.__end_cap();
|
|
__move_assign_alloc(__c, integral_constant<bool, __alloc_traits::propagate_on_container_move_assignment::value>());
|
|
__c.__first_ = __c.__begin_ = __c.__end_ = __c.__end_cap() = nullptr;
|
|
return *this;
|
|
}
|
|
|
|
template <class _Tp, class _Allocator>
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator>::swap(__split_buffer& __x)
|
|
_NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || __is_nothrow_swappable_v<__alloc_rr>) {
|
|
std::swap(__first_, __x.__first_);
|
|
std::swap(__begin_, __x.__begin_);
|
|
std::swap(__end_, __x.__end_);
|
|
std::swap(__end_cap(), __x.__end_cap());
|
|
std::__swap_allocator(__alloc(), __x.__alloc());
|
|
}
|
|
|
|
template <class _Tp, class _Allocator>
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator>::reserve(size_type __n) {
|
|
if (__n < capacity()) {
|
|
__split_buffer<value_type, __alloc_rr&> __t(__n, 0, __alloc());
|
|
__t.__construct_at_end(move_iterator<pointer>(__begin_), move_iterator<pointer>(__end_));
|
|
std::swap(__first_, __t.__first_);
|
|
std::swap(__begin_, __t.__begin_);
|
|
std::swap(__end_, __t.__end_);
|
|
std::swap(__end_cap(), __t.__end_cap());
|
|
}
|
|
}
|
|
|
|
template <class _Tp, class _Allocator>
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator>::shrink_to_fit() _NOEXCEPT {
|
|
if (capacity() > size()) {
|
|
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
|
|
try {
|
|
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
|
|
__split_buffer<value_type, __alloc_rr&> __t(size(), 0, __alloc());
|
|
__t.__construct_at_end(move_iterator<pointer>(__begin_), move_iterator<pointer>(__end_));
|
|
__t.__end_ = __t.__begin_ + (__end_ - __begin_);
|
|
std::swap(__first_, __t.__first_);
|
|
std::swap(__begin_, __t.__begin_);
|
|
std::swap(__end_, __t.__end_);
|
|
std::swap(__end_cap(), __t.__end_cap());
|
|
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
|
|
} catch (...) {
|
|
}
|
|
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
|
|
}
|
|
}
|
|
|
|
template <class _Tp, class _Allocator>
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator>::push_front(const_reference __x) {
|
|
if (__begin_ == __first_) {
|
|
if (__end_ < __end_cap()) {
|
|
difference_type __d = __end_cap() - __end_;
|
|
__d = (__d + 1) / 2;
|
|
__begin_ = std::move_backward(__begin_, __end_, __end_ + __d);
|
|
__end_ += __d;
|
|
} else {
|
|
size_type __c = std::max<size_type>(2 * static_cast<size_t>(__end_cap() - __first_), 1);
|
|
__split_buffer<value_type, __alloc_rr&> __t(__c, (__c + 3) / 4, __alloc());
|
|
__t.__construct_at_end(move_iterator<pointer>(__begin_), move_iterator<pointer>(__end_));
|
|
std::swap(__first_, __t.__first_);
|
|
std::swap(__begin_, __t.__begin_);
|
|
std::swap(__end_, __t.__end_);
|
|
std::swap(__end_cap(), __t.__end_cap());
|
|
}
|
|
}
|
|
__alloc_traits::construct(__alloc(), std::__to_address(__begin_ - 1), __x);
|
|
--__begin_;
|
|
}
|
|
|
|
template <class _Tp, class _Allocator>
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator>::push_front(value_type&& __x) {
|
|
if (__begin_ == __first_) {
|
|
if (__end_ < __end_cap()) {
|
|
difference_type __d = __end_cap() - __end_;
|
|
__d = (__d + 1) / 2;
|
|
__begin_ = std::move_backward(__begin_, __end_, __end_ + __d);
|
|
__end_ += __d;
|
|
} else {
|
|
size_type __c = std::max<size_type>(2 * static_cast<size_t>(__end_cap() - __first_), 1);
|
|
__split_buffer<value_type, __alloc_rr&> __t(__c, (__c + 3) / 4, __alloc());
|
|
__t.__construct_at_end(move_iterator<pointer>(__begin_), move_iterator<pointer>(__end_));
|
|
std::swap(__first_, __t.__first_);
|
|
std::swap(__begin_, __t.__begin_);
|
|
std::swap(__end_, __t.__end_);
|
|
std::swap(__end_cap(), __t.__end_cap());
|
|
}
|
|
}
|
|
__alloc_traits::construct(__alloc(), std::__to_address(__begin_ - 1), std::move(__x));
|
|
--__begin_;
|
|
}
|
|
|
|
template <class _Tp, class _Allocator>
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI void
|
|
__split_buffer<_Tp, _Allocator>::push_back(const_reference __x) {
|
|
if (__end_ == __end_cap()) {
|
|
if (__begin_ > __first_) {
|
|
difference_type __d = __begin_ - __first_;
|
|
__d = (__d + 1) / 2;
|
|
__end_ = std::move(__begin_, __end_, __begin_ - __d);
|
|
__begin_ -= __d;
|
|
} else {
|
|
size_type __c = std::max<size_type>(2 * static_cast<size_t>(__end_cap() - __first_), 1);
|
|
__split_buffer<value_type, __alloc_rr&> __t(__c, __c / 4, __alloc());
|
|
__t.__construct_at_end(move_iterator<pointer>(__begin_), move_iterator<pointer>(__end_));
|
|
std::swap(__first_, __t.__first_);
|
|
std::swap(__begin_, __t.__begin_);
|
|
std::swap(__end_, __t.__end_);
|
|
std::swap(__end_cap(), __t.__end_cap());
|
|
}
|
|
}
|
|
__alloc_traits::construct(__alloc(), std::__to_address(__end_), __x);
|
|
++__end_;
|
|
}
|
|
|
|
template <class _Tp, class _Allocator>
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator>::push_back(value_type&& __x) {
|
|
if (__end_ == __end_cap()) {
|
|
if (__begin_ > __first_) {
|
|
difference_type __d = __begin_ - __first_;
|
|
__d = (__d + 1) / 2;
|
|
__end_ = std::move(__begin_, __end_, __begin_ - __d);
|
|
__begin_ -= __d;
|
|
} else {
|
|
size_type __c = std::max<size_type>(2 * static_cast<size_t>(__end_cap() - __first_), 1);
|
|
__split_buffer<value_type, __alloc_rr&> __t(__c, __c / 4, __alloc());
|
|
__t.__construct_at_end(move_iterator<pointer>(__begin_), move_iterator<pointer>(__end_));
|
|
std::swap(__first_, __t.__first_);
|
|
std::swap(__begin_, __t.__begin_);
|
|
std::swap(__end_, __t.__end_);
|
|
std::swap(__end_cap(), __t.__end_cap());
|
|
}
|
|
}
|
|
__alloc_traits::construct(__alloc(), std::__to_address(__end_), std::move(__x));
|
|
++__end_;
|
|
}
|
|
|
|
template <class _Tp, class _Allocator>
|
|
template <class... _Args>
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator>::emplace_back(_Args&&... __args) {
|
|
if (__end_ == __end_cap()) {
|
|
if (__begin_ > __first_) {
|
|
difference_type __d = __begin_ - __first_;
|
|
__d = (__d + 1) / 2;
|
|
__end_ = std::move(__begin_, __end_, __begin_ - __d);
|
|
__begin_ -= __d;
|
|
} else {
|
|
size_type __c = std::max<size_type>(2 * static_cast<size_t>(__end_cap() - __first_), 1);
|
|
__split_buffer<value_type, __alloc_rr&> __t(__c, __c / 4, __alloc());
|
|
__t.__construct_at_end(move_iterator<pointer>(__begin_), move_iterator<pointer>(__end_));
|
|
std::swap(__first_, __t.__first_);
|
|
std::swap(__begin_, __t.__begin_);
|
|
std::swap(__end_, __t.__end_);
|
|
std::swap(__end_cap(), __t.__end_cap());
|
|
}
|
|
}
|
|
__alloc_traits::construct(__alloc(), std::__to_address(__end_), std::forward<_Args>(__args)...);
|
|
++__end_;
|
|
}
|
|
|
|
template <class _Tp, class _Allocator>
|
|
_LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI void
|
|
swap(__split_buffer<_Tp, _Allocator>& __x, __split_buffer<_Tp, _Allocator>& __y) _NOEXCEPT_(_NOEXCEPT_(__x.swap(__y))) {
|
|
__x.swap(__y);
|
|
}
|
|
|
|
_LIBCPP_END_NAMESPACE_STD
|
|
|
|
_LIBCPP_POP_MACROS
|
|
|
|
#endif // _LIBCPP___SPLIT_BUFFER
|