2019-09-05 01:57:56 +03:00
|
|
|
// xmemory internal header
|
|
|
|
|
|
|
|
// Copyright (c) Microsoft Corporation.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
#ifndef _XMEMORY_
|
|
|
|
#define _XMEMORY_
|
|
|
|
#include <yvals_core.h>
|
|
|
|
#if _STL_COMPILER_PREPROCESSOR
|
|
|
|
#include <cstdint>
|
|
|
|
#include <cstdlib>
|
|
|
|
#include <limits>
|
|
|
|
#include <new>
|
|
|
|
#include <xatomic.h>
|
|
|
|
#include <xutility>
|
|
|
|
|
2021-02-26 05:26:14 +03:00
|
|
|
#if _HAS_CXX20
|
|
|
|
#include <tuple>
|
|
|
|
#endif // _HAS_CXX20
|
|
|
|
|
2019-09-05 01:57:56 +03:00
|
|
|
#pragma pack(push, _CRT_PACKING)
|
|
|
|
#pragma warning(push, _STL_WARNING_LEVEL)
|
|
|
|
#pragma warning(disable : _STL_DISABLED_WARNINGS)
|
|
|
|
_STL_DISABLE_CLANG_WARNINGS
|
|
|
|
#pragma push_macro("new")
|
|
|
|
#undef new
|
|
|
|
|
|
|
|
_STD_BEGIN
|
2020-02-21 16:55:22 +03:00
|
|
|
// STRUCT TEMPLATE _Tidy_guard
|
|
|
|
template <class _Ty>
|
2020-12-03 02:10:23 +03:00
|
|
|
struct _NODISCARD _Tidy_guard { // class with destructor that calls _Tidy
|
2020-02-21 16:55:22 +03:00
|
|
|
_Ty* _Target;
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20_DYNALLOC ~_Tidy_guard() {
|
2020-02-21 16:55:22 +03:00
|
|
|
if (_Target) {
|
|
|
|
_Target->_Tidy();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// STRUCT TEMPLATE _Tidy_deallocate_guard
|
|
|
|
template <class _Ty>
|
2020-12-03 02:10:23 +03:00
|
|
|
struct _NODISCARD _Tidy_deallocate_guard { // class with destructor that calls _Tidy_deallocate
|
2020-02-21 16:55:22 +03:00
|
|
|
_Ty* _Target;
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20_DYNALLOC ~_Tidy_deallocate_guard() {
|
2020-02-21 16:55:22 +03:00
|
|
|
if (_Target) {
|
|
|
|
_Target->_Tidy_deallocate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// VARIABLE TEMPLATE _Nothrow_compare
|
|
|
|
template <class _Keycmp, class _Lhs, class _Rhs>
|
|
|
|
_INLINE_VAR constexpr bool _Nothrow_compare = noexcept(
|
|
|
|
static_cast<bool>(_STD declval<const _Keycmp&>()(_STD declval<const _Lhs&>(), _STD declval<const _Rhs&>())));
|
|
|
|
|
2019-09-05 01:57:56 +03:00
|
|
|
// FUNCTION TEMPLATE _Get_size_of_n
|
|
|
|
template <size_t _Ty_size>
|
|
|
|
_NODISCARD constexpr size_t _Get_size_of_n(const size_t _Count) {
|
|
|
|
constexpr bool _Overflow_is_possible = _Ty_size > 1;
|
|
|
|
|
2021-01-06 04:19:12 +03:00
|
|
|
if constexpr (_Overflow_is_possible) {
|
2020-03-29 04:53:15 +03:00
|
|
|
constexpr size_t _Max_possible = static_cast<size_t>(-1) / _Ty_size;
|
|
|
|
if (_Count > _Max_possible) {
|
|
|
|
_Throw_bad_array_new_length(); // multiply overflow
|
2019-09-05 01:57:56 +03:00
|
|
|
}
|
2020-03-29 04:53:15 +03:00
|
|
|
}
|
2019-09-05 01:57:56 +03:00
|
|
|
|
|
|
|
return _Count * _Ty_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
// VARIABLE TEMPLATE _New_alignof
|
|
|
|
template <class _Ty>
|
2020-02-21 16:55:22 +03:00
|
|
|
_INLINE_VAR constexpr size_t _New_alignof = (_STD max)(alignof(_Ty),
|
2019-10-11 23:43:06 +03:00
|
|
|
static_cast<size_t>(__STDCPP_DEFAULT_NEW_ALIGNMENT__) // TRANSITION, VSO-522105
|
2019-09-05 01:57:56 +03:00
|
|
|
);
|
|
|
|
|
|
|
|
// STRUCT _Default_allocate_traits
|
|
|
|
struct _Default_allocate_traits {
|
2021-01-08 06:01:52 +03:00
|
|
|
__declspec(allocator) static
|
|
|
|
#ifdef __clang__ // Clang and MSVC implement P0784R7 differently; see GH-1532
|
|
|
|
_CONSTEXPR20_DYNALLOC
|
|
|
|
#endif // __clang__
|
|
|
|
void* _Allocate(const size_t _Bytes) {
|
2019-09-05 01:57:56 +03:00
|
|
|
return ::operator new(_Bytes);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef __cpp_aligned_new
|
2021-01-08 06:01:52 +03:00
|
|
|
__declspec(allocator) static
|
|
|
|
#ifdef __clang__ // Clang and MSVC implement P0784R7 differently; see GH-1532
|
|
|
|
_CONSTEXPR20_DYNALLOC
|
|
|
|
#endif // __clang__
|
|
|
|
void* _Allocate_aligned(const size_t _Bytes, const size_t _Align) {
|
|
|
|
#ifdef __clang__ // Clang and MSVC implement P0784R7 differently; see GH-1532
|
|
|
|
#ifdef __cpp_lib_constexpr_dynamic_alloc
|
|
|
|
if (_STD is_constant_evaluated()) {
|
|
|
|
return ::operator new(_Bytes);
|
|
|
|
} else
|
|
|
|
#endif // __cpp_lib_constexpr_dynamic_alloc
|
|
|
|
#endif // __clang__
|
|
|
|
{
|
|
|
|
return ::operator new (_Bytes, align_val_t{_Align});
|
|
|
|
}
|
2019-09-05 01:57:56 +03:00
|
|
|
}
|
|
|
|
#endif // __cpp_aligned_new
|
|
|
|
};
|
|
|
|
|
|
|
|
constexpr bool _Is_pow_2(const size_t _Value) noexcept {
|
|
|
|
return _Value != 0 && (_Value & (_Value - 1)) == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(_M_IX86) || defined(_M_X64)
|
|
|
|
constexpr size_t _Big_allocation_threshold = 4096;
|
|
|
|
constexpr size_t _Big_allocation_alignment = 32;
|
|
|
|
|
|
|
|
static_assert(2 * sizeof(void*) <= _Big_allocation_alignment,
|
|
|
|
"Big allocation alignment should at least match vector register alignment");
|
|
|
|
static_assert(_Is_pow_2(_Big_allocation_alignment), "Big allocation alignment must be a power of two");
|
|
|
|
|
|
|
|
#ifdef _DEBUG
|
|
|
|
constexpr size_t _Non_user_size = 2 * sizeof(void*) + _Big_allocation_alignment - 1;
|
|
|
|
#else // _DEBUG
|
2020-12-09 23:46:07 +03:00
|
|
|
constexpr size_t _Non_user_size = sizeof(void*) + _Big_allocation_alignment - 1;
|
2019-09-05 01:57:56 +03:00
|
|
|
#endif // _DEBUG
|
|
|
|
|
|
|
|
#ifdef _WIN64
|
|
|
|
constexpr size_t _Big_allocation_sentinel = 0xFAFAFAFAFAFAFAFAULL;
|
|
|
|
#else // ^^^ _WIN64 ^^^ // vvv !_WIN64 vvv
|
|
|
|
constexpr size_t _Big_allocation_sentinel = 0xFAFAFAFAUL;
|
|
|
|
#endif // _WIN64
|
|
|
|
|
|
|
|
// FUNCTION _Allocate_manually_vector_aligned
|
|
|
|
template <class _Traits>
|
2020-04-13 23:09:34 +03:00
|
|
|
__declspec(allocator) void* _Allocate_manually_vector_aligned(const size_t _Bytes) {
|
2019-09-05 01:57:56 +03:00
|
|
|
// allocate _Bytes manually aligned to at least _Big_allocation_alignment
|
|
|
|
const size_t _Block_size = _Non_user_size + _Bytes;
|
|
|
|
if (_Block_size <= _Bytes) {
|
|
|
|
_Throw_bad_array_new_length(); // add overflow
|
|
|
|
}
|
|
|
|
|
|
|
|
const uintptr_t _Ptr_container = reinterpret_cast<uintptr_t>(_Traits::_Allocate(_Block_size));
|
|
|
|
_STL_VERIFY(_Ptr_container != 0, "invalid argument"); // validate even in release since we're doing p[-1]
|
|
|
|
void* const _Ptr = reinterpret_cast<void*>((_Ptr_container + _Non_user_size) & ~(_Big_allocation_alignment - 1));
|
|
|
|
static_cast<uintptr_t*>(_Ptr)[-1] = _Ptr_container;
|
|
|
|
|
|
|
|
#ifdef _DEBUG
|
|
|
|
static_cast<uintptr_t*>(_Ptr)[-2] = _Big_allocation_sentinel;
|
|
|
|
#endif // _DEBUG
|
|
|
|
return _Ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// FUNCTION TEMPLATE _Adjust_manually_vector_aligned
|
|
|
|
inline void _Adjust_manually_vector_aligned(void*& _Ptr, size_t& _Bytes) {
|
|
|
|
// adjust parameters from _Allocate_manually_vector_aligned to pass to operator delete
|
|
|
|
_Bytes += _Non_user_size;
|
|
|
|
|
|
|
|
const uintptr_t* const _Ptr_user = reinterpret_cast<uintptr_t*>(_Ptr);
|
|
|
|
const uintptr_t _Ptr_container = _Ptr_user[-1];
|
|
|
|
|
|
|
|
// If the following asserts, it likely means that we are performing
|
|
|
|
// an aligned delete on memory coming from an unaligned allocation.
|
|
|
|
_STL_ASSERT(_Ptr_user[-2] == _Big_allocation_sentinel, "invalid argument");
|
|
|
|
|
|
|
|
// Extra paranoia on aligned allocation/deallocation; ensure _Ptr_container is
|
|
|
|
// in range [_Min_back_shift, _Non_user_size]
|
|
|
|
#ifdef _DEBUG
|
|
|
|
constexpr uintptr_t _Min_back_shift = 2 * sizeof(void*);
|
|
|
|
#else // ^^^ _DEBUG ^^^ // vvv !_DEBUG vvv
|
|
|
|
constexpr uintptr_t _Min_back_shift = sizeof(void*);
|
|
|
|
#endif // _DEBUG
|
|
|
|
const uintptr_t _Back_shift = reinterpret_cast<uintptr_t>(_Ptr) - _Ptr_container;
|
|
|
|
_STL_VERIFY(_Back_shift >= _Min_back_shift && _Back_shift <= _Non_user_size, "invalid argument");
|
|
|
|
_Ptr = reinterpret_cast<void*>(_Ptr_container);
|
|
|
|
}
|
|
|
|
#endif // defined(_M_IX86) || defined(_M_X64)
|
|
|
|
|
|
|
|
// FUNCTION TEMPLATES _Allocate and _Deallocate
|
|
|
|
#ifdef __cpp_aligned_new
|
|
|
|
template <size_t _Align, class _Traits = _Default_allocate_traits,
|
|
|
|
enable_if_t<(_Align > __STDCPP_DEFAULT_NEW_ALIGNMENT__), int> = 0>
|
2021-01-08 06:01:52 +03:00
|
|
|
__declspec(allocator) _CONSTEXPR20_DYNALLOC void* _Allocate(const size_t _Bytes) {
|
2019-09-05 01:57:56 +03:00
|
|
|
// allocate _Bytes when __cpp_aligned_new && _Align > __STDCPP_DEFAULT_NEW_ALIGNMENT__
|
|
|
|
if (_Bytes == 0) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2021-01-08 06:01:52 +03:00
|
|
|
#ifdef __cpp_lib_constexpr_dynamic_alloc // TRANSITION, GH-1532
|
|
|
|
if (_STD is_constant_evaluated()) {
|
|
|
|
return _Traits::_Allocate(_Bytes);
|
|
|
|
} else
|
|
|
|
#endif // __cpp_lib_constexpr_dynamic_alloc
|
|
|
|
{
|
|
|
|
size_t _Passed_align = _Align;
|
2019-09-05 01:57:56 +03:00
|
|
|
#if defined(_M_IX86) || defined(_M_X64)
|
2021-01-08 06:01:52 +03:00
|
|
|
if (_Bytes >= _Big_allocation_threshold) {
|
|
|
|
// boost the alignment of big allocations to help autovectorization
|
|
|
|
_Passed_align = (_STD max)(_Align, _Big_allocation_alignment);
|
|
|
|
}
|
2019-09-05 01:57:56 +03:00
|
|
|
#endif // defined(_M_IX86) || defined(_M_X64)
|
2021-01-08 06:01:52 +03:00
|
|
|
return _Traits::_Allocate_aligned(_Bytes, _Passed_align);
|
|
|
|
}
|
2019-09-05 01:57:56 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
template <size_t _Align, enable_if_t<(_Align > __STDCPP_DEFAULT_NEW_ALIGNMENT__), int> = 0>
|
2021-01-08 06:01:52 +03:00
|
|
|
_CONSTEXPR20_DYNALLOC void _Deallocate(void* _Ptr, const size_t _Bytes) noexcept {
|
2019-09-05 01:57:56 +03:00
|
|
|
// deallocate storage allocated by _Allocate when __cpp_aligned_new && _Align > __STDCPP_DEFAULT_NEW_ALIGNMENT__
|
2021-01-08 06:01:52 +03:00
|
|
|
#ifdef __cpp_lib_constexpr_dynamic_alloc // TRANSITION, GH-1532
|
|
|
|
if (_STD is_constant_evaluated()) {
|
|
|
|
::operator delete(_Ptr);
|
|
|
|
} else
|
|
|
|
#endif // __cpp_lib_constexpr_dynamic_alloc
|
|
|
|
{
|
|
|
|
size_t _Passed_align = _Align;
|
2019-09-05 01:57:56 +03:00
|
|
|
#if defined(_M_IX86) || defined(_M_X64)
|
2021-01-08 06:01:52 +03:00
|
|
|
if (_Bytes >= _Big_allocation_threshold) { // boost the alignment of big allocations to help autovectorization
|
|
|
|
_Passed_align = (_STD max)(_Align, _Big_allocation_alignment);
|
|
|
|
}
|
2019-09-05 01:57:56 +03:00
|
|
|
#endif // defined(_M_IX86) || defined(_M_X64)
|
2021-01-08 06:01:52 +03:00
|
|
|
::operator delete (_Ptr, _Bytes, align_val_t{_Passed_align});
|
|
|
|
}
|
2019-09-05 01:57:56 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
#define _HAS_ALIGNED_NEW 1
|
|
|
|
#else // ^^^ __cpp_aligned_new ^^^ / vvv !__cpp_aligned_new vvv
|
|
|
|
#define _HAS_ALIGNED_NEW 0
|
|
|
|
#endif // __cpp_aligned_new
|
|
|
|
|
|
|
|
template <size_t _Align, class _Traits = _Default_allocate_traits,
|
|
|
|
enable_if_t<(!_HAS_ALIGNED_NEW || _Align <= __STDCPP_DEFAULT_NEW_ALIGNMENT__), int> = 0>
|
2021-01-08 06:01:52 +03:00
|
|
|
__declspec(allocator) _CONSTEXPR20_DYNALLOC void* _Allocate(const size_t _Bytes) {
|
2019-09-05 01:57:56 +03:00
|
|
|
// allocate _Bytes when !_HAS_ALIGNED_NEW || _Align <= __STDCPP_DEFAULT_NEW_ALIGNMENT__
|
|
|
|
#if defined(_M_IX86) || defined(_M_X64)
|
2021-01-08 06:01:52 +03:00
|
|
|
#ifdef __cpp_lib_constexpr_dynamic_alloc // TRANSITION, GH-1532
|
|
|
|
if (!_STD is_constant_evaluated())
|
|
|
|
#endif // __cpp_lib_constexpr_dynamic_alloc
|
|
|
|
{
|
|
|
|
if (_Bytes >= _Big_allocation_threshold) { // boost the alignment of big allocations to help autovectorization
|
|
|
|
return _Allocate_manually_vector_aligned<_Traits>(_Bytes);
|
|
|
|
}
|
2019-09-05 01:57:56 +03:00
|
|
|
}
|
|
|
|
#endif // defined(_M_IX86) || defined(_M_X64)
|
|
|
|
|
|
|
|
if (_Bytes != 0) {
|
|
|
|
return _Traits::_Allocate(_Bytes);
|
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <size_t _Align, enable_if_t<(!_HAS_ALIGNED_NEW || _Align <= __STDCPP_DEFAULT_NEW_ALIGNMENT__), int> = 0>
|
2021-01-08 06:01:52 +03:00
|
|
|
_CONSTEXPR20_DYNALLOC void _Deallocate(void* _Ptr, size_t _Bytes) noexcept {
|
2019-09-05 01:57:56 +03:00
|
|
|
// deallocate storage allocated by _Allocate when !_HAS_ALIGNED_NEW || _Align <= __STDCPP_DEFAULT_NEW_ALIGNMENT__
|
2021-01-08 06:01:52 +03:00
|
|
|
#ifdef __cpp_lib_constexpr_dynamic_alloc // TRANSITION, GH-1532
|
|
|
|
if (_STD is_constant_evaluated()) {
|
|
|
|
::operator delete(_Ptr);
|
|
|
|
} else
|
|
|
|
#endif // __cpp_lib_constexpr_dynamic_alloc
|
|
|
|
{
|
2019-09-05 01:57:56 +03:00
|
|
|
#if defined(_M_IX86) || defined(_M_X64)
|
2021-01-08 06:01:52 +03:00
|
|
|
if (_Bytes >= _Big_allocation_threshold) { // boost the alignment of big allocations to help autovectorization
|
|
|
|
_Adjust_manually_vector_aligned(_Ptr, _Bytes);
|
|
|
|
}
|
2019-09-05 01:57:56 +03:00
|
|
|
#endif // defined(_M_IX86) || defined(_M_X64)
|
2021-01-08 06:01:52 +03:00
|
|
|
::operator delete(_Ptr, _Bytes);
|
|
|
|
}
|
2019-09-05 01:57:56 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
#undef _HAS_ALIGNED_NEW
|
|
|
|
|
|
|
|
// FUNCTION TEMPLATE _Global_new
|
|
|
|
template <class _Ty, class... _Types>
|
|
|
|
_Ty* _Global_new(_Types&&... _Args) { // acts as "new" while disallowing user overload selection
|
2020-12-03 02:10:23 +03:00
|
|
|
struct _NODISCARD _Guard_type {
|
2019-09-05 01:57:56 +03:00
|
|
|
void* _Result;
|
|
|
|
~_Guard_type() {
|
|
|
|
if (_Result) {
|
|
|
|
_Deallocate<_New_alignof<_Ty>>(_Result, sizeof(_Ty));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
_Guard_type _Guard{_Allocate<_New_alignof<_Ty>>(sizeof(_Ty))};
|
|
|
|
::new (_Guard._Result) _Ty(_STD forward<_Types>(_Args)...);
|
|
|
|
return static_cast<_Ty*>(_STD exchange(_Guard._Result, nullptr));
|
|
|
|
}
|
|
|
|
|
|
|
|
// ALIAS TEMPLATE _Rebind_pointer_t
|
|
|
|
template <class _Ptr, class _Ty>
|
|
|
|
using _Rebind_pointer_t = typename pointer_traits<_Ptr>::template rebind<_Ty>;
|
|
|
|
|
|
|
|
// FUNCTION TEMPLATE _Refancy
|
|
|
|
template <class _Pointer, enable_if_t<!is_pointer_v<_Pointer>, int> = 0>
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20 _Pointer _Refancy(typename pointer_traits<_Pointer>::element_type* _Ptr) noexcept {
|
2019-09-05 01:57:56 +03:00
|
|
|
return pointer_traits<_Pointer>::pointer_to(*_Ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Pointer, enable_if_t<is_pointer_v<_Pointer>, int> = 0>
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20 _Pointer _Refancy(_Pointer _Ptr) noexcept {
|
2019-09-05 01:57:56 +03:00
|
|
|
return _Ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// FUNCTION TEMPLATE _Destroy_in_place
|
2020-08-12 22:47:52 +03:00
|
|
|
template <class _NoThrowFwdIt, class _NoThrowSentinel>
|
2020-09-23 01:02:43 +03:00
|
|
|
_CONSTEXPR20_DYNALLOC void _Destroy_range(_NoThrowFwdIt _First, _NoThrowSentinel _Last) noexcept;
|
2020-08-12 22:47:52 +03:00
|
|
|
|
2019-09-05 01:57:56 +03:00
|
|
|
template <class _Ty>
|
2020-09-23 01:02:43 +03:00
|
|
|
_CONSTEXPR20_DYNALLOC void _Destroy_in_place(_Ty& _Obj) noexcept {
|
2020-08-12 22:47:52 +03:00
|
|
|
if constexpr (is_array_v<_Ty>) {
|
|
|
|
_Destroy_range(_Obj, _Obj + extent_v<_Ty>);
|
2021-01-06 04:19:12 +03:00
|
|
|
} else {
|
2020-08-12 22:47:52 +03:00
|
|
|
_Obj.~_Ty();
|
|
|
|
}
|
2019-09-05 01:57:56 +03:00
|
|
|
}
|
|
|
|
|
2021-01-08 06:01:52 +03:00
|
|
|
#if _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE destroy_at
|
|
|
|
template <class _Ty>
|
|
|
|
_CONSTEXPR20_DYNALLOC void destroy_at(_Ty* const _Location) noexcept /* strengthened */ {
|
|
|
|
#if _HAS_CXX20
|
|
|
|
if constexpr (is_array_v<_Ty>) {
|
|
|
|
_Destroy_range(_STD begin(*_Location), _STD end(*_Location));
|
|
|
|
} else
|
|
|
|
#endif // _HAS_CXX20
|
|
|
|
{
|
|
|
|
_Location->~_Ty();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif // _HAS_CXX17
|
|
|
|
|
2019-09-05 01:57:56 +03:00
|
|
|
// FUNCTION TEMPLATE _Const_cast
|
|
|
|
template <class _Ptrty>
|
|
|
|
auto _Const_cast(_Ptrty _Ptr) noexcept { // remove constness from a fancy pointer
|
|
|
|
using _Elem = typename pointer_traits<_Ptrty>::element_type;
|
|
|
|
using _Modifiable = remove_const_t<_Elem>;
|
|
|
|
using _Dest = typename pointer_traits<_Ptrty>::template rebind<_Modifiable>;
|
|
|
|
|
|
|
|
return pointer_traits<_Dest>::pointer_to(const_cast<_Modifiable&>(*_Ptr));
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Ty>
|
|
|
|
auto _Const_cast(_Ty* _Ptr) noexcept {
|
|
|
|
return const_cast<remove_const_t<_Ty>*>(_Ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
// STRUCT TEMPLATE _Get_pointer_type
|
|
|
|
template <class _Ty, class = void>
|
|
|
|
struct _Get_pointer_type {
|
|
|
|
using type = typename _Ty::value_type*;
|
|
|
|
};
|
|
|
|
|
|
|
|
_STL_DISABLE_DEPRECATED_WARNING
|
|
|
|
template <class _Ty>
|
|
|
|
struct _Get_pointer_type<_Ty, void_t<typename _Ty::pointer>> {
|
|
|
|
using type = typename _Ty::pointer;
|
|
|
|
};
|
|
|
|
_STL_RESTORE_DEPRECATED_WARNING
|
|
|
|
|
|
|
|
// STRUCT TEMPLATE _Get_const_pointer_type
|
|
|
|
template <class _Ty, class = void>
|
|
|
|
struct _Get_const_pointer_type {
|
|
|
|
using _Ptrty = typename _Get_pointer_type<_Ty>::type;
|
|
|
|
using _Valty = typename _Ty::value_type;
|
|
|
|
using type = typename pointer_traits<_Ptrty>::template rebind<const _Valty>;
|
|
|
|
};
|
|
|
|
|
|
|
|
_STL_DISABLE_DEPRECATED_WARNING
|
|
|
|
template <class _Ty>
|
|
|
|
struct _Get_const_pointer_type<_Ty, void_t<typename _Ty::const_pointer>> {
|
|
|
|
using type = typename _Ty::const_pointer;
|
|
|
|
};
|
|
|
|
_STL_RESTORE_DEPRECATED_WARNING
|
|
|
|
|
|
|
|
// STRUCT TEMPLATE _Get_void_pointer_type
|
|
|
|
template <class _Ty, class = void>
|
|
|
|
struct _Get_void_pointer_type {
|
|
|
|
using _Ptrty = typename _Get_pointer_type<_Ty>::type;
|
|
|
|
using type = typename pointer_traits<_Ptrty>::template rebind<void>;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <class _Ty>
|
|
|
|
struct _Get_void_pointer_type<_Ty, void_t<typename _Ty::void_pointer>> {
|
|
|
|
using type = typename _Ty::void_pointer;
|
|
|
|
};
|
|
|
|
|
|
|
|
// STRUCT TEMPLATE _Get_const_void_pointer_type
|
|
|
|
template <class _Ty, class = void>
|
|
|
|
struct _Get_const_void_pointer_type {
|
|
|
|
using _Ptrty = typename _Get_pointer_type<_Ty>::type;
|
|
|
|
using type = typename pointer_traits<_Ptrty>::template rebind<const void>;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <class _Ty>
|
|
|
|
struct _Get_const_void_pointer_type<_Ty, void_t<typename _Ty::const_void_pointer>> {
|
|
|
|
using type = typename _Ty::const_void_pointer;
|
|
|
|
};
|
|
|
|
|
|
|
|
// STRUCT TEMPLATE _Get_difference_type
|
|
|
|
template <class _Ty, class = void>
|
|
|
|
struct _Get_difference_type {
|
|
|
|
using _Ptrty = typename _Get_pointer_type<_Ty>::type;
|
|
|
|
using type = typename pointer_traits<_Ptrty>::difference_type;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <class _Ty>
|
|
|
|
struct _Get_difference_type<_Ty, void_t<typename _Ty::difference_type>> {
|
|
|
|
using type = typename _Ty::difference_type;
|
|
|
|
};
|
|
|
|
|
|
|
|
// STRUCT TEMPLATE _Get_size_type
|
|
|
|
template <class _Ty, class = void>
|
|
|
|
struct _Get_size_type {
|
|
|
|
using type = make_unsigned_t<typename _Get_difference_type<_Ty>::type>;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <class _Ty>
|
|
|
|
struct _Get_size_type<_Ty, void_t<typename _Ty::size_type>> {
|
|
|
|
using type = typename _Ty::size_type;
|
|
|
|
};
|
|
|
|
|
|
|
|
// STRUCT TEMPLATE _Get_propagate_on_container_copy
|
|
|
|
template <class _Ty, class = void>
|
|
|
|
struct _Get_propagate_on_container_copy {
|
|
|
|
using type = false_type;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <class _Ty>
|
|
|
|
struct _Get_propagate_on_container_copy<_Ty, void_t<typename _Ty::propagate_on_container_copy_assignment>> {
|
|
|
|
using type = typename _Ty::propagate_on_container_copy_assignment;
|
|
|
|
};
|
|
|
|
|
|
|
|
// STRUCT TEMPLATE _Get_propagate_on_container_move
|
|
|
|
template <class _Ty, class = void>
|
|
|
|
struct _Get_propagate_on_container_move {
|
|
|
|
using type = false_type;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <class _Ty>
|
|
|
|
struct _Get_propagate_on_container_move<_Ty, void_t<typename _Ty::propagate_on_container_move_assignment>> {
|
|
|
|
using type = typename _Ty::propagate_on_container_move_assignment;
|
|
|
|
};
|
|
|
|
|
|
|
|
// STRUCT TEMPLATE _Get_propagate_on_container_swap
|
|
|
|
template <class _Ty, class = void>
|
|
|
|
struct _Get_propagate_on_container_swap {
|
|
|
|
using type = false_type;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <class _Ty>
|
|
|
|
struct _Get_propagate_on_container_swap<_Ty, void_t<typename _Ty::propagate_on_container_swap>> {
|
|
|
|
using type = typename _Ty::propagate_on_container_swap;
|
|
|
|
};
|
|
|
|
|
|
|
|
// STRUCT TEMPLATE _Get_is_always_equal
|
|
|
|
template <class _Ty, class = void>
|
|
|
|
struct _Get_is_always_equal {
|
2020-11-07 03:31:40 +03:00
|
|
|
using type = bool_constant<is_empty_v<_Ty>>;
|
2019-09-05 01:57:56 +03:00
|
|
|
};
|
|
|
|
|
2020-12-02 02:39:26 +03:00
|
|
|
_STL_DISABLE_DEPRECATED_WARNING
|
2019-09-05 01:57:56 +03:00
|
|
|
template <class _Ty>
|
|
|
|
struct _Get_is_always_equal<_Ty, void_t<typename _Ty::is_always_equal>> {
|
|
|
|
using type = typename _Ty::is_always_equal;
|
|
|
|
};
|
2020-12-02 02:39:26 +03:00
|
|
|
_STL_RESTORE_DEPRECATED_WARNING
|
2019-09-05 01:57:56 +03:00
|
|
|
|
|
|
|
// STRUCT TEMPLATE _Get_rebind_type
|
|
|
|
template <class _Ty, class _Other, class = void>
|
|
|
|
struct _Get_rebind_type {
|
|
|
|
using type = typename _Replace_first_parameter<_Other, _Ty>::type;
|
|
|
|
};
|
|
|
|
|
|
|
|
_STL_DISABLE_DEPRECATED_WARNING
|
|
|
|
template <class _Ty, class _Other>
|
|
|
|
struct _Get_rebind_type<_Ty, _Other, void_t<typename _Ty::template rebind<_Other>::other>> {
|
|
|
|
using type = typename _Ty::template rebind<_Other>::other;
|
|
|
|
};
|
|
|
|
_STL_RESTORE_DEPRECATED_WARNING
|
|
|
|
|
|
|
|
// STRUCT TEMPLATE _Is_default_allocator
|
|
|
|
template <class _Ty>
|
|
|
|
class allocator;
|
|
|
|
|
|
|
|
template <class _Alloc, class = void>
|
|
|
|
struct _Is_default_allocator : false_type {};
|
|
|
|
|
|
|
|
template <class _Ty>
|
|
|
|
struct _Is_default_allocator<allocator<_Ty>, void_t<typename allocator<_Ty>::_From_primary>>
|
|
|
|
: is_same<typename allocator<_Ty>::_From_primary, allocator<_Ty>>::type {};
|
|
|
|
|
|
|
|
// ALIAS TEMPLATES _Uses_default_construct
|
|
|
|
template <class _Void, class... _Types>
|
|
|
|
struct _Has_no_allocator_construct : true_type {};
|
|
|
|
|
|
|
|
_STL_DISABLE_DEPRECATED_WARNING
|
|
|
|
template <class _Alloc, class _Ptr, class... _Args>
|
|
|
|
struct _Has_no_allocator_construct<
|
|
|
|
void_t<decltype(_STD declval<_Alloc&>().construct(_STD declval<_Ptr>(), _STD declval<_Args>()...))>, _Alloc, _Ptr,
|
|
|
|
_Args...> : false_type {};
|
|
|
|
_STL_RESTORE_DEPRECATED_WARNING
|
|
|
|
|
|
|
|
template <class _Alloc, class _Ptr, class... _Args>
|
|
|
|
using _Uses_default_construct =
|
|
|
|
disjunction<_Is_default_allocator<_Alloc>, _Has_no_allocator_construct<void, _Alloc, _Ptr, _Args...>>;
|
|
|
|
|
|
|
|
// ALIAS TEMPLATE _Uses_default_destroy AND _Uses_default_destroy_t
|
|
|
|
template <class _Alloc, class _Ptr, class = void>
|
|
|
|
struct _Has_no_alloc_destroy : true_type {};
|
|
|
|
|
|
|
|
_STL_DISABLE_DEPRECATED_WARNING
|
|
|
|
template <class _Alloc, class _Ptr>
|
|
|
|
struct _Has_no_alloc_destroy<_Alloc, _Ptr, void_t<decltype(_STD declval<_Alloc&>().destroy(_STD declval<_Ptr>()))>>
|
|
|
|
: false_type {};
|
|
|
|
_STL_RESTORE_DEPRECATED_WARNING
|
|
|
|
|
|
|
|
template <class _Alloc, class _Ptr>
|
|
|
|
using _Uses_default_destroy = disjunction<_Is_default_allocator<_Alloc>, _Has_no_alloc_destroy<_Alloc, _Ptr>>;
|
|
|
|
|
|
|
|
template <class _Alloc, class _Ptr>
|
|
|
|
using _Uses_default_destroy_t = typename _Uses_default_destroy<_Alloc, _Ptr>::type;
|
|
|
|
|
|
|
|
// STRUCT TEMPLATE _Has_allocate_hint
|
|
|
|
template <class _Alloc, class _Size_type, class _Const_void_pointer, class = void>
|
|
|
|
struct _Has_allocate_hint : false_type {};
|
|
|
|
|
|
|
|
_STL_DISABLE_DEPRECATED_WARNING
|
|
|
|
template <class _Alloc, class _Size_type, class _Const_void_pointer>
|
|
|
|
struct _Has_allocate_hint<_Alloc, _Size_type, _Const_void_pointer,
|
|
|
|
void_t<decltype(_STD declval<_Alloc&>().allocate(
|
|
|
|
_STD declval<const _Size_type&>(), _STD declval<const _Const_void_pointer&>()))>> : true_type {};
|
|
|
|
_STL_RESTORE_DEPRECATED_WARNING
|
|
|
|
|
|
|
|
// STRUCT TEMPLATE _Has_max_size
|
|
|
|
template <class _Alloc, class = void>
|
|
|
|
struct _Has_max_size : false_type {};
|
|
|
|
|
|
|
|
_STL_DISABLE_DEPRECATED_WARNING
|
|
|
|
template <class _Alloc>
|
|
|
|
struct _Has_max_size<_Alloc, void_t<decltype(_STD declval<const _Alloc&>().max_size())>> : true_type {};
|
|
|
|
_STL_RESTORE_DEPRECATED_WARNING
|
|
|
|
|
|
|
|
// STRUCT TEMPLATE _Has_select_on_container_copy_construction
|
|
|
|
template <class _Alloc, class = void>
|
|
|
|
struct _Has_select_on_container_copy_construction : false_type {};
|
|
|
|
|
|
|
|
template <class _Alloc>
|
|
|
|
struct _Has_select_on_container_copy_construction<_Alloc,
|
|
|
|
void_t<decltype(_STD declval<const _Alloc&>().select_on_container_copy_construction())>> : true_type {};
|
|
|
|
|
|
|
|
// STRUCT TEMPLATE allocator_traits
|
|
|
|
template <class _Alloc>
|
|
|
|
struct allocator_traits;
|
|
|
|
|
|
|
|
_STL_DISABLE_DEPRECATED_WARNING
|
|
|
|
template <class _Alloc>
|
|
|
|
struct _Normal_allocator_traits { // defines traits for allocators
|
|
|
|
using allocator_type = _Alloc;
|
|
|
|
using value_type = typename _Alloc::value_type;
|
|
|
|
|
|
|
|
using pointer = typename _Get_pointer_type<_Alloc>::type;
|
|
|
|
using const_pointer = typename _Get_const_pointer_type<_Alloc>::type;
|
|
|
|
using void_pointer = typename _Get_void_pointer_type<_Alloc>::type;
|
|
|
|
using const_void_pointer = typename _Get_const_void_pointer_type<_Alloc>::type;
|
|
|
|
|
|
|
|
using size_type = typename _Get_size_type<_Alloc>::type;
|
|
|
|
using difference_type = typename _Get_difference_type<_Alloc>::type;
|
|
|
|
|
|
|
|
using propagate_on_container_copy_assignment = typename _Get_propagate_on_container_copy<_Alloc>::type;
|
|
|
|
using propagate_on_container_move_assignment = typename _Get_propagate_on_container_move<_Alloc>::type;
|
|
|
|
using propagate_on_container_swap = typename _Get_propagate_on_container_swap<_Alloc>::type;
|
|
|
|
using is_always_equal = typename _Get_is_always_equal<_Alloc>::type;
|
|
|
|
|
|
|
|
template <class _Other>
|
|
|
|
using rebind_alloc = typename _Get_rebind_type<_Alloc, _Other>::type;
|
|
|
|
|
|
|
|
template <class _Other>
|
|
|
|
using rebind_traits = allocator_traits<rebind_alloc<_Other>>;
|
|
|
|
|
2021-01-08 06:01:52 +03:00
|
|
|
_NODISCARD static _CONSTEXPR20_DYNALLOC __declspec(allocator) pointer
|
|
|
|
allocate(_Alloc& _Al, _CRT_GUARDOVERFLOW const size_type _Count) {
|
2019-09-05 01:57:56 +03:00
|
|
|
return _Al.allocate(_Count);
|
|
|
|
}
|
|
|
|
|
2021-01-08 06:01:52 +03:00
|
|
|
_NODISCARD static _CONSTEXPR20_DYNALLOC __declspec(allocator) pointer
|
2020-04-13 23:09:34 +03:00
|
|
|
allocate(_Alloc& _Al, _CRT_GUARDOVERFLOW const size_type _Count, const const_void_pointer _Hint) {
|
2019-09-05 01:57:56 +03:00
|
|
|
if constexpr (_Has_allocate_hint<_Alloc, size_type, const_void_pointer>::value) {
|
|
|
|
return _Al.allocate(_Count, _Hint);
|
|
|
|
} else {
|
|
|
|
return _Al.allocate(_Count);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-08 06:01:52 +03:00
|
|
|
static _CONSTEXPR20_DYNALLOC void deallocate(_Alloc& _Al, pointer _Ptr, size_type _Count) {
|
2019-09-05 01:57:56 +03:00
|
|
|
_Al.deallocate(_Ptr, _Count);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Ty, class... _Types>
|
2021-01-08 06:01:52 +03:00
|
|
|
static _CONSTEXPR20_DYNALLOC void construct(_Alloc& _Al, _Ty* _Ptr, _Types&&... _Args) {
|
2019-09-05 01:57:56 +03:00
|
|
|
if constexpr (_Uses_default_construct<_Alloc, _Ty*, _Types...>::value) {
|
2020-04-30 12:23:37 +03:00
|
|
|
(void) _Al; // TRANSITION, DevCom-1004719
|
2021-01-08 06:01:52 +03:00
|
|
|
#ifdef __cpp_lib_constexpr_dynamic_alloc
|
|
|
|
_STD construct_at(_Ptr, _STD forward<_Types>(_Args)...);
|
|
|
|
#else // __cpp_lib_constexpr_dynamic_alloc
|
2019-09-05 01:57:56 +03:00
|
|
|
::new (static_cast<void*>(_Ptr)) _Ty(_STD forward<_Types>(_Args)...);
|
2021-01-08 06:01:52 +03:00
|
|
|
#endif // __cpp_lib_constexpr_dynamic_alloc
|
2019-09-05 01:57:56 +03:00
|
|
|
} else {
|
|
|
|
_Al.construct(_Ptr, _STD forward<_Types>(_Args)...);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Ty>
|
2021-01-08 06:01:52 +03:00
|
|
|
static _CONSTEXPR20_DYNALLOC void destroy(_Alloc& _Al, _Ty* _Ptr) {
|
2019-09-05 01:57:56 +03:00
|
|
|
if constexpr (_Uses_default_destroy<_Alloc, _Ty*>::value) {
|
2021-01-08 06:01:52 +03:00
|
|
|
#ifdef __cpp_lib_constexpr_dynamic_alloc
|
|
|
|
_STD destroy_at(_Ptr);
|
|
|
|
#else // __cpp_lib_constexpr_dynamic_alloc
|
2019-09-05 01:57:56 +03:00
|
|
|
_Ptr->~_Ty();
|
2021-01-08 06:01:52 +03:00
|
|
|
#endif // __cpp_lib_constexpr_dynamic_alloc
|
2019-09-05 01:57:56 +03:00
|
|
|
} else {
|
|
|
|
_Al.destroy(_Ptr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-08 06:01:52 +03:00
|
|
|
_NODISCARD static _CONSTEXPR20_DYNALLOC size_type max_size(const _Alloc& _Al) noexcept {
|
2019-09-05 01:57:56 +03:00
|
|
|
if constexpr (_Has_max_size<_Alloc>::value) {
|
|
|
|
return _Al.max_size();
|
|
|
|
} else {
|
|
|
|
return (numeric_limits<size_type>::max)() / sizeof(value_type);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-08 06:01:52 +03:00
|
|
|
_NODISCARD static _CONSTEXPR20_DYNALLOC _Alloc select_on_container_copy_construction(const _Alloc& _Al) {
|
2019-09-05 01:57:56 +03:00
|
|
|
if constexpr (_Has_select_on_container_copy_construction<_Alloc>::value) {
|
|
|
|
return _Al.select_on_container_copy_construction();
|
|
|
|
} else {
|
|
|
|
return _Al;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
_STL_RESTORE_DEPRECATED_WARNING
|
|
|
|
|
|
|
|
template <class _Alloc>
|
|
|
|
struct _Default_allocator_traits { // traits for std::allocator
|
|
|
|
using allocator_type = _Alloc;
|
|
|
|
using value_type = typename _Alloc::value_type;
|
|
|
|
|
|
|
|
using pointer = value_type*;
|
|
|
|
using const_pointer = const value_type*;
|
|
|
|
using void_pointer = void*;
|
|
|
|
using const_void_pointer = const void*;
|
|
|
|
|
|
|
|
using size_type = size_t;
|
|
|
|
using difference_type = ptrdiff_t;
|
|
|
|
|
|
|
|
using propagate_on_container_copy_assignment = false_type;
|
|
|
|
using propagate_on_container_move_assignment = true_type;
|
|
|
|
using propagate_on_container_swap = false_type;
|
|
|
|
using is_always_equal = true_type;
|
|
|
|
|
|
|
|
template <class _Other>
|
|
|
|
using rebind_alloc = allocator<_Other>;
|
|
|
|
|
|
|
|
template <class _Other>
|
|
|
|
using rebind_traits = allocator_traits<allocator<_Other>>;
|
|
|
|
|
2021-01-08 06:01:52 +03:00
|
|
|
_NODISCARD static _CONSTEXPR20_DYNALLOC __declspec(allocator) pointer
|
|
|
|
allocate(_Alloc& _Al, _CRT_GUARDOVERFLOW const size_type _Count) {
|
|
|
|
#ifdef __cpp_lib_constexpr_dynamic_alloc // TRANSITION, GH-1532
|
|
|
|
if (_STD is_constant_evaluated()) {
|
|
|
|
return _Al.allocate(_Count);
|
|
|
|
} else
|
|
|
|
#endif // __cpp_lib_constexpr_dynamic_alloc
|
|
|
|
{
|
|
|
|
(void) _Al;
|
|
|
|
return static_cast<pointer>(
|
|
|
|
_Allocate<_New_alignof<value_type>>(_Get_size_of_n<sizeof(value_type)>(_Count)));
|
|
|
|
}
|
2019-09-05 01:57:56 +03:00
|
|
|
}
|
|
|
|
|
2021-01-08 06:01:52 +03:00
|
|
|
_NODISCARD static _CONSTEXPR20_DYNALLOC __declspec(allocator) pointer
|
|
|
|
allocate(_Alloc& _Al, _CRT_GUARDOVERFLOW const size_type _Count, const_void_pointer) {
|
|
|
|
#ifdef __cpp_lib_constexpr_dynamic_alloc // TRANSITION, GH-1532
|
|
|
|
if (_STD is_constant_evaluated()) {
|
|
|
|
return _Al.allocate(_Count);
|
|
|
|
} else
|
|
|
|
#endif // __cpp_lib_constexpr_dynamic_alloc
|
|
|
|
{
|
|
|
|
(void) _Al;
|
|
|
|
return static_cast<pointer>(
|
|
|
|
_Allocate<_New_alignof<value_type>>(_Get_size_of_n<sizeof(value_type)>(_Count)));
|
|
|
|
}
|
2019-09-05 01:57:56 +03:00
|
|
|
}
|
|
|
|
|
2021-01-08 06:01:52 +03:00
|
|
|
static _CONSTEXPR20_DYNALLOC void deallocate(_Alloc& _Al, const pointer _Ptr, const size_type _Count) {
|
2019-09-05 01:57:56 +03:00
|
|
|
// no overflow check on the following multiply; we assume _Allocate did that check
|
2021-01-08 06:01:52 +03:00
|
|
|
#ifdef __cpp_lib_constexpr_dynamic_alloc // TRANSITION, GH-1532
|
|
|
|
if (_STD is_constant_evaluated()) {
|
|
|
|
_Al.deallocate(_Ptr, _Count);
|
|
|
|
} else
|
|
|
|
#endif // __cpp_lib_constexpr_dynamic_alloc
|
|
|
|
{
|
|
|
|
(void) _Al;
|
|
|
|
_Deallocate<_New_alignof<value_type>>(_Ptr, sizeof(value_type) * _Count);
|
|
|
|
}
|
2019-09-05 01:57:56 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Objty, class... _Types>
|
2021-01-08 06:01:52 +03:00
|
|
|
static _CONSTEXPR20_DYNALLOC void construct(_Alloc&, _Objty* const _Ptr, _Types&&... _Args) {
|
|
|
|
#ifdef __cpp_lib_constexpr_dynamic_alloc
|
|
|
|
if (_STD is_constant_evaluated()) {
|
|
|
|
_STD construct_at(_Ptr, _STD forward<_Types>(_Args)...);
|
|
|
|
} else
|
|
|
|
#endif // __cpp_lib_constexpr_dynamic_alloc
|
|
|
|
{
|
|
|
|
::new (_Voidify_iter(_Ptr)) _Objty(_STD forward<_Types>(_Args)...);
|
|
|
|
}
|
2019-09-05 01:57:56 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Uty>
|
2021-01-08 06:01:52 +03:00
|
|
|
static _CONSTEXPR20_DYNALLOC void destroy(_Alloc&, _Uty* const _Ptr) {
|
|
|
|
#ifdef __cpp_lib_constexpr_dynamic_alloc
|
|
|
|
_STD destroy_at(_Ptr);
|
|
|
|
#else // __cpp_lib_constexpr_dynamic_alloc
|
2019-09-05 01:57:56 +03:00
|
|
|
_Ptr->~_Uty();
|
2021-01-08 06:01:52 +03:00
|
|
|
#endif // __cpp_lib_constexpr_dynamic_alloc
|
2019-09-05 01:57:56 +03:00
|
|
|
}
|
|
|
|
|
2021-01-08 06:01:52 +03:00
|
|
|
_NODISCARD static _CONSTEXPR20_DYNALLOC size_type max_size(const _Alloc&) noexcept {
|
2019-09-05 01:57:56 +03:00
|
|
|
return static_cast<size_t>(-1) / sizeof(value_type);
|
|
|
|
}
|
|
|
|
|
2021-01-08 06:01:52 +03:00
|
|
|
_NODISCARD static _CONSTEXPR20_DYNALLOC _Alloc select_on_container_copy_construction(const _Alloc& _Al) {
|
2019-09-05 01:57:56 +03:00
|
|
|
return _Al;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template <class _Alloc>
|
|
|
|
struct allocator_traits : conditional_t<_Is_default_allocator<_Alloc>::value, _Default_allocator_traits<_Alloc>,
|
|
|
|
_Normal_allocator_traits<_Alloc>> {};
|
|
|
|
|
|
|
|
// _Choose_pocca returns whether an attempt to propagate allocators is necessary in copy assignment operations.
|
|
|
|
// Note that even when false_type, callers should call _Pocca as we want to assign allocators even when equal.
|
|
|
|
template <class _Alloc>
|
|
|
|
using _Choose_pocca = bool_constant<allocator_traits<_Alloc>::propagate_on_container_copy_assignment::value
|
|
|
|
&& !allocator_traits<_Alloc>::is_always_equal::value>;
|
|
|
|
|
|
|
|
struct _Equal_allocators {}; // usually allows contents to be stolen (e.g. with swap)
|
|
|
|
using _Propagate_allocators = true_type; // usually allows the allocator to be propagated, and then contents stolen
|
|
|
|
using _No_propagate_allocators = false_type; // usually turns moves into copies
|
|
|
|
|
|
|
|
template <class _Alloc>
|
|
|
|
using _Choose_pocma = conditional_t<allocator_traits<_Alloc>::is_always_equal::value, _Equal_allocators,
|
|
|
|
typename allocator_traits<_Alloc>::propagate_on_container_move_assignment::type>;
|
|
|
|
|
|
|
|
// ALIAS TEMPLATE _Rebind_alloc_t
|
|
|
|
template <class _Alloc, class _Value_type>
|
|
|
|
using _Rebind_alloc_t = typename allocator_traits<_Alloc>::template rebind_alloc<_Value_type>;
|
|
|
|
|
|
|
|
// ALIAS TEMPLATE _Maybe_rebind_alloc_t
|
|
|
|
// If _Alloc is already rebound appropriately, binds an lvalue reference to it, avoiding a copy. Otherwise, creates a
|
|
|
|
// rebound copy.
|
|
|
|
template <class _Alloc, class _Value_type>
|
|
|
|
using _Maybe_rebind_alloc_t =
|
|
|
|
typename _Select<is_same_v<typename _Alloc::value_type, _Value_type>>::template _Apply<_Alloc&,
|
|
|
|
_Rebind_alloc_t<_Alloc, _Value_type>>;
|
|
|
|
|
|
|
|
// VARIABLE TEMPLATE _Is_simple_alloc_v
|
|
|
|
template <class _Alloc> // tests if allocator has simple addressing
|
|
|
|
_INLINE_VAR constexpr bool _Is_simple_alloc_v = is_same_v<typename allocator_traits<_Alloc>::size_type, size_t>&&
|
|
|
|
is_same_v<typename allocator_traits<_Alloc>::difference_type, ptrdiff_t>&&
|
|
|
|
is_same_v<typename allocator_traits<_Alloc>::pointer, typename _Alloc::value_type*>&&
|
|
|
|
is_same_v<typename allocator_traits<_Alloc>::const_pointer, const typename _Alloc::value_type*>;
|
|
|
|
|
|
|
|
// STRUCT TEMPLATE _Simple_types
|
|
|
|
template <class _Value_type>
|
|
|
|
struct _Simple_types { // wraps types from allocators with simple addressing for use in iterators
|
|
|
|
// and other SCARY machinery
|
|
|
|
using value_type = _Value_type;
|
|
|
|
using size_type = size_t;
|
|
|
|
using difference_type = ptrdiff_t;
|
|
|
|
using pointer = value_type*;
|
|
|
|
using const_pointer = const value_type*;
|
|
|
|
};
|
|
|
|
|
|
|
|
// CLASS TEMPLATE allocator
|
|
|
|
template <class _Ty>
|
|
|
|
class allocator {
|
|
|
|
public:
|
|
|
|
static_assert(!is_const_v<_Ty>, "The C++ Standard forbids containers of const elements "
|
|
|
|
"because allocator<const T> is ill-formed.");
|
|
|
|
|
|
|
|
using _From_primary = allocator;
|
|
|
|
|
|
|
|
using value_type = _Ty;
|
|
|
|
|
2021-02-02 06:35:06 +03:00
|
|
|
#if _HAS_DEPRECATED_ALLOCATOR_MEMBERS
|
2019-09-05 01:57:56 +03:00
|
|
|
_CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS typedef _Ty* pointer;
|
|
|
|
_CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS typedef const _Ty* const_pointer;
|
|
|
|
|
|
|
|
_CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS typedef _Ty& reference;
|
|
|
|
_CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS typedef const _Ty& const_reference;
|
2021-02-02 06:35:06 +03:00
|
|
|
#endif // _HAS_DEPRECATED_ALLOCATOR_MEMBERS
|
2019-09-05 01:57:56 +03:00
|
|
|
|
|
|
|
using size_type = size_t;
|
|
|
|
using difference_type = ptrdiff_t;
|
|
|
|
|
2021-02-02 06:35:06 +03:00
|
|
|
using propagate_on_container_move_assignment = true_type;
|
|
|
|
|
|
|
|
#if _HAS_DEPRECATED_ALLOCATOR_MEMBERS
|
2020-12-02 02:39:26 +03:00
|
|
|
using is_always_equal _CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS = true_type;
|
2019-09-05 01:57:56 +03:00
|
|
|
|
|
|
|
template <class _Other>
|
|
|
|
struct _CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS rebind {
|
|
|
|
using other = allocator<_Other>;
|
|
|
|
};
|
|
|
|
|
2020-01-09 06:16:40 +03:00
|
|
|
_CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS _NODISCARD _Ty* address(_Ty& _Val) const noexcept {
|
2019-09-05 01:57:56 +03:00
|
|
|
return _STD addressof(_Val);
|
|
|
|
}
|
|
|
|
|
2020-01-09 06:16:40 +03:00
|
|
|
_CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS _NODISCARD const _Ty* address(const _Ty& _Val) const noexcept {
|
2019-09-05 01:57:56 +03:00
|
|
|
return _STD addressof(_Val);
|
|
|
|
}
|
2021-02-02 06:35:06 +03:00
|
|
|
#endif // _HAS_DEPRECATED_ALLOCATOR_MEMBERS
|
2019-09-05 01:57:56 +03:00
|
|
|
|
|
|
|
constexpr allocator() noexcept {}
|
|
|
|
|
|
|
|
constexpr allocator(const allocator&) noexcept = default;
|
|
|
|
template <class _Other>
|
|
|
|
constexpr allocator(const allocator<_Other>&) noexcept {}
|
2021-01-08 06:01:52 +03:00
|
|
|
_CONSTEXPR20_DYNALLOC ~allocator() = default;
|
|
|
|
_CONSTEXPR20_DYNALLOC allocator& operator=(const allocator&) = default;
|
2019-09-05 01:57:56 +03:00
|
|
|
|
2021-01-08 06:01:52 +03:00
|
|
|
_CONSTEXPR20_DYNALLOC void deallocate(_Ty* const _Ptr, const size_t _Count) {
|
2019-09-05 01:57:56 +03:00
|
|
|
// no overflow check on the following multiply; we assume _Allocate did that check
|
|
|
|
_Deallocate<_New_alignof<_Ty>>(_Ptr, sizeof(_Ty) * _Count);
|
|
|
|
}
|
|
|
|
|
2021-01-08 06:01:52 +03:00
|
|
|
_NODISCARD _CONSTEXPR20_DYNALLOC __declspec(allocator) _Ty* allocate(_CRT_GUARDOVERFLOW const size_t _Count) {
|
2019-09-05 01:57:56 +03:00
|
|
|
return static_cast<_Ty*>(_Allocate<_New_alignof<_Ty>>(_Get_size_of_n<sizeof(_Ty)>(_Count)));
|
|
|
|
}
|
|
|
|
|
2021-02-02 06:35:06 +03:00
|
|
|
#if _HAS_DEPRECATED_ALLOCATOR_MEMBERS
|
2020-04-13 23:09:34 +03:00
|
|
|
_CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS _NODISCARD __declspec(allocator) _Ty* allocate(
|
2019-09-05 01:57:56 +03:00
|
|
|
_CRT_GUARDOVERFLOW const size_t _Count, const void*) {
|
|
|
|
return allocate(_Count);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Objty, class... _Types>
|
|
|
|
_CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS void construct(_Objty* const _Ptr, _Types&&... _Args) {
|
2021-02-04 00:54:37 +03:00
|
|
|
::new (_Voidify_iter(_Ptr)) _Objty(_STD forward<_Types>(_Args)...);
|
2019-09-05 01:57:56 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Uty>
|
|
|
|
_CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS void destroy(_Uty* const _Ptr) {
|
|
|
|
_Ptr->~_Uty();
|
|
|
|
}
|
|
|
|
|
2020-01-09 06:16:40 +03:00
|
|
|
_CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS _NODISCARD size_t max_size() const noexcept {
|
2019-09-05 01:57:56 +03:00
|
|
|
return static_cast<size_t>(-1) / sizeof(_Ty);
|
|
|
|
}
|
2021-02-02 06:35:06 +03:00
|
|
|
#endif // _HAS_DEPRECATED_ALLOCATOR_MEMBERS
|
2019-09-05 01:57:56 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
// CLASS allocator<void>
|
|
|
|
template <>
|
|
|
|
class allocator<void> {
|
|
|
|
public:
|
|
|
|
using value_type = void;
|
2021-02-02 06:35:06 +03:00
|
|
|
#if _HAS_DEPRECATED_ALLOCATOR_MEMBERS
|
2019-09-05 01:57:56 +03:00
|
|
|
_CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS typedef void* pointer;
|
|
|
|
_CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS typedef const void* const_pointer;
|
2021-02-02 06:35:06 +03:00
|
|
|
#endif // _HAS_DEPRECATED_ALLOCATOR_MEMBERS
|
2019-09-05 01:57:56 +03:00
|
|
|
|
|
|
|
using size_type = size_t;
|
|
|
|
using difference_type = ptrdiff_t;
|
|
|
|
|
2021-02-02 06:35:06 +03:00
|
|
|
using propagate_on_container_move_assignment = true_type;
|
|
|
|
|
|
|
|
#if _HAS_DEPRECATED_ALLOCATOR_MEMBERS
|
2020-12-02 02:39:26 +03:00
|
|
|
using is_always_equal _CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS = true_type;
|
2019-09-05 01:57:56 +03:00
|
|
|
|
|
|
|
template <class _Other>
|
|
|
|
struct _CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS rebind {
|
|
|
|
using other = allocator<_Other>;
|
|
|
|
};
|
2021-02-02 06:35:06 +03:00
|
|
|
#endif // _HAS_DEPRECATED_ALLOCATOR_MEMBERS
|
2019-09-05 01:57:56 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
template <class _Ty, class _Other>
|
2021-01-08 06:01:52 +03:00
|
|
|
_NODISCARD _CONSTEXPR20_DYNALLOC bool operator==(const allocator<_Ty>&, const allocator<_Other>&) noexcept {
|
2019-09-05 01:57:56 +03:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-02-25 03:19:31 +03:00
|
|
|
#if !_HAS_CXX20
|
2019-09-05 01:57:56 +03:00
|
|
|
template <class _Ty, class _Other>
|
2021-02-25 03:19:31 +03:00
|
|
|
_NODISCARD bool operator!=(const allocator<_Ty>&, const allocator<_Other>&) noexcept {
|
2019-09-05 01:57:56 +03:00
|
|
|
return false;
|
|
|
|
}
|
2021-02-25 03:19:31 +03:00
|
|
|
#endif // !_HAS_CXX20
|
2019-09-05 01:57:56 +03:00
|
|
|
|
|
|
|
#if _HAS_CXX17
|
|
|
|
// ALIAS TEMPLATE _Guide_size_type_t FOR DEDUCTION GUIDES, N4687 26.5.4.1 [unord.map.overview]/4
|
|
|
|
template <class _Alloc>
|
|
|
|
using _Guide_size_type_t =
|
|
|
|
typename allocator_traits<conditional_t<_Is_allocator<_Alloc>::value, _Alloc, allocator<int>>>::size_type;
|
|
|
|
#endif // _HAS_CXX17
|
|
|
|
|
|
|
|
// ALIAS TEMPLATE _Alloc_ptr_t
|
|
|
|
template <class _Alloc>
|
|
|
|
using _Alloc_ptr_t = typename allocator_traits<_Alloc>::pointer;
|
|
|
|
|
|
|
|
// ALIAS_TEMPLATE _Alloc_size_t
|
|
|
|
template <class _Alloc>
|
|
|
|
using _Alloc_size_t = typename allocator_traits<_Alloc>::size_type;
|
|
|
|
|
|
|
|
// FUNCTION TEMPLATE _Pocca
|
|
|
|
template <class _Alloc>
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20 void _Pocca(_Alloc& _Left, const _Alloc& _Right) noexcept {
|
2019-09-05 01:57:56 +03:00
|
|
|
if constexpr (allocator_traits<_Alloc>::propagate_on_container_copy_assignment::value) {
|
|
|
|
_Left = _Right;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// FUNCTION TEMPLATE _Pocma
|
|
|
|
template <class _Alloc>
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20 void _Pocma(_Alloc& _Left, _Alloc& _Right) noexcept { // (maybe) propagate on container move assignment
|
2019-09-05 01:57:56 +03:00
|
|
|
if constexpr (allocator_traits<_Alloc>::propagate_on_container_move_assignment::value) {
|
|
|
|
_Left = _STD move(_Right);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// FUNCTION TEMPLATE _Pocs
|
|
|
|
template <class _Alloc>
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20 void _Pocs(_Alloc& _Left, _Alloc& _Right) noexcept {
|
2019-09-05 01:57:56 +03:00
|
|
|
if constexpr (allocator_traits<_Alloc>::propagate_on_container_swap::value) {
|
|
|
|
_Swap_adl(_Left, _Right);
|
|
|
|
} else {
|
|
|
|
_STL_ASSERT(_Left == _Right, "containers incompatible for swap");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// FUNCTION TEMPLATE _Destroy_range WITH ALLOC
|
|
|
|
template <class _Alloc>
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20_DYNALLOC void _Destroy_range(
|
|
|
|
_Alloc_ptr_t<_Alloc> _First, const _Alloc_ptr_t<_Alloc> _Last, _Alloc& _Al) noexcept {
|
2019-09-05 01:57:56 +03:00
|
|
|
// note that this is an optimization for debug mode codegen; in release mode the BE removes all of this
|
|
|
|
using _Ty = typename _Alloc::value_type;
|
2021-01-06 04:19:12 +03:00
|
|
|
if constexpr (!conjunction_v<is_trivially_destructible<_Ty>, _Uses_default_destroy<_Alloc, _Ty*>>) {
|
2019-09-05 01:57:56 +03:00
|
|
|
for (; _First != _Last; ++_First) {
|
|
|
|
allocator_traits<_Alloc>::destroy(_Al, _Unfancy(_First));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// FUNCTION TEMPLATE _Destroy_range
|
2020-08-12 22:47:52 +03:00
|
|
|
template <class _NoThrowFwdIt, class _NoThrowSentinel>
|
2020-09-23 01:02:43 +03:00
|
|
|
_CONSTEXPR20_DYNALLOC void _Destroy_range(_NoThrowFwdIt _First, const _NoThrowSentinel _Last) noexcept {
|
2019-09-05 01:57:56 +03:00
|
|
|
// note that this is an optimization for debug mode codegen; in release mode the BE removes all of this
|
2021-01-06 04:19:12 +03:00
|
|
|
if constexpr (!is_trivially_destructible_v<_Iter_value_t<_NoThrowFwdIt>>) {
|
2019-09-05 01:57:56 +03:00
|
|
|
for (; _First != _Last; ++_First) {
|
|
|
|
_Destroy_in_place(*_First);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// FUNCTION TEMPLATE _Convert_size
|
|
|
|
template <class _Size_type>
|
|
|
|
_NODISCARD constexpr _Size_type _Convert_size(const size_t _Len) noexcept {
|
|
|
|
// convert size_t to _Size_type, avoiding truncation
|
|
|
|
if (_Len > (numeric_limits<_Size_type>::max)()) {
|
|
|
|
_Xlength_error("size_t too long for _Size_type");
|
|
|
|
}
|
|
|
|
|
|
|
|
return static_cast<_Size_type>(_Len);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <>
|
|
|
|
_NODISCARD constexpr size_t _Convert_size<size_t>(const size_t _Len) noexcept {
|
|
|
|
// convert size_t to size_t, unchanged
|
|
|
|
return _Len;
|
|
|
|
}
|
|
|
|
|
|
|
|
// FUNCTION TEMPLATE _Deallocate_plain
|
|
|
|
template <class _Alloc>
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20_DYNALLOC void _Deallocate_plain(_Alloc& _Al, typename _Alloc::value_type* const _Ptr) noexcept {
|
2019-09-05 01:57:56 +03:00
|
|
|
// deallocate a plain pointer using an allocator
|
|
|
|
using _Alloc_traits = allocator_traits<_Alloc>;
|
|
|
|
if constexpr (is_same_v<_Alloc_ptr_t<_Alloc>, typename _Alloc::value_type*>) {
|
|
|
|
_Alloc_traits::deallocate(_Al, _Ptr, 1);
|
|
|
|
} else {
|
|
|
|
using _Ptr_traits = pointer_traits<_Alloc_ptr_t<_Alloc>>;
|
|
|
|
_Alloc_traits::deallocate(_Al, _Ptr_traits::pointer_to(*_Ptr), 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// FUNCTION TEMPLATE _Delete_plain_internal
|
|
|
|
template <class _Alloc>
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20_DYNALLOC void _Delete_plain_internal(_Alloc& _Al, typename _Alloc::value_type* const _Ptr) noexcept {
|
2019-09-05 01:57:56 +03:00
|
|
|
// destroy *_Ptr in place, then deallocate _Ptr using _Al; used for internal container types the user didn't name
|
|
|
|
using _Ty = typename _Alloc::value_type;
|
|
|
|
_Ptr->~_Ty();
|
|
|
|
_Deallocate_plain(_Al, _Ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
// STRUCT TEMPLATE _Alloc_construct_ptr
|
|
|
|
template <class _Alloc>
|
|
|
|
struct _Alloc_construct_ptr { // pointer used to help construct 1 _Alloc::value_type without EH
|
|
|
|
using pointer = _Alloc_ptr_t<_Alloc>;
|
|
|
|
_Alloc& _Al;
|
|
|
|
pointer _Ptr;
|
|
|
|
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20_DYNALLOC explicit _Alloc_construct_ptr(_Alloc& _Al_) : _Al(_Al_), _Ptr(nullptr) {}
|
2019-09-05 01:57:56 +03:00
|
|
|
|
2021-02-04 00:54:37 +03:00
|
|
|
_NODISCARD _CONSTEXPR20_DYNALLOC pointer _Release() noexcept { // disengage *this and return contained pointer
|
2019-09-05 01:57:56 +03:00
|
|
|
return _STD exchange(_Ptr, nullptr);
|
|
|
|
}
|
|
|
|
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20_DYNALLOC void _Allocate() { // disengage *this, then allocate a new memory block
|
2019-09-05 01:57:56 +03:00
|
|
|
_Ptr = nullptr; // if allocate throws, prevents double-free
|
|
|
|
_Ptr = _Al.allocate(1);
|
|
|
|
}
|
|
|
|
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20_DYNALLOC ~_Alloc_construct_ptr() { // if this instance is engaged, deallocate storage
|
2019-09-05 01:57:56 +03:00
|
|
|
if (_Ptr) {
|
|
|
|
_Al.deallocate(_Ptr, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_Alloc_construct_ptr(const _Alloc_construct_ptr&) = delete;
|
|
|
|
_Alloc_construct_ptr& operator=(const _Alloc_construct_ptr&) = delete;
|
|
|
|
};
|
|
|
|
|
|
|
|
// CLASSES _Container_base*, _Iterator_base*
|
|
|
|
struct _Fake_allocator {};
|
|
|
|
|
|
|
|
struct _Container_base0 {
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20_CONTAINER void _Orphan_all() noexcept {}
|
|
|
|
_CONSTEXPR20_CONTAINER void _Swap_proxy_and_iterators(_Container_base0&) noexcept {}
|
|
|
|
_CONSTEXPR20_CONTAINER void _Alloc_proxy(const _Fake_allocator&) noexcept {}
|
|
|
|
_CONSTEXPR20_CONTAINER void _Reload_proxy(const _Fake_allocator&, const _Fake_allocator&) noexcept {}
|
2019-09-05 01:57:56 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
struct _Iterator_base0 {
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20_CONTAINER void _Adopt(const void*) noexcept {}
|
|
|
|
_CONSTEXPR20_CONTAINER const _Container_base0* _Getcont() const noexcept {
|
2019-09-05 01:57:56 +03:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
static constexpr bool _Unwrap_when_unverified = true;
|
|
|
|
};
|
|
|
|
|
|
|
|
// CLASS _Container_proxy
|
|
|
|
struct _Container_base12;
|
|
|
|
struct _Container_proxy { // store head of iterator chain and back pointer
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20_CONTAINER _Container_proxy() noexcept = default;
|
|
|
|
_CONSTEXPR20_CONTAINER _Container_proxy(_Container_base12* _Mycont_) noexcept : _Mycont(_Mycont_) {}
|
2019-09-05 01:57:56 +03:00
|
|
|
|
2021-02-04 00:54:37 +03:00
|
|
|
const _Container_base12* _Mycont = nullptr;
|
|
|
|
mutable _Iterator_base12* _Myfirstiter = nullptr;
|
2019-09-05 01:57:56 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
struct _Container_base12 {
|
|
|
|
public:
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20_CONTAINER _Container_base12() noexcept = default;
|
2019-09-05 01:57:56 +03:00
|
|
|
|
|
|
|
_Container_base12(const _Container_base12&) = delete;
|
|
|
|
_Container_base12& operator=(const _Container_base12&) = delete;
|
|
|
|
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20_CONTAINER void _Orphan_all() noexcept;
|
|
|
|
_CONSTEXPR20_CONTAINER void _Swap_proxy_and_iterators(_Container_base12&) noexcept;
|
2019-09-05 01:57:56 +03:00
|
|
|
|
|
|
|
template <class _Alloc>
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20_CONTAINER void _Alloc_proxy(_Alloc&& _Al) {
|
2019-09-05 01:57:56 +03:00
|
|
|
_Container_proxy* const _New_proxy = _Unfancy(_Al.allocate(1));
|
|
|
|
_Construct_in_place(*_New_proxy, this);
|
|
|
|
_Myproxy = _New_proxy;
|
|
|
|
_New_proxy->_Mycont = this;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Alloc>
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20_CONTAINER void _Reload_proxy(_Alloc&& _Old_alloc, _Alloc&& _New_alloc) {
|
2019-09-05 01:57:56 +03:00
|
|
|
// pre: no iterators refer to the existing proxy
|
|
|
|
_Container_proxy* const _New_proxy = _Unfancy(_New_alloc.allocate(1));
|
|
|
|
_Construct_in_place(*_New_proxy, this);
|
|
|
|
_New_proxy->_Mycont = this;
|
|
|
|
_Delete_plain_internal(_Old_alloc, _STD exchange(_Myproxy, _New_proxy));
|
|
|
|
}
|
|
|
|
|
2021-02-04 00:54:37 +03:00
|
|
|
_Container_proxy* _Myproxy = nullptr;
|
|
|
|
|
|
|
|
private:
|
|
|
|
_CONSTEXPR20_CONTAINER void _Orphan_all_unlocked() noexcept;
|
|
|
|
_CONSTEXPR20_CONTAINER void _Swap_proxy_and_iterators_unlocked(_Container_base12&) noexcept;
|
|
|
|
|
|
|
|
void _Orphan_all_locked() noexcept {
|
|
|
|
_Lockit _Lock(_LOCK_DEBUG);
|
|
|
|
_Orphan_all_unlocked();
|
|
|
|
}
|
|
|
|
|
|
|
|
void _Swap_proxy_and_iterators_locked(_Container_base12& _Right) noexcept {
|
|
|
|
_Lockit _Lock(_LOCK_DEBUG);
|
|
|
|
_Swap_proxy_and_iterators_unlocked(_Right);
|
|
|
|
}
|
2019-09-05 01:57:56 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
struct _Iterator_base12 { // store links to container proxy, next iterator
|
2021-02-04 00:54:37 +03:00
|
|
|
public:
|
|
|
|
_CONSTEXPR20_CONTAINER _Iterator_base12() noexcept = default; // construct orphaned iterator
|
2019-09-05 01:57:56 +03:00
|
|
|
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20_CONTAINER _Iterator_base12(const _Iterator_base12& _Right) noexcept {
|
2019-09-05 01:57:56 +03:00
|
|
|
*this = _Right;
|
|
|
|
}
|
|
|
|
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20_CONTAINER _Iterator_base12& operator=(const _Iterator_base12& _Right) noexcept {
|
2019-09-05 01:57:56 +03:00
|
|
|
if (_Myproxy != _Right._Myproxy) {
|
|
|
|
if (_Right._Myproxy) {
|
|
|
|
_Adopt(_Right._Myproxy->_Mycont);
|
|
|
|
} else { // becoming invalid, disown current parent
|
|
|
|
#if _ITERATOR_DEBUG_LEVEL == 2
|
2021-02-04 00:54:37 +03:00
|
|
|
_Orphan_me_v2();
|
2019-09-05 01:57:56 +03:00
|
|
|
#else // _ITERATOR_DEBUG_LEVEL == 2
|
|
|
|
_Myproxy = nullptr;
|
|
|
|
#endif // _ITERATOR_DEBUG_LEVEL == 2
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if _ITERATOR_DEBUG_LEVEL == 2
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20_CONTAINER ~_Iterator_base12() noexcept {
|
|
|
|
_Orphan_me_v2();
|
2019-09-05 01:57:56 +03:00
|
|
|
}
|
|
|
|
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20_CONTAINER void _Adopt(const _Container_base12* _Parent) noexcept {
|
|
|
|
if (_Parent) { // have a parent, do adoption
|
2019-09-05 01:57:56 +03:00
|
|
|
_Container_proxy* _Parent_proxy = _Parent->_Myproxy;
|
|
|
|
if (_Myproxy != _Parent_proxy) { // change parentage
|
2021-02-04 00:54:37 +03:00
|
|
|
#ifdef __cpp_lib_constexpr_dynamic_alloc
|
|
|
|
if (_STD is_constant_evaluated()) {
|
|
|
|
_Adopt_unlocked(_Parent_proxy);
|
|
|
|
} else
|
|
|
|
#endif // __cpp_lib_constexpr_dynamic_alloc
|
|
|
|
{
|
|
|
|
_Adopt_locked(_Parent_proxy);
|
|
|
|
}
|
2019-09-05 01:57:56 +03:00
|
|
|
}
|
2021-02-04 00:54:37 +03:00
|
|
|
} else { // no future parent, just disown current parent
|
|
|
|
_Orphan_me_v2();
|
2019-09-05 01:57:56 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20_CONTAINER void _Orphan_me_v2() noexcept {
|
2019-09-05 01:57:56 +03:00
|
|
|
if (_Myproxy) { // adopted, remove self from list
|
2021-02-04 00:54:37 +03:00
|
|
|
#ifdef __cpp_lib_constexpr_dynamic_alloc
|
|
|
|
if (_STD is_constant_evaluated()) {
|
|
|
|
_Orphan_me_unlocked();
|
|
|
|
} else
|
|
|
|
#endif // __cpp_lib_constexpr_dynamic_alloc
|
|
|
|
{
|
|
|
|
_Orphan_me_locked();
|
2019-09-05 01:57:56 +03:00
|
|
|
}
|
2021-02-04 00:54:37 +03:00
|
|
|
}
|
|
|
|
}
|
2019-09-05 01:57:56 +03:00
|
|
|
|
2021-02-04 00:54:37 +03:00
|
|
|
#else // ^^^ _ITERATOR_DEBUG_LEVEL == 2 ^^^ / vvv _ITERATOR_DEBUG_LEVEL != 2 vvv
|
|
|
|
_CONSTEXPR20_CONTAINER void _Adopt(const _Container_base12* _Parent) noexcept {
|
|
|
|
if (_Parent) { // have a parent, do adoption
|
|
|
|
_Myproxy = _Parent->_Myproxy;
|
|
|
|
} else { // no future parent, just disown current parent
|
2019-09-05 01:57:56 +03:00
|
|
|
_Myproxy = nullptr;
|
|
|
|
}
|
|
|
|
}
|
2021-02-04 00:54:37 +03:00
|
|
|
#endif // _ITERATOR_DEBUG_LEVEL != 2
|
|
|
|
|
|
|
|
_CONSTEXPR20_CONTAINER const _Container_base12* _Getcont() const noexcept {
|
|
|
|
return _Myproxy ? _Myproxy->_Mycont : nullptr;
|
|
|
|
}
|
2019-09-05 01:57:56 +03:00
|
|
|
|
|
|
|
static constexpr bool _Unwrap_when_unverified = _ITERATOR_DEBUG_LEVEL == 0;
|
|
|
|
|
2021-02-27 08:38:32 +03:00
|
|
|
mutable _Container_proxy* _Myproxy = nullptr;
|
|
|
|
mutable _Iterator_base12* _Mynextiter = nullptr;
|
2019-09-05 01:57:56 +03:00
|
|
|
|
|
|
|
#if _ITERATOR_DEBUG_LEVEL == 2
|
2021-02-04 00:54:37 +03:00
|
|
|
private:
|
|
|
|
_CONSTEXPR20_CONTAINER void _Adopt_unlocked(_Container_proxy* _Parent_proxy) noexcept {
|
|
|
|
if (_Myproxy) { // adopted, remove self from list
|
|
|
|
_Orphan_me_unlocked();
|
|
|
|
}
|
|
|
|
_Mynextiter = _Parent_proxy->_Myfirstiter;
|
|
|
|
_Parent_proxy->_Myfirstiter = this;
|
|
|
|
_Myproxy = _Parent_proxy;
|
|
|
|
}
|
|
|
|
|
|
|
|
void _Adopt_locked(_Container_proxy* _Parent_proxy) noexcept {
|
2019-09-05 01:57:56 +03:00
|
|
|
_Lockit _Lock(_LOCK_DEBUG);
|
2021-02-04 00:54:37 +03:00
|
|
|
_Adopt_unlocked(_Parent_proxy);
|
|
|
|
}
|
2019-09-05 01:57:56 +03:00
|
|
|
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20_CONTAINER void _Orphan_me_unlocked() noexcept {
|
|
|
|
_Iterator_base12** _Pnext = &_Myproxy->_Myfirstiter;
|
|
|
|
while (*_Pnext && *_Pnext != this) {
|
|
|
|
const auto _Temp = *_Pnext; // TRANSITION, VSO-1269037
|
|
|
|
_Pnext = &_Temp->_Mynextiter;
|
2019-09-05 01:57:56 +03:00
|
|
|
}
|
|
|
|
|
2021-02-04 00:54:37 +03:00
|
|
|
_STL_VERIFY(*_Pnext, "ITERATOR LIST CORRUPTED!");
|
|
|
|
*_Pnext = _Mynextiter;
|
|
|
|
_Myproxy = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void _Orphan_me_locked() noexcept {
|
|
|
|
_Lockit _Lock(_LOCK_DEBUG);
|
|
|
|
_Orphan_me_unlocked();
|
2019-09-05 01:57:56 +03:00
|
|
|
}
|
|
|
|
#endif // _ITERATOR_DEBUG_LEVEL == 2
|
2021-02-04 00:54:37 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
// MEMBER FUNCTIONS FOR _Container_base12
|
|
|
|
_CONSTEXPR20_CONTAINER void _Container_base12::_Orphan_all_unlocked() noexcept {
|
2021-02-17 10:54:27 +03:00
|
|
|
for (auto& _Pnext = _Myproxy->_Myfirstiter; _Pnext; _Pnext = _Pnext->_Mynextiter) { // TRANSITION, VSO-1269037
|
|
|
|
_Pnext->_Myproxy = nullptr;
|
2021-02-04 00:54:37 +03:00
|
|
|
}
|
|
|
|
_Myproxy->_Myfirstiter = nullptr;
|
2019-09-05 01:57:56 +03:00
|
|
|
}
|
|
|
|
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20_CONTAINER void _Container_base12::_Orphan_all() noexcept {
|
2019-09-05 01:57:56 +03:00
|
|
|
#if _ITERATOR_DEBUG_LEVEL == 2
|
2021-02-04 00:54:37 +03:00
|
|
|
if (_Myproxy) { // proxy allocated, drain it
|
|
|
|
#ifdef __cpp_lib_constexpr_dynamic_alloc
|
|
|
|
if (_STD is_constant_evaluated()) {
|
|
|
|
_Orphan_all_unlocked();
|
|
|
|
} else
|
|
|
|
#endif // __cpp_lib_constexpr_dynamic_alloc
|
|
|
|
{
|
|
|
|
_Orphan_all_locked();
|
|
|
|
}
|
|
|
|
}
|
2019-09-05 01:57:56 +03:00
|
|
|
#endif // _ITERATOR_DEBUG_LEVEL == 2
|
2021-02-04 00:54:37 +03:00
|
|
|
}
|
2019-09-05 01:57:56 +03:00
|
|
|
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20_CONTAINER void _Container_base12::_Swap_proxy_and_iterators_unlocked(_Container_base12& _Right) noexcept {
|
2019-09-05 01:57:56 +03:00
|
|
|
_Container_proxy* _Temp = _Myproxy;
|
|
|
|
_Myproxy = _Right._Myproxy;
|
|
|
|
_Right._Myproxy = _Temp;
|
|
|
|
|
|
|
|
if (_Myproxy) {
|
|
|
|
_Myproxy->_Mycont = this;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_Right._Myproxy) {
|
|
|
|
_Right._Myproxy->_Mycont = &_Right;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20_CONTAINER void _Container_base12::_Swap_proxy_and_iterators(_Container_base12& _Right) noexcept {
|
|
|
|
#if _ITERATOR_DEBUG_LEVEL == 2
|
|
|
|
#ifdef __cpp_lib_constexpr_dynamic_alloc
|
|
|
|
if (_STD is_constant_evaluated()) {
|
|
|
|
_Swap_proxy_and_iterators_unlocked(_Right);
|
|
|
|
} else
|
|
|
|
#endif // __cpp_lib_constexpr_dynamic_alloc
|
|
|
|
{
|
|
|
|
_Swap_proxy_and_iterators_locked(_Right);
|
|
|
|
}
|
|
|
|
#else // ^^^ _ITERATOR_DEBUG_LEVEL == 2 ^^^ / vvv _ITERATOR_DEBUG_LEVEL != 2 vvv
|
|
|
|
_Swap_proxy_and_iterators_unlocked(_Right);
|
|
|
|
#endif // _ITERATOR_DEBUG_LEVEL != 2
|
|
|
|
}
|
|
|
|
|
2019-09-05 01:57:56 +03:00
|
|
|
#if _ITERATOR_DEBUG_LEVEL == 0
|
|
|
|
using _Container_base = _Container_base0;
|
|
|
|
using _Iterator_base = _Iterator_base0;
|
|
|
|
#else // _ITERATOR_DEBUG_LEVEL == 0
|
|
|
|
using _Container_base = _Container_base12;
|
|
|
|
using _Iterator_base = _Iterator_base12;
|
|
|
|
#endif // _ITERATOR_DEBUG_LEVEL == 0
|
|
|
|
|
|
|
|
// ALIAS TEMPLATE _Container_proxy_ptr AND SUPPORTING MACHINERY
|
2020-03-01 01:21:41 +03:00
|
|
|
struct _Leave_proxy_unbound {
|
|
|
|
explicit _Leave_proxy_unbound() = default;
|
|
|
|
}; // tag to indicate that a proxy is being allocated before it is safe to bind to a _Container_base12
|
2019-09-05 01:57:56 +03:00
|
|
|
|
|
|
|
struct _Fake_proxy_ptr_impl { // fake replacement for a container proxy smart pointer when no container proxy is in use
|
|
|
|
_Fake_proxy_ptr_impl(const _Fake_proxy_ptr_impl&) = delete;
|
|
|
|
_Fake_proxy_ptr_impl& operator=(const _Fake_proxy_ptr_impl&) = delete;
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20_CONTAINER _Fake_proxy_ptr_impl(const _Fake_allocator&, _Leave_proxy_unbound) noexcept {}
|
|
|
|
_CONSTEXPR20_CONTAINER _Fake_proxy_ptr_impl(const _Fake_allocator&, const _Container_base0&) noexcept {}
|
2019-09-05 01:57:56 +03:00
|
|
|
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20_CONTAINER void _Bind(const _Fake_allocator&, _Container_base0*) noexcept {}
|
|
|
|
_CONSTEXPR20_CONTAINER void _Release() noexcept {}
|
2019-09-05 01:57:56 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
struct _Basic_container_proxy_ptr12 {
|
|
|
|
// smart pointer components for a _Container_proxy * that don't depend on the allocator
|
2021-02-04 00:54:37 +03:00
|
|
|
_Container_proxy* _Ptr = nullptr;
|
2019-09-05 01:57:56 +03:00
|
|
|
|
2021-02-04 00:54:37 +03:00
|
|
|
constexpr void _Release() noexcept { // disengage this _Basic_container_proxy_ptr12
|
2019-09-05 01:57:56 +03:00
|
|
|
_Ptr = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20_CONTAINER _Basic_container_proxy_ptr12() = default;
|
2019-09-05 01:57:56 +03:00
|
|
|
_Basic_container_proxy_ptr12(const _Basic_container_proxy_ptr12&) = delete;
|
|
|
|
_Basic_container_proxy_ptr12(_Basic_container_proxy_ptr12&&) = delete;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <class _Alloc>
|
|
|
|
struct _Container_proxy_ptr12 : _Basic_container_proxy_ptr12 {
|
|
|
|
// smart pointer components for a _Container_proxy * for an allocator family
|
|
|
|
_Alloc& _Al;
|
|
|
|
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20_CONTAINER _Container_proxy_ptr12(_Alloc& _Al_, _Leave_proxy_unbound) : _Al(_Al_) {
|
|
|
|
// create a new unbound _Container_proxy
|
2019-09-05 01:57:56 +03:00
|
|
|
_Ptr = _Unfancy(_Al_.allocate(1));
|
|
|
|
_Construct_in_place(*_Ptr);
|
|
|
|
}
|
|
|
|
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20_CONTAINER _Container_proxy_ptr12(_Alloc& _Al_, _Container_base12& _Mycont) : _Al(_Al_) {
|
|
|
|
// create a new _Container_proxy pointing at _Mycont
|
2019-09-05 01:57:56 +03:00
|
|
|
_Ptr = _Unfancy(_Al_.allocate(1));
|
|
|
|
_Construct_in_place(*_Ptr, _STD addressof(_Mycont));
|
|
|
|
_Mycont._Myproxy = _Ptr;
|
|
|
|
}
|
|
|
|
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20_CONTAINER void _Bind(_Alloc& _Old_alloc, _Container_base12* _Mycont) noexcept {
|
2019-09-05 01:57:56 +03:00
|
|
|
// Attach the proxy stored in *this to _Mycont, and destroy _Mycont's existing proxy
|
|
|
|
// with _Old_alloc. Requires that no iterators are alive referring to _Mycont.
|
|
|
|
_Ptr->_Mycont = _Mycont;
|
|
|
|
_Delete_plain_internal(_Old_alloc, _STD exchange(_Mycont->_Myproxy, _STD exchange(_Ptr, nullptr)));
|
|
|
|
}
|
|
|
|
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20_CONTAINER ~_Container_proxy_ptr12() {
|
2019-09-05 01:57:56 +03:00
|
|
|
if (_Ptr) {
|
|
|
|
_Delete_plain_internal(_Al, _Ptr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
#if _ITERATOR_DEBUG_LEVEL == 0
|
2021-02-27 08:38:32 +03:00
|
|
|
_INLINE_VAR constexpr _Fake_allocator _Fake_alloc{};
|
|
|
|
#define _GET_PROXY_ALLOCATOR(_Alty, _Al) _Fake_alloc // TRANSITION, VSO-1284799, should be _Fake_allocator{}
|
2019-09-05 01:57:56 +03:00
|
|
|
template <class _Alloc>
|
|
|
|
using _Container_proxy_ptr = _Fake_proxy_ptr_impl;
|
|
|
|
#else // _ITERATOR_DEBUG_LEVEL == 0
|
|
|
|
#define _GET_PROXY_ALLOCATOR(_Alty, _Al) static_cast<_Rebind_alloc_t<_Alty, _Container_proxy>>(_Al)
|
|
|
|
template <class _Alloc>
|
|
|
|
using _Container_proxy_ptr = _Container_proxy_ptr12<_Rebind_alloc_t<_Alloc, _Container_proxy>>;
|
|
|
|
#endif // _ITERATOR_DEBUG_LEVEL == 0
|
|
|
|
|
|
|
|
// CLASS TEMPLATE _Compressed_pair
|
2020-03-01 01:21:41 +03:00
|
|
|
struct _Zero_then_variadic_args_t {
|
|
|
|
explicit _Zero_then_variadic_args_t() = default;
|
|
|
|
}; // tag type for value-initializing first, constructing second from remaining args
|
2019-09-05 01:57:56 +03:00
|
|
|
|
|
|
|
struct _One_then_variadic_args_t {
|
2020-03-01 01:21:41 +03:00
|
|
|
explicit _One_then_variadic_args_t() = default;
|
2019-09-05 01:57:56 +03:00
|
|
|
}; // tag type for constructing first from one arg, constructing second from remaining args
|
|
|
|
|
|
|
|
template <class _Ty1, class _Ty2, bool = is_empty_v<_Ty1> && !is_final_v<_Ty1>>
|
|
|
|
class _Compressed_pair final : private _Ty1 { // store a pair of values, deriving from empty first
|
|
|
|
public:
|
|
|
|
_Ty2 _Myval2;
|
|
|
|
|
|
|
|
using _Mybase = _Ty1; // for visualization
|
|
|
|
|
|
|
|
template <class... _Other2>
|
|
|
|
constexpr explicit _Compressed_pair(_Zero_then_variadic_args_t, _Other2&&... _Val2) noexcept(
|
|
|
|
conjunction_v<is_nothrow_default_constructible<_Ty1>, is_nothrow_constructible<_Ty2, _Other2...>>)
|
|
|
|
: _Ty1(), _Myval2(_STD forward<_Other2>(_Val2)...) {}
|
|
|
|
|
|
|
|
template <class _Other1, class... _Other2>
|
2019-10-23 03:15:35 +03:00
|
|
|
constexpr _Compressed_pair(_One_then_variadic_args_t, _Other1&& _Val1, _Other2&&... _Val2) noexcept(
|
2019-09-05 01:57:56 +03:00
|
|
|
conjunction_v<is_nothrow_constructible<_Ty1, _Other1>, is_nothrow_constructible<_Ty2, _Other2...>>)
|
|
|
|
: _Ty1(_STD forward<_Other1>(_Val1)), _Myval2(_STD forward<_Other2>(_Val2)...) {}
|
|
|
|
|
2019-10-23 03:15:35 +03:00
|
|
|
constexpr _Ty1& _Get_first() noexcept {
|
2019-09-05 01:57:56 +03:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2019-10-23 03:15:35 +03:00
|
|
|
constexpr const _Ty1& _Get_first() const noexcept {
|
2019-09-05 01:57:56 +03:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template <class _Ty1, class _Ty2>
|
|
|
|
class _Compressed_pair<_Ty1, _Ty2, false> final { // store a pair of values, not deriving from first
|
|
|
|
public:
|
|
|
|
_Ty1 _Myval1;
|
|
|
|
_Ty2 _Myval2;
|
|
|
|
|
|
|
|
template <class... _Other2>
|
|
|
|
constexpr explicit _Compressed_pair(_Zero_then_variadic_args_t, _Other2&&... _Val2) noexcept(
|
|
|
|
conjunction_v<is_nothrow_default_constructible<_Ty1>, is_nothrow_constructible<_Ty2, _Other2...>>)
|
|
|
|
: _Myval1(), _Myval2(_STD forward<_Other2>(_Val2)...) {}
|
|
|
|
|
|
|
|
template <class _Other1, class... _Other2>
|
2019-10-23 03:15:35 +03:00
|
|
|
constexpr _Compressed_pair(_One_then_variadic_args_t, _Other1&& _Val1, _Other2&&... _Val2) noexcept(
|
2019-09-05 01:57:56 +03:00
|
|
|
conjunction_v<is_nothrow_constructible<_Ty1, _Other1>, is_nothrow_constructible<_Ty2, _Other2...>>)
|
|
|
|
: _Myval1(_STD forward<_Other1>(_Val1)), _Myval2(_STD forward<_Other2>(_Val2)...) {}
|
|
|
|
|
2019-10-23 03:15:35 +03:00
|
|
|
constexpr _Ty1& _Get_first() noexcept {
|
2019-09-05 01:57:56 +03:00
|
|
|
return _Myval1;
|
|
|
|
}
|
|
|
|
|
2019-10-23 03:15:35 +03:00
|
|
|
constexpr const _Ty1& _Get_first() const noexcept {
|
2019-09-05 01:57:56 +03:00
|
|
|
return _Myval1;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-03-01 01:21:41 +03:00
|
|
|
struct _Move_allocator_tag {
|
|
|
|
explicit _Move_allocator_tag() = default;
|
|
|
|
};
|
2019-09-05 01:57:56 +03:00
|
|
|
|
|
|
|
// FUNCTION TEMPLATE _Get_temporary_buffer
|
|
|
|
template <class _Ty>
|
|
|
|
pair<_Ty*, ptrdiff_t> _Get_temporary_buffer(ptrdiff_t _Count) noexcept {
|
|
|
|
if (static_cast<size_t>(_Count) <= static_cast<size_t>(-1) / sizeof(_Ty)) {
|
|
|
|
for (; 0 < _Count; _Count /= 2) {
|
|
|
|
const auto _Size = static_cast<size_t>(_Count) * sizeof(_Ty);
|
|
|
|
void* _Pbuf;
|
|
|
|
#ifdef __cpp_aligned_new
|
|
|
|
if constexpr (alignof(_Ty) > __STDCPP_DEFAULT_NEW_ALIGNMENT__) {
|
|
|
|
_Pbuf = ::operator new (_Size, align_val_t{alignof(_Ty)}, nothrow);
|
|
|
|
} else
|
|
|
|
#endif // __cpp_aligned_new
|
|
|
|
{
|
|
|
|
_Pbuf = ::operator new(_Size, nothrow);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_Pbuf) {
|
|
|
|
return {static_cast<_Ty*>(_Pbuf), _Count};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return {nullptr, 0};
|
|
|
|
}
|
|
|
|
|
|
|
|
// FUNCTION TEMPLATE _Return_temporary_buffer
|
|
|
|
template <class _Ty>
|
|
|
|
void _Return_temporary_buffer(_Ty* const _Pbuf) noexcept {
|
|
|
|
#ifdef __cpp_aligned_new
|
|
|
|
if constexpr (alignof(_Ty) > __STDCPP_DEFAULT_NEW_ALIGNMENT__) {
|
|
|
|
::operator delete (_Pbuf, align_val_t{alignof(_Ty)});
|
|
|
|
} else
|
|
|
|
#endif // __cpp_aligned_new
|
|
|
|
{
|
|
|
|
::operator delete(_Pbuf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// STRUCT TEMPLATE _Uninitialized_backout
|
|
|
|
template <class _NoThrowFwdIt>
|
2020-12-03 02:10:23 +03:00
|
|
|
struct _NODISCARD _Uninitialized_backout {
|
|
|
|
// struct to undo partially constructed ranges in _Uninitialized_xxx algorithms
|
2019-09-05 01:57:56 +03:00
|
|
|
_NoThrowFwdIt _First;
|
|
|
|
_NoThrowFwdIt _Last;
|
|
|
|
|
2020-08-12 22:47:52 +03:00
|
|
|
constexpr explicit _Uninitialized_backout(_NoThrowFwdIt _Dest) : _First(_Dest), _Last(_Dest) {}
|
2019-09-05 01:57:56 +03:00
|
|
|
|
2020-08-12 22:47:52 +03:00
|
|
|
constexpr _Uninitialized_backout(_NoThrowFwdIt _First_, _NoThrowFwdIt _Last_) : _First(_First_), _Last(_Last_) {}
|
2019-09-05 01:57:56 +03:00
|
|
|
|
|
|
|
_Uninitialized_backout(const _Uninitialized_backout&) = delete;
|
|
|
|
_Uninitialized_backout& operator=(const _Uninitialized_backout&) = delete;
|
|
|
|
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20_DYNALLOC ~_Uninitialized_backout() {
|
2019-09-05 01:57:56 +03:00
|
|
|
_Destroy_range(_First, _Last);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class... _Types>
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20_DYNALLOC void _Emplace_back(_Types&&... _Vals) {
|
2020-08-12 22:47:52 +03:00
|
|
|
// construct a new element at *_Last and increment
|
2019-09-05 01:57:56 +03:00
|
|
|
_Construct_in_place(*_Last, _STD forward<_Types>(_Vals)...);
|
|
|
|
++_Last;
|
|
|
|
}
|
|
|
|
|
2021-02-04 00:54:37 +03:00
|
|
|
constexpr _NoThrowFwdIt _Release() { // suppress any exception handling backout and return _Last
|
2019-09-05 01:57:56 +03:00
|
|
|
_First = _Last;
|
|
|
|
return _Last;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-08-12 22:47:52 +03:00
|
|
|
#ifdef __cpp_lib_concepts
|
|
|
|
namespace ranges {
|
|
|
|
// STRUCT TEMPLATE in_out_result
|
|
|
|
template <class _In, class _Out>
|
|
|
|
struct in_out_result {
|
2020-10-24 02:48:24 +03:00
|
|
|
/* [[no_unique_address]] */ _In in;
|
|
|
|
/* [[no_unique_address]] */ _Out out;
|
2020-08-12 22:47:52 +03:00
|
|
|
|
|
|
|
template <_Convertible_from<const _In&> _IIn, _Convertible_from<const _Out&> _OOut>
|
|
|
|
constexpr operator in_out_result<_IIn, _OOut>() const& {
|
|
|
|
return {in, out};
|
|
|
|
}
|
|
|
|
|
|
|
|
template <_Convertible_from<_In> _IIn, _Convertible_from<_Out> _OOut>
|
|
|
|
constexpr operator in_out_result<_IIn, _OOut>() && {
|
|
|
|
return {_STD move(in), _STD move(out)};
|
|
|
|
}
|
|
|
|
};
|
|
|
|
} // namespace ranges
|
|
|
|
#endif // __cpp_lib_concepts
|
|
|
|
|
2019-09-05 01:57:56 +03:00
|
|
|
// FUNCTION TEMPLATE _Uninitialized_move_unchecked
|
|
|
|
template <class _InIt, class _NoThrowFwdIt>
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20_DYNALLOC _NoThrowFwdIt _Uninitialized_move_unchecked(
|
|
|
|
_InIt _First, const _InIt _Last, _NoThrowFwdIt _Dest) {
|
2019-09-05 01:57:56 +03:00
|
|
|
// move [_First, _Last) to raw [_Dest, ...)
|
|
|
|
if constexpr (_Ptr_move_cat<_InIt, _NoThrowFwdIt>::_Really_trivial) {
|
2021-02-04 00:54:37 +03:00
|
|
|
#ifdef __cpp_lib_constexpr_dynamic_alloc
|
|
|
|
if (!_STD is_constant_evaluated())
|
|
|
|
#endif // __cpp_lib_constexpr_dynamic_alloc
|
|
|
|
{
|
|
|
|
return _Copy_memmove(_First, _Last, _Dest);
|
2019-09-05 01:57:56 +03:00
|
|
|
}
|
|
|
|
}
|
2021-02-04 00:54:37 +03:00
|
|
|
_Uninitialized_backout<_NoThrowFwdIt> _Backout{_Dest};
|
|
|
|
for (; _First != _Last; ++_First) {
|
|
|
|
_Backout._Emplace_back(_STD move(*_First));
|
|
|
|
}
|
|
|
|
|
|
|
|
return _Backout._Release();
|
2019-09-05 01:57:56 +03:00
|
|
|
}
|
|
|
|
|
2021-01-27 13:02:49 +03:00
|
|
|
#ifdef __cpp_lib_concepts
|
|
|
|
namespace ranges {
|
|
|
|
// clang-format off
|
|
|
|
// CONCEPT _No_throw_input_iterator
|
|
|
|
template <class _It>
|
|
|
|
concept _No_throw_input_iterator = input_iterator<_It>
|
|
|
|
&& is_lvalue_reference_v<iter_reference_t<_It>>
|
|
|
|
&& same_as<remove_cvref_t<iter_reference_t<_It>>, iter_value_t<_It>>;
|
|
|
|
|
|
|
|
// CONCEPT _No_throw_sentinel_for
|
|
|
|
template <class _Se, class _It>
|
|
|
|
concept _No_throw_sentinel_for = sentinel_for<_Se, _It>;
|
|
|
|
|
|
|
|
// CONCEPT _No_throw_forward_iterator
|
|
|
|
template <class _It>
|
|
|
|
concept _No_throw_forward_iterator = _No_throw_input_iterator<_It>
|
|
|
|
&& forward_iterator<_It>
|
|
|
|
&& _No_throw_sentinel_for<_It, _It>;
|
|
|
|
|
|
|
|
// CONCEPT _No_throw_input_range
|
|
|
|
template <class _Rng>
|
|
|
|
concept _No_throw_input_range = range<_Rng>
|
|
|
|
&& _No_throw_input_iterator<iterator_t<_Rng>>
|
|
|
|
&& _No_throw_sentinel_for<sentinel_t<_Rng>, iterator_t<_Rng>>;
|
|
|
|
|
|
|
|
// CONCEPT _No_throw_forward_range
|
|
|
|
template <class _Rng>
|
|
|
|
concept _No_throw_forward_range = _No_throw_input_range<_Rng>
|
|
|
|
&& _No_throw_forward_iterator<iterator_t<_Rng>>;
|
|
|
|
// clang-format on
|
|
|
|
|
2021-02-18 09:21:05 +03:00
|
|
|
template <class _InIt, class _OutIt>
|
|
|
|
in_out_result<_InIt, _OutIt> _Copy_memcpy_common(
|
|
|
|
_InIt _IFirst, _InIt _ILast, _OutIt _OFirst, _OutIt _OLast) noexcept {
|
|
|
|
const auto _IFirst_ch = const_cast<char*>(reinterpret_cast<const volatile char*>(_IFirst));
|
|
|
|
const auto _ILast_ch = const_cast<const char*>(reinterpret_cast<const volatile char*>(_ILast));
|
|
|
|
const auto _OFirst_ch = const_cast<char*>(reinterpret_cast<volatile char*>(_OFirst));
|
|
|
|
const auto _OLast_ch = const_cast<const char*>(reinterpret_cast<const volatile char*>(_OLast));
|
|
|
|
const auto _Count = static_cast<size_t>((_STD min)(_ILast_ch - _IFirst_ch, _OLast_ch - _OFirst_ch));
|
|
|
|
_CSTD memcpy(_OFirst_ch, _IFirst_ch, _Count);
|
|
|
|
return {reinterpret_cast<_InIt>(_IFirst_ch + _Count), reinterpret_cast<_OutIt>(_OFirst_ch + _Count)};
|
|
|
|
}
|
|
|
|
|
2021-01-27 13:02:49 +03:00
|
|
|
// ALIAS TEMPLATE uninitialized_move_result
|
|
|
|
template <class _In, class _Out>
|
|
|
|
using uninitialized_move_result = in_out_result<_In, _Out>;
|
|
|
|
|
|
|
|
// FUNCTION TEMPLATE _Uninitialized_move_unchecked
|
|
|
|
// clang-format off
|
|
|
|
template <input_iterator _It, sentinel_for<_It> _Se, _No_throw_forward_iterator _Out,
|
|
|
|
_No_throw_sentinel_for<_Out> _OSe>
|
|
|
|
requires constructible_from<iter_value_t<_Out>, iter_rvalue_reference_t<_It>>
|
|
|
|
uninitialized_move_result<_It, _Out> _Uninitialized_move_unchecked(
|
|
|
|
_It _IFirst, const _Se _ILast, _Out _OFirst, const _OSe _OLast) {
|
|
|
|
// clang-format on
|
2021-03-05 01:44:44 +03:00
|
|
|
if constexpr (is_same_v<_Se, _It> && is_same_v<_OSe, _Out> && _Ptr_move_cat<_It, _Out>::_Really_trivial) {
|
2021-01-27 13:02:49 +03:00
|
|
|
return _Copy_memcpy_common(_IFirst, _ILast, _OFirst, _OLast);
|
|
|
|
} else {
|
|
|
|
_Uninitialized_backout _Backout{_STD move(_OFirst)};
|
|
|
|
|
|
|
|
for (; _IFirst != _ILast && _Backout._Last != _OLast; ++_IFirst) {
|
|
|
|
_Backout._Emplace_back(_RANGES iter_move(_IFirst));
|
|
|
|
}
|
|
|
|
|
|
|
|
return {_STD move(_IFirst), _Backout._Release()};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} // namespace ranges
|
|
|
|
#endif // __cpp_lib_concepts
|
|
|
|
|
2019-09-05 01:57:56 +03:00
|
|
|
// STRUCT TEMPLATE _Uninitialized_backout_al
|
|
|
|
template <class _Alloc>
|
2020-12-03 02:10:23 +03:00
|
|
|
class _NODISCARD _Uninitialized_backout_al {
|
|
|
|
// struct to undo partially constructed ranges in _Uninitialized_xxx_al algorithms
|
2019-09-05 01:57:56 +03:00
|
|
|
using pointer = _Alloc_ptr_t<_Alloc>;
|
|
|
|
|
|
|
|
public:
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20_DYNALLOC _Uninitialized_backout_al(pointer _Dest, _Alloc& _Al_)
|
|
|
|
: _First(_Dest), _Last(_Dest), _Al(_Al_) {}
|
2019-09-05 01:57:56 +03:00
|
|
|
|
|
|
|
_Uninitialized_backout_al(const _Uninitialized_backout_al&) = delete;
|
|
|
|
_Uninitialized_backout_al& operator=(const _Uninitialized_backout_al&) = delete;
|
|
|
|
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20_DYNALLOC ~_Uninitialized_backout_al() {
|
2019-09-05 01:57:56 +03:00
|
|
|
_Destroy_range(_First, _Last, _Al);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class... _Types>
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20_DYNALLOC void _Emplace_back(_Types&&... _Vals) { // construct a new element at *_Last and increment
|
2019-09-05 01:57:56 +03:00
|
|
|
allocator_traits<_Alloc>::construct(_Al, _Unfancy(_Last), _STD forward<_Types>(_Vals)...);
|
|
|
|
++_Last;
|
|
|
|
}
|
|
|
|
|
2021-02-04 00:54:37 +03:00
|
|
|
constexpr pointer _Release() { // suppress any exception handling backout and return _Last
|
2019-09-05 01:57:56 +03:00
|
|
|
_First = _Last;
|
|
|
|
return _Last;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
pointer _First;
|
|
|
|
pointer _Last;
|
|
|
|
_Alloc& _Al;
|
|
|
|
};
|
|
|
|
|
|
|
|
// FUNCTION TEMPLATE _Uninitialized_copy WITH ALLOCATOR
|
|
|
|
template <class _InIt, class _Alloc>
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20_DYNALLOC _Alloc_ptr_t<_Alloc> _Uninitialized_copy(
|
2019-09-05 01:57:56 +03:00
|
|
|
const _InIt _First, const _InIt _Last, _Alloc_ptr_t<_Alloc> _Dest, _Alloc& _Al) {
|
|
|
|
// copy [_First, _Last) to raw _Dest, using _Al
|
|
|
|
// note: only called internally from elsewhere in the STL
|
|
|
|
using _Ptrval = typename _Alloc::value_type*;
|
|
|
|
|
|
|
|
auto _UFirst = _Get_unwrapped(_First);
|
|
|
|
const auto _ULast = _Get_unwrapped(_Last);
|
|
|
|
|
|
|
|
if constexpr (conjunction_v<bool_constant<_Ptr_copy_cat<decltype(_UFirst), _Ptrval>::_Really_trivial>,
|
|
|
|
_Uses_default_construct<_Alloc, _Ptrval, decltype(*_UFirst)>>) {
|
2021-02-04 00:54:37 +03:00
|
|
|
#ifdef __cpp_lib_constexpr_dynamic_alloc
|
|
|
|
if (!_STD is_constant_evaluated())
|
|
|
|
#endif // __cpp_lib_constexpr_dynamic_alloc
|
|
|
|
{
|
|
|
|
_Copy_memmove(_UFirst, _ULast, _Unfancy(_Dest));
|
|
|
|
_Dest += _ULast - _UFirst;
|
|
|
|
return _Dest;
|
2019-09-05 01:57:56 +03:00
|
|
|
}
|
2021-02-04 00:54:37 +03:00
|
|
|
}
|
2019-09-05 01:57:56 +03:00
|
|
|
|
2021-02-04 00:54:37 +03:00
|
|
|
_Uninitialized_backout_al<_Alloc> _Backout{_Dest, _Al};
|
|
|
|
for (; _UFirst != _ULast; ++_UFirst) {
|
|
|
|
_Backout._Emplace_back(*_UFirst);
|
2019-09-05 01:57:56 +03:00
|
|
|
}
|
|
|
|
|
2021-02-04 00:54:37 +03:00
|
|
|
return _Backout._Release();
|
2019-09-05 01:57:56 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// FUNCTION TEMPLATE uninitialized_copy
|
2021-02-04 00:54:37 +03:00
|
|
|
template <class _InIt, class _NoThrowFwdIt>
|
|
|
|
_CONSTEXPR20_DYNALLOC _NoThrowFwdIt _Uninitialized_copy_unchecked(
|
|
|
|
_InIt _First, const _InIt _Last, _NoThrowFwdIt _Dest) {
|
|
|
|
// copy [_First, _Last) to raw [_Dest, ...)
|
|
|
|
if constexpr (_Ptr_copy_cat<_InIt, _NoThrowFwdIt>::_Really_trivial) {
|
|
|
|
#ifdef __cpp_lib_constexpr_dynamic_alloc
|
|
|
|
if (!_STD is_constant_evaluated())
|
|
|
|
#endif // __cpp_lib_constexpr_dynamic_alloc
|
|
|
|
{
|
|
|
|
return _Copy_memmove(_First, _Last, _Dest);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_Uninitialized_backout<_NoThrowFwdIt> _Backout{_Dest};
|
|
|
|
for (; _First != _Last; ++_First) {
|
|
|
|
_Backout._Emplace_back(*_First);
|
|
|
|
}
|
|
|
|
|
|
|
|
return _Backout._Release();
|
|
|
|
}
|
|
|
|
|
2019-09-05 01:57:56 +03:00
|
|
|
template <class _InIt, class _NoThrowFwdIt>
|
|
|
|
_NoThrowFwdIt uninitialized_copy(const _InIt _First, const _InIt _Last, _NoThrowFwdIt _Dest) {
|
|
|
|
// copy [_First, _Last) to raw [_Dest, ...)
|
|
|
|
_Adl_verify_range(_First, _Last);
|
|
|
|
auto _UFirst = _Get_unwrapped(_First);
|
|
|
|
const auto _ULast = _Get_unwrapped(_Last);
|
|
|
|
auto _UDest = _Get_unwrapped_n(_Dest, _Idl_distance<_InIt>(_UFirst, _ULast));
|
2021-02-04 00:54:37 +03:00
|
|
|
_Seek_wrapped(_Dest, _Uninitialized_copy_unchecked(_UFirst, _ULast, _UDest));
|
2019-09-05 01:57:56 +03:00
|
|
|
return _Dest;
|
|
|
|
}
|
|
|
|
|
|
|
|
// FUNCTION TEMPLATE _Uninitialized_move WITH ALLOCATOR
|
|
|
|
template <class _InIt, class _Alloc>
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20_DYNALLOC _Alloc_ptr_t<_Alloc> _Uninitialized_move(
|
2019-09-05 01:57:56 +03:00
|
|
|
const _InIt _First, const _InIt _Last, _Alloc_ptr_t<_Alloc> _Dest, _Alloc& _Al) {
|
|
|
|
// move [_First, _Last) to raw _Dest, using _Al
|
|
|
|
// note: only called internally from elsewhere in the STL
|
|
|
|
using _Ptrval = typename _Alloc::value_type*;
|
|
|
|
auto _UFirst = _Get_unwrapped(_First);
|
|
|
|
const auto _ULast = _Get_unwrapped(_Last);
|
|
|
|
if constexpr (conjunction_v<bool_constant<_Ptr_move_cat<decltype(_UFirst), _Ptrval>::_Really_trivial>,
|
|
|
|
_Uses_default_construct<_Alloc, _Ptrval, decltype(_STD move(*_UFirst))>>) {
|
2021-02-04 00:54:37 +03:00
|
|
|
#ifdef __cpp_lib_constexpr_dynamic_alloc
|
|
|
|
if (!_STD is_constant_evaluated())
|
|
|
|
#endif // __cpp_lib_constexpr_dynamic_alloc
|
|
|
|
{
|
|
|
|
_Copy_memmove(_UFirst, _ULast, _Unfancy(_Dest));
|
|
|
|
return _Dest + (_ULast - _UFirst);
|
2019-09-05 01:57:56 +03:00
|
|
|
}
|
2021-02-04 00:54:37 +03:00
|
|
|
}
|
2019-09-05 01:57:56 +03:00
|
|
|
|
2021-02-04 00:54:37 +03:00
|
|
|
_Uninitialized_backout_al<_Alloc> _Backout{_Dest, _Al};
|
|
|
|
for (; _UFirst != _ULast; ++_UFirst) {
|
|
|
|
_Backout._Emplace_back(_STD move(*_UFirst));
|
2019-09-05 01:57:56 +03:00
|
|
|
}
|
2021-02-04 00:54:37 +03:00
|
|
|
|
|
|
|
return _Backout._Release();
|
2019-09-05 01:57:56 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// FUNCTION TEMPLATE _Uninitialized_fill_n WITH ALLOCATOR
|
|
|
|
template <class _Alloc>
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20_DYNALLOC _Alloc_ptr_t<_Alloc> _Uninitialized_fill_n(
|
2019-09-05 01:57:56 +03:00
|
|
|
_Alloc_ptr_t<_Alloc> _First, _Alloc_size_t<_Alloc> _Count, const typename _Alloc::value_type& _Val, _Alloc& _Al) {
|
|
|
|
// copy _Count copies of _Val to raw _First, using _Al
|
|
|
|
using _Ty = typename _Alloc::value_type;
|
|
|
|
if constexpr (_Fill_memset_is_safe<_Ty*, _Ty> && _Uses_default_construct<_Alloc, _Ty*, _Ty>::value) {
|
2021-02-04 00:54:37 +03:00
|
|
|
#ifdef __cpp_lib_constexpr_dynamic_alloc
|
|
|
|
if (!_STD is_constant_evaluated())
|
|
|
|
#endif // __cpp_lib_constexpr_dynamic_alloc
|
|
|
|
{
|
|
|
|
_Fill_memset(_Unfancy(_First), _Val, static_cast<size_t>(_Count));
|
|
|
|
return _First + _Count;
|
|
|
|
}
|
|
|
|
} else if constexpr (_Fill_zero_memset_is_safe<_Ty*, _Ty> && _Uses_default_construct<_Alloc, _Ty*, _Ty>::value) {
|
|
|
|
#ifdef __cpp_lib_constexpr_dynamic_alloc
|
|
|
|
if (!_STD is_constant_evaluated())
|
|
|
|
#endif // __cpp_lib_constexpr_dynamic_alloc
|
|
|
|
{
|
2020-10-29 10:12:36 +03:00
|
|
|
if (_Is_all_bits_zero(_Val)) {
|
|
|
|
_Fill_zero_memset(_Unfancy(_First), static_cast<size_t>(_Count));
|
|
|
|
return _First + _Count;
|
|
|
|
}
|
|
|
|
}
|
2021-02-04 00:54:37 +03:00
|
|
|
}
|
2019-09-05 01:57:56 +03:00
|
|
|
|
2021-02-04 00:54:37 +03:00
|
|
|
_Uninitialized_backout_al<_Alloc> _Backout{_First, _Al};
|
|
|
|
for (; 0 < _Count; --_Count) {
|
|
|
|
_Backout._Emplace_back(_Val);
|
2019-09-05 01:57:56 +03:00
|
|
|
}
|
2021-02-04 00:54:37 +03:00
|
|
|
|
|
|
|
return _Backout._Release();
|
2019-09-05 01:57:56 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// FUNCTION TEMPLATE uninitialized_fill
|
|
|
|
template <class _NoThrowFwdIt, class _Tval>
|
|
|
|
void uninitialized_fill(const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last, const _Tval& _Val) {
|
|
|
|
// copy _Val throughout raw [_First, _Last)
|
|
|
|
_Adl_verify_range(_First, _Last);
|
|
|
|
auto _UFirst = _Get_unwrapped(_First);
|
|
|
|
const auto _ULast = _Get_unwrapped(_Last);
|
[range.iter.ops], default_sentinel, and unreachable_sentinel (#329)
Implements iterator primitive operations `std::ranges::advance`, `std::ranges::next`, `std::ranges::prev`, and `std::ranges::distance`; as well as `std::default_sentinel` and `std::unreachable_sentinel`.
This change reworks the STL's iterator unwrapping machinery to enable unwrapping of C++20 move-only single-pass iterators (and `if constepxr`s all the things). Consequently, `_Iter_ref_t`, `_Iter_value_t`, and `_Iter_diff_t` resolve to `iter_reference_t`, `iter_value_t`, and `iter_difference_t` (respectively) in `__cpp_lib_concepts` (soon to be C++20) mode. This change necessitates some fixes to `unique_copy` and `_Fill_memset_is_safe` which both assume that `_Iter_value_t<T>` is well-formed for any iterator `T`. (`iter_value_t<T>` does not have that property: it is only well-formed when `readable<T>`.)
I notably haven't unified `default_sentinel_t` with `_Default_sentinel` out of an abundance of paranoia. Our `move_iterator` is comparable with `_Default_sentinel`, which is not the case for `std::default_sentinel`.
Drive-by:
* This change `if constexpr`-izes `unique_copy`.
2019-12-03 02:32:14 +03:00
|
|
|
if constexpr (_Fill_memset_is_safe<_Unwrapped_t<const _NoThrowFwdIt&>, _Tval>) {
|
2020-09-04 21:21:21 +03:00
|
|
|
_Fill_memset(_UFirst, _Val, static_cast<size_t>(_ULast - _UFirst));
|
2019-09-05 01:57:56 +03:00
|
|
|
} else {
|
2020-10-29 10:12:36 +03:00
|
|
|
if constexpr (_Fill_zero_memset_is_safe<_Unwrapped_t<const _NoThrowFwdIt&>, _Tval>) {
|
|
|
|
if (_Is_all_bits_zero(_Val)) {
|
|
|
|
_Fill_zero_memset(_UFirst, static_cast<size_t>(_ULast - _UFirst));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2021-02-04 00:54:37 +03:00
|
|
|
|
[range.iter.ops], default_sentinel, and unreachable_sentinel (#329)
Implements iterator primitive operations `std::ranges::advance`, `std::ranges::next`, `std::ranges::prev`, and `std::ranges::distance`; as well as `std::default_sentinel` and `std::unreachable_sentinel`.
This change reworks the STL's iterator unwrapping machinery to enable unwrapping of C++20 move-only single-pass iterators (and `if constepxr`s all the things). Consequently, `_Iter_ref_t`, `_Iter_value_t`, and `_Iter_diff_t` resolve to `iter_reference_t`, `iter_value_t`, and `iter_difference_t` (respectively) in `__cpp_lib_concepts` (soon to be C++20) mode. This change necessitates some fixes to `unique_copy` and `_Fill_memset_is_safe` which both assume that `_Iter_value_t<T>` is well-formed for any iterator `T`. (`iter_value_t<T>` does not have that property: it is only well-formed when `readable<T>`.)
I notably haven't unified `default_sentinel_t` with `_Default_sentinel` out of an abundance of paranoia. Our `move_iterator` is comparable with `_Default_sentinel`, which is not the case for `std::default_sentinel`.
Drive-by:
* This change `if constexpr`-izes `unique_copy`.
2019-12-03 02:32:14 +03:00
|
|
|
_Uninitialized_backout<_Unwrapped_t<const _NoThrowFwdIt&>> _Backout{_UFirst};
|
2019-09-05 01:57:56 +03:00
|
|
|
while (_Backout._Last != _ULast) {
|
|
|
|
_Backout._Emplace_back(_Val);
|
|
|
|
}
|
|
|
|
|
|
|
|
_Backout._Release();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// FUNCTION TEMPLATE _Uninitialized_value_construct_n WITH ALLOCATOR
|
|
|
|
template <class _NoThrowFwdIt>
|
|
|
|
_INLINE_VAR constexpr bool _Use_memset_value_construct_v = conjunction_v<is_pointer<_NoThrowFwdIt>,
|
|
|
|
is_scalar<_Iter_value_t<_NoThrowFwdIt>>, negation<is_volatile<remove_reference_t<_Iter_ref_t<_NoThrowFwdIt>>>>,
|
|
|
|
negation<is_member_pointer<_Iter_value_t<_NoThrowFwdIt>>>>;
|
|
|
|
|
|
|
|
template <class _Ptr>
|
|
|
|
_Ptr _Zero_range(const _Ptr _First, const _Ptr _Last) { // fill [_First, _Last) with zeroes
|
|
|
|
char* const _First_ch = reinterpret_cast<char*>(_First);
|
|
|
|
char* const _Last_ch = reinterpret_cast<char*>(_Last);
|
|
|
|
_CSTD memset(_First_ch, 0, static_cast<size_t>(_Last_ch - _First_ch));
|
|
|
|
return _Last;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Alloc>
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20_DYNALLOC _Alloc_ptr_t<_Alloc> _Uninitialized_value_construct_n(
|
2019-09-05 01:57:56 +03:00
|
|
|
_Alloc_ptr_t<_Alloc> _First, _Alloc_size_t<_Alloc> _Count, _Alloc& _Al) {
|
|
|
|
// value-initialize _Count objects to raw _First, using _Al
|
|
|
|
using _Ptrty = typename _Alloc::value_type*;
|
|
|
|
if constexpr (_Use_memset_value_construct_v<_Ptrty> && _Uses_default_construct<_Alloc, _Ptrty>::value) {
|
2021-02-04 00:54:37 +03:00
|
|
|
#ifdef __cpp_lib_constexpr_dynamic_alloc
|
|
|
|
if (!_STD is_constant_evaluated())
|
|
|
|
#endif // __cpp_lib_constexpr_dynamic_alloc
|
|
|
|
{
|
|
|
|
auto _PFirst = _Unfancy(_First);
|
|
|
|
_Zero_range(_PFirst, _PFirst + _Count);
|
|
|
|
return _First + _Count;
|
2019-09-05 01:57:56 +03:00
|
|
|
}
|
2021-02-04 00:54:37 +03:00
|
|
|
}
|
2019-09-05 01:57:56 +03:00
|
|
|
|
2021-02-04 00:54:37 +03:00
|
|
|
_Uninitialized_backout_al<_Alloc> _Backout{_First, _Al};
|
|
|
|
for (; 0 < _Count; --_Count) {
|
|
|
|
_Backout._Emplace_back();
|
2019-09-05 01:57:56 +03:00
|
|
|
}
|
2021-02-04 00:54:37 +03:00
|
|
|
|
|
|
|
return _Backout._Release();
|
2019-09-05 01:57:56 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class _NoThrowFwdIt, class _Diff>
|
|
|
|
_NoThrowFwdIt _Uninitialized_value_construct_n_unchecked1(_NoThrowFwdIt _UFirst, _Diff _Count) {
|
|
|
|
// value-initialize all elements in [_UFirst, _UFirst + _Count_raw)
|
|
|
|
_STL_INTERNAL_CHECK(_Count >= 0);
|
|
|
|
if constexpr (_Use_memset_value_construct_v<_NoThrowFwdIt>) {
|
|
|
|
return _Zero_range(_UFirst, _UFirst + _Count);
|
|
|
|
} else {
|
|
|
|
_Uninitialized_backout<_NoThrowFwdIt> _Backout{_UFirst};
|
|
|
|
for (; 0 < _Count; --_Count) {
|
|
|
|
_Backout._Emplace_back();
|
|
|
|
}
|
|
|
|
|
|
|
|
return _Backout._Release();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-03 13:55:53 +03:00
|
|
|
#if _HAS_DEPRECATED_TEMPORARY_BUFFER
|
2019-09-05 01:57:56 +03:00
|
|
|
// FUNCTION TEMPLATE get_temporary_buffer
|
|
|
|
template <class _Ty>
|
2020-01-09 06:16:40 +03:00
|
|
|
_CXX17_DEPRECATE_TEMPORARY_BUFFER _NODISCARD pair<_Ty*, ptrdiff_t> get_temporary_buffer(ptrdiff_t _Count) noexcept {
|
2019-09-05 01:57:56 +03:00
|
|
|
return _Get_temporary_buffer<_Ty>(_Count);
|
|
|
|
}
|
|
|
|
|
|
|
|
// FUNCTION TEMPLATE return_temporary_buffer
|
|
|
|
template <class _Ty>
|
|
|
|
_CXX17_DEPRECATE_TEMPORARY_BUFFER void return_temporary_buffer(_Ty* _Pbuf) {
|
|
|
|
_Return_temporary_buffer(_Pbuf);
|
|
|
|
}
|
2020-02-03 13:55:53 +03:00
|
|
|
#endif // _HAS_DEPRECATED_TEMPORARY_BUFFER
|
2019-09-05 01:57:56 +03:00
|
|
|
|
|
|
|
// STRUCT TEMPLATE _In_place_key_extract_set
|
|
|
|
// assumes _Args have already been _Remove_cvref_t'd
|
|
|
|
template <class _Key, class... _Args>
|
|
|
|
struct _In_place_key_extract_set {
|
|
|
|
// by default we can't extract the key in the emplace family and must construct a node we might not use
|
|
|
|
static constexpr bool _Extractable = false;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <class _Key>
|
|
|
|
struct _In_place_key_extract_set<_Key, _Key> {
|
|
|
|
// we can extract the key in emplace if the emplaced type is identical to the key type
|
|
|
|
static constexpr bool _Extractable = true;
|
|
|
|
static const _Key& _Extract(const _Key& _Val) noexcept {
|
|
|
|
return _Val;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// STRUCT TEMPLATE _In_place_key_extract_map
|
|
|
|
// assumes _Args have already been _Remove_cvref_t'd
|
|
|
|
template <class _Key, class... Args>
|
|
|
|
struct _In_place_key_extract_map {
|
|
|
|
// by default we can't extract the key in the emplace family and must construct a node we might not use
|
|
|
|
static constexpr bool _Extractable = false;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <class _Key, class _Second>
|
|
|
|
struct _In_place_key_extract_map<_Key, _Key, _Second> {
|
|
|
|
// if we would call the pair(key, value) constructor family, we can use the first parameter as the key
|
|
|
|
static constexpr bool _Extractable = true;
|
|
|
|
static const _Key& _Extract(const _Key& _Val, const _Second&) noexcept {
|
|
|
|
return _Val;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template <class _Key, class _First, class _Second>
|
|
|
|
struct _In_place_key_extract_map<_Key, pair<_First, _Second>> {
|
|
|
|
// if we would call the pair(pair<other, other>) constructor family, we can use the pair.first member as the key
|
|
|
|
static constexpr bool _Extractable = is_same_v<_Key, _Remove_cvref_t<_First>>;
|
|
|
|
static const _Key& _Extract(const pair<_First, _Second>& _Val) {
|
|
|
|
return _Val.first;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// STRUCT TEMPLATE _Wrap
|
2021-02-02 06:43:49 +03:00
|
|
|
#pragma warning(push)
|
|
|
|
#pragma warning(disable : 4624) // '%s': destructor was implicitly defined as deleted
|
2019-09-05 01:57:56 +03:00
|
|
|
template <class _Ty>
|
|
|
|
struct _Wrap {
|
|
|
|
_Ty _Value; // workaround for "T^ is not allowed in a union"
|
|
|
|
};
|
2021-02-02 06:43:49 +03:00
|
|
|
#pragma warning(pop)
|
2019-09-05 01:57:56 +03:00
|
|
|
|
|
|
|
// STRUCT TEMPLATE _Alloc_temporary
|
|
|
|
template <class _Alloc>
|
|
|
|
struct _Alloc_temporary {
|
|
|
|
using value_type = typename _Alloc::value_type;
|
|
|
|
using _Traits = allocator_traits<_Alloc>;
|
|
|
|
|
|
|
|
_Alloc& _Al;
|
|
|
|
union {
|
|
|
|
_Wrap<value_type> _Storage;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <class... _Args>
|
|
|
|
explicit _Alloc_temporary(_Alloc& _Al_, _Args&&... _Vals) noexcept(
|
|
|
|
noexcept(_Traits::construct(_Al_, _STD addressof(_Storage._Value), _STD forward<_Args>(_Vals)...)))
|
|
|
|
: _Al(_Al_) {
|
|
|
|
_Traits::construct(_Al, _STD addressof(_Storage._Value), _STD forward<_Args>(_Vals)...);
|
|
|
|
}
|
|
|
|
|
|
|
|
_Alloc_temporary(const _Alloc_temporary&) = delete;
|
|
|
|
_Alloc_temporary& operator=(const _Alloc_temporary&) = delete;
|
|
|
|
|
|
|
|
~_Alloc_temporary() {
|
|
|
|
_Traits::destroy(_Al, _STD addressof(_Storage._Value));
|
|
|
|
}
|
|
|
|
};
|
2019-11-02 00:32:39 +03:00
|
|
|
|
Avoid double strlen for string operator+ and implement P1165R1 (#467)
Resolves GH-53.
Resolves GH-456.
Co-authored by: @barcharcraz
Co-authored by: @ArtemSarmini
This change adds a bespoke constructor to `basic_string` to handle string concat use cases, removing any EH states we previously emitted in our operator+s, avoiding double strlen in our operator+s,
The EH states problem comes from our old pattern:
```
S operator+(a, b) {
S result;
result.reserve(a.size() +b.size()); // throws
result += a; // throws
result += b; // throws
return result;
}
```
Here, the compiler does not know that the append operation can't throw, because it doesn't understand `basic_string` and doesn't know the `reserve` has made that always safe. As a result, the compiler emitted EH handing code to call `result`'s destructor after each of the reserve and `operator+=` calls.
Using a bespoke concatenating constructor avoids these problems because there is only one throwing operation (in IDL0 mode). As expected, this results in a small performance win in all concats due to avoiding needing to set up EH stuff, and a large performance win for the `const char*` concats due to the avoided second `strlen`:
Performance:
```
#include <benchmark/benchmark.h>
#include <stdint.h>
#include <string>
constexpr size_t big = 2 << 12;
constexpr size_t multiplier = 64;
static void string_concat_string(benchmark::State &state) {
std::string x(static_cast<size_t>(state.range(0)), 'a');
std::string y(static_cast<size_t>(state.range(1)), 'b');
for (auto _ : state) {
(void)_;
benchmark::DoNotOptimize(x + y);
}
}
BENCHMARK(string_concat_string)->RangeMultiplier(multiplier)->Ranges({{2, big}, {2, big}});
static void string_concat_ntbs(benchmark::State &state) {
std::string x(static_cast<size_t>(state.range(0)), 'a');
std::string yBuf(static_cast<size_t>(state.range(1)), 'b');
const char *const y = yBuf.c_str();
for (auto _ : state) {
(void)_;
benchmark::DoNotOptimize(x + y);
}
}
BENCHMARK(string_concat_ntbs)->RangeMultiplier(multiplier)->Ranges({{2, big}, {2, big}});
static void string_concat_char(benchmark::State &state) {
std::string x(static_cast<size_t>(state.range(0)), 'a');
for (auto _ : state) {
(void)_;
benchmark::DoNotOptimize(x + 'b');
}
}
BENCHMARK(string_concat_char)->Range(2, big);
static void ntbs_concat_string(benchmark::State &state) {
std::string xBuf(static_cast<size_t>(state.range(0)), 'a');
const char *const x = xBuf.c_str();
std::string y(static_cast<size_t>(state.range(1)), 'b');
for (auto _ : state) {
(void)_;
benchmark::DoNotOptimize(x + y);
}
}
BENCHMARK(ntbs_concat_string)->RangeMultiplier(multiplier)->Ranges({{2, big}, {2, big}});
static void char_concat_string(benchmark::State &state) {
std::string x(static_cast<size_t>(state.range(0)), 'a');
for (auto _ : state) {
(void)_;
benchmark::DoNotOptimize('b' + x);
}
}
BENCHMARK(char_concat_string)->Range(2, big);
BENCHMARK_MAIN();
```
Times are in NS on a Ryzen Threadripper 3970X, improvements are `((Old/New)-1)*100`
| | old x64 | new x64 | improvement | old x86 | new x86 | improvement |
| ------------------------------- | ------- | ------- | ----------- | ------- |-------- | ----------- |
| string_concat_string/2/2 | 12.8697 | 5.78125 | 122.61% | 13.9029 | 11.0696 | 25.60% |
| string_concat_string/64/2 | 62.779 | 61.3839 | 2.27% | 66.4394 | 61.6296 | 7.80% |
| string_concat_string/4096/2 | 125.558 | 124.512 | 0.84% | 124.477 | 117.606 | 5.84% |
| string_concat_string/8192/2 | 188.337 | 184.152 | 2.27% | 189.982 | 185.598 | 2.36% |
| string_concat_string/2/64 | 64.5229 | 64.1741 | 0.54% | 67.1338 | 61.4962 | 9.17% |
| string_concat_string/64/64 | 65.5692 | 59.9888 | 9.30% | 66.7742 | 60.4781 | 10.41% |
| string_concat_string/4096/64 | 122.768 | 122.768 | 0.00% | 126.774 | 116.327 | 8.98% |
| string_concat_string/8192/64 | 190.43 | 181.362 | 5.00% | 188.516 | 186.234 | 1.23% |
| string_concat_string/2/4096 | 125.558 | 119.978 | 4.65% | 120.444 | 111.524 | 8.00% |
| string_concat_string/64/4096 | 125.558 | 119.978 | 4.65% | 122.911 | 117.136 | 4.93% |
| string_concat_string/4096/4096 | 188.337 | 184.152 | 2.27% | 193.337 | 182.357 | 6.02% |
| string_concat_string/8192/4096 | 273.438 | 266.811 | 2.48% | 267.656 | 255.508 | 4.75% |
| string_concat_string/2/8192 | 205.078 | 194.964 | 5.19% | 175.025 | 170.181 | 2.85% |
| string_concat_string/64/8192 | 205.078 | 188.337 | 8.89% | 191.676 | 183.06 | 4.71% |
| string_concat_string/4096/8192 | 266.811 | 256.696 | 3.94% | 267.455 | 255.221 | 4.79% |
| string_concat_string/8192/8192 | 414.69 | 435.965 | -4.88% | 412.784 | 403.01 | 2.43% |
| string_concat_ntbs/2/2 | 12.8348 | 5.9375 | 116.17% | 14.74 | 11.132 | 32.41% |
| string_concat_ntbs/64/2 | 71.1496 | 59.375 | 19.83% | 70.6934 | 60.9371 | 16.01% |
| string_concat_ntbs/4096/2 | 128.697 | 114.397 | 12.50% | 126.626 | 121.887 | 3.89% |
| string_concat_ntbs/8192/2 | 194.964 | 176.479 | 10.47% | 196.641 | 186.88 | 5.22% |
| string_concat_ntbs/2/64 | 100.446 | 74.986 | 33.95% | 109.082 | 83.3939 | 30.80% |
| string_concat_ntbs/64/64 | 106.027 | 78.4738 | 35.11% | 109.589 | 84.3635 | 29.90% |
| string_concat_ntbs/4096/64 | 164.969 | 138.114 | 19.44% | 165.417 | 142.116 | 16.40% |
| string_concat_ntbs/8192/64 | 224.958 | 200.195 | 12.37% | 228.769 | 200.347 | 14.19% |
| string_concat_ntbs/2/4096 | 2040.32 | 1074.22 | 89.94% | 2877.33 | 1362.74 | 111.14% |
| string_concat_ntbs/64/4096 | 1994.98 | 1074.22 | 85.71% | 2841.93 | 1481.62 | 91.81% |
| string_concat_ntbs/4096/4096 | 2050.78 | 1147.46 | 78.72% | 2907.78 | 1550.82 | 87.50% |
| string_concat_ntbs/8192/4096 | 2148.44 | 1227.68 | 75.00% | 2966.92 | 1583.78 | 87.33% |
| string_concat_ntbs/2/8192 | 3934.14 | 2099.61 | 87.37% | 5563.32 | 2736.56 | 103.30% |
| string_concat_ntbs/64/8192 | 3989.95 | 1994.98 | 100.00% | 5456.84 | 2823.53 | 93.26% |
| string_concat_ntbs/4096/8192 | 4049.24 | 2197.27 | 84.29% | 5674.02 | 2957.04 | 91.88% |
| string_concat_ntbs/8192/8192 | 4237.58 | 2249.58 | 88.37% | 5755.07 | 3095.65 | 85.91% |
| string_concat_char/2 | 12.8348 | 3.44936 | 272.09% | 11.1104 | 10.6976 | 3.86% |
| string_concat_char/8 | 8.99833 | 3.45285 | 160.61% | 11.1964 | 10.6928 | 4.71% |
| string_concat_char/64 | 65.5692 | 60.9375 | 7.60% | 65.7585 | 60.0182 | 9.56% |
| string_concat_char/512 | 72.5446 | 69.7545 | 4.00% | 83.952 | 79.5254 | 5.57% |
| string_concat_char/4096 | 125.558 | 119.978 | 4.65% | 123.475 | 117.103 | 5.44% |
| string_concat_char/8192 | 190.43 | 187.988 | 1.30% | 189.181 | 185.174 | 2.16% |
| ntbs_concat_string/2/2 | 13.4975 | 6.13839 | 119.89% | 14.8623 | 11.09 | 34.02% |
| ntbs_concat_string/64/2 | 104.98 | 79.5201 | 32.02% | 112.207 | 83.7111 | 34.04% |
| ntbs_concat_string/4096/2 | 2085.66 | 1098.63 | 89.84% | 2815.19 | 1456.08 | 93.34% |
| ntbs_concat_string/8192/2 | 3899.27 | 2099.61 | 85.71% | 5544.52 | 2765.16 | 100.51% |
| ntbs_concat_string/2/64 | 71.4983 | 62.779 | 13.89% | 72.6602 | 63.1953 | 14.98% |
| ntbs_concat_string/64/64 | 104.98 | 80.2176 | 30.87% | 111.073 | 81.8413 | 35.72% |
| ntbs_concat_string/4096/64 | 2085.66 | 1074.22 | 94.16% | 2789.73 | 1318.7 | 111.55% |
| ntbs_concat_string/8192/64 | 3989.95 | 2085.66 | 91.30% | 5486.85 | 2693.83 | 103.68% |
| ntbs_concat_string/2/4096 | 136.719 | 128.348 | 6.52% | 122.605 | 114.44 | 7.13% |
| ntbs_concat_string/64/4096 | 167.411 | 142.997 | 17.07% | 168.572 | 138.566 | 21.65% |
| ntbs_concat_string/4096/40 | 2099.61 | 1171.88 | 79.17% | 2923.85 | 1539.02 | 89.98% |
| ntbs_concat_string/8192/40 | 4098.07 | 2246.09 | 82.45% | 5669.34 | 3005.25 | 88.65% |
| ntbs_concat_string/2/8192 | 213.1 | 199.498 | 6.82% | 178.197 | 168.532 | 5.73% |
| ntbs_concat_string/64/8192 | 223.214 | 214.844 | 3.90% | 232.263 | 203.722 | 14.01% |
| ntbs_concat_string/4096/81 | 2148.44 | 1255.58 | 71.11% | 2980.78 | 1612.97 | 84.80% |
| ntbs_concat_string/8192/81 | 4237.58 | 2406.53 | 76.09% | 5775.55 | 3067.94 | 88.25% |
| char_concat_string/2 | 11.1607 | 3.60631 | 209.48% | 11.2101 | 10.7192 | 4.58% |
| char_concat_string/8 | 11.4746 | 3.52958 | 225.10% | 11.4595 | 10.709 | 7.01% |
| char_concat_string/64 | 65.5692 | 66.9643 | -2.08% | 66.6272 | 60.8601 | 9.48% |
| char_concat_string/512 | 68.0106 | 73.2422 | -7.14% | 91.1946 | 83.0791 | 9.77% |
| char_concat_string/4096 | 125.558 | 122.768 | 2.27% | 119.432 | 110.031 | 8.54% |
| char_concat_string/8192 | 199.498 | 199.498 | 0.00% | 171.895 | 169.173 | 1.61% |
Code size:
```
#include <string>
std::string strings(const std::string& a, const std::string& b) {
return a + b;
}
std::string string_ntbs(const std::string& a, const char * b) {
return a + b;
}
std::string string_char(const std::string& a, char b) {
return a + b;
}
std::string ntbs_string(const char * a, const std::string& b) {
return a + b;
}
std::string char_string(char a, const std::string& b) {
return a + b;
}
```
Sizes are in bytes for the `.obj`, "Times Original" is New/Old, `cl /EHsc /W4 /WX /c /O2 .\code_size.cpp`:
| Bytes | Before | After | Times Original |
| ----- | ------ | ------ | -------------- |
| x64 | 70,290 | 34,192 | 0.486 |
| x86 | 47,152 | 28,792 | 0.611 |
2020-02-01 03:45:39 +03:00
|
|
|
template <class _Alloc>
|
|
|
|
_NODISCARD constexpr bool _Allocators_equal(const _Alloc& _Lhs, const _Alloc& _Rhs) noexcept {
|
2021-01-06 04:19:12 +03:00
|
|
|
if constexpr (allocator_traits<_Alloc>::is_always_equal::value) {
|
2020-03-29 04:53:15 +03:00
|
|
|
return true;
|
|
|
|
} else {
|
Avoid double strlen for string operator+ and implement P1165R1 (#467)
Resolves GH-53.
Resolves GH-456.
Co-authored by: @barcharcraz
Co-authored by: @ArtemSarmini
This change adds a bespoke constructor to `basic_string` to handle string concat use cases, removing any EH states we previously emitted in our operator+s, avoiding double strlen in our operator+s,
The EH states problem comes from our old pattern:
```
S operator+(a, b) {
S result;
result.reserve(a.size() +b.size()); // throws
result += a; // throws
result += b; // throws
return result;
}
```
Here, the compiler does not know that the append operation can't throw, because it doesn't understand `basic_string` and doesn't know the `reserve` has made that always safe. As a result, the compiler emitted EH handing code to call `result`'s destructor after each of the reserve and `operator+=` calls.
Using a bespoke concatenating constructor avoids these problems because there is only one throwing operation (in IDL0 mode). As expected, this results in a small performance win in all concats due to avoiding needing to set up EH stuff, and a large performance win for the `const char*` concats due to the avoided second `strlen`:
Performance:
```
#include <benchmark/benchmark.h>
#include <stdint.h>
#include <string>
constexpr size_t big = 2 << 12;
constexpr size_t multiplier = 64;
static void string_concat_string(benchmark::State &state) {
std::string x(static_cast<size_t>(state.range(0)), 'a');
std::string y(static_cast<size_t>(state.range(1)), 'b');
for (auto _ : state) {
(void)_;
benchmark::DoNotOptimize(x + y);
}
}
BENCHMARK(string_concat_string)->RangeMultiplier(multiplier)->Ranges({{2, big}, {2, big}});
static void string_concat_ntbs(benchmark::State &state) {
std::string x(static_cast<size_t>(state.range(0)), 'a');
std::string yBuf(static_cast<size_t>(state.range(1)), 'b');
const char *const y = yBuf.c_str();
for (auto _ : state) {
(void)_;
benchmark::DoNotOptimize(x + y);
}
}
BENCHMARK(string_concat_ntbs)->RangeMultiplier(multiplier)->Ranges({{2, big}, {2, big}});
static void string_concat_char(benchmark::State &state) {
std::string x(static_cast<size_t>(state.range(0)), 'a');
for (auto _ : state) {
(void)_;
benchmark::DoNotOptimize(x + 'b');
}
}
BENCHMARK(string_concat_char)->Range(2, big);
static void ntbs_concat_string(benchmark::State &state) {
std::string xBuf(static_cast<size_t>(state.range(0)), 'a');
const char *const x = xBuf.c_str();
std::string y(static_cast<size_t>(state.range(1)), 'b');
for (auto _ : state) {
(void)_;
benchmark::DoNotOptimize(x + y);
}
}
BENCHMARK(ntbs_concat_string)->RangeMultiplier(multiplier)->Ranges({{2, big}, {2, big}});
static void char_concat_string(benchmark::State &state) {
std::string x(static_cast<size_t>(state.range(0)), 'a');
for (auto _ : state) {
(void)_;
benchmark::DoNotOptimize('b' + x);
}
}
BENCHMARK(char_concat_string)->Range(2, big);
BENCHMARK_MAIN();
```
Times are in NS on a Ryzen Threadripper 3970X, improvements are `((Old/New)-1)*100`
| | old x64 | new x64 | improvement | old x86 | new x86 | improvement |
| ------------------------------- | ------- | ------- | ----------- | ------- |-------- | ----------- |
| string_concat_string/2/2 | 12.8697 | 5.78125 | 122.61% | 13.9029 | 11.0696 | 25.60% |
| string_concat_string/64/2 | 62.779 | 61.3839 | 2.27% | 66.4394 | 61.6296 | 7.80% |
| string_concat_string/4096/2 | 125.558 | 124.512 | 0.84% | 124.477 | 117.606 | 5.84% |
| string_concat_string/8192/2 | 188.337 | 184.152 | 2.27% | 189.982 | 185.598 | 2.36% |
| string_concat_string/2/64 | 64.5229 | 64.1741 | 0.54% | 67.1338 | 61.4962 | 9.17% |
| string_concat_string/64/64 | 65.5692 | 59.9888 | 9.30% | 66.7742 | 60.4781 | 10.41% |
| string_concat_string/4096/64 | 122.768 | 122.768 | 0.00% | 126.774 | 116.327 | 8.98% |
| string_concat_string/8192/64 | 190.43 | 181.362 | 5.00% | 188.516 | 186.234 | 1.23% |
| string_concat_string/2/4096 | 125.558 | 119.978 | 4.65% | 120.444 | 111.524 | 8.00% |
| string_concat_string/64/4096 | 125.558 | 119.978 | 4.65% | 122.911 | 117.136 | 4.93% |
| string_concat_string/4096/4096 | 188.337 | 184.152 | 2.27% | 193.337 | 182.357 | 6.02% |
| string_concat_string/8192/4096 | 273.438 | 266.811 | 2.48% | 267.656 | 255.508 | 4.75% |
| string_concat_string/2/8192 | 205.078 | 194.964 | 5.19% | 175.025 | 170.181 | 2.85% |
| string_concat_string/64/8192 | 205.078 | 188.337 | 8.89% | 191.676 | 183.06 | 4.71% |
| string_concat_string/4096/8192 | 266.811 | 256.696 | 3.94% | 267.455 | 255.221 | 4.79% |
| string_concat_string/8192/8192 | 414.69 | 435.965 | -4.88% | 412.784 | 403.01 | 2.43% |
| string_concat_ntbs/2/2 | 12.8348 | 5.9375 | 116.17% | 14.74 | 11.132 | 32.41% |
| string_concat_ntbs/64/2 | 71.1496 | 59.375 | 19.83% | 70.6934 | 60.9371 | 16.01% |
| string_concat_ntbs/4096/2 | 128.697 | 114.397 | 12.50% | 126.626 | 121.887 | 3.89% |
| string_concat_ntbs/8192/2 | 194.964 | 176.479 | 10.47% | 196.641 | 186.88 | 5.22% |
| string_concat_ntbs/2/64 | 100.446 | 74.986 | 33.95% | 109.082 | 83.3939 | 30.80% |
| string_concat_ntbs/64/64 | 106.027 | 78.4738 | 35.11% | 109.589 | 84.3635 | 29.90% |
| string_concat_ntbs/4096/64 | 164.969 | 138.114 | 19.44% | 165.417 | 142.116 | 16.40% |
| string_concat_ntbs/8192/64 | 224.958 | 200.195 | 12.37% | 228.769 | 200.347 | 14.19% |
| string_concat_ntbs/2/4096 | 2040.32 | 1074.22 | 89.94% | 2877.33 | 1362.74 | 111.14% |
| string_concat_ntbs/64/4096 | 1994.98 | 1074.22 | 85.71% | 2841.93 | 1481.62 | 91.81% |
| string_concat_ntbs/4096/4096 | 2050.78 | 1147.46 | 78.72% | 2907.78 | 1550.82 | 87.50% |
| string_concat_ntbs/8192/4096 | 2148.44 | 1227.68 | 75.00% | 2966.92 | 1583.78 | 87.33% |
| string_concat_ntbs/2/8192 | 3934.14 | 2099.61 | 87.37% | 5563.32 | 2736.56 | 103.30% |
| string_concat_ntbs/64/8192 | 3989.95 | 1994.98 | 100.00% | 5456.84 | 2823.53 | 93.26% |
| string_concat_ntbs/4096/8192 | 4049.24 | 2197.27 | 84.29% | 5674.02 | 2957.04 | 91.88% |
| string_concat_ntbs/8192/8192 | 4237.58 | 2249.58 | 88.37% | 5755.07 | 3095.65 | 85.91% |
| string_concat_char/2 | 12.8348 | 3.44936 | 272.09% | 11.1104 | 10.6976 | 3.86% |
| string_concat_char/8 | 8.99833 | 3.45285 | 160.61% | 11.1964 | 10.6928 | 4.71% |
| string_concat_char/64 | 65.5692 | 60.9375 | 7.60% | 65.7585 | 60.0182 | 9.56% |
| string_concat_char/512 | 72.5446 | 69.7545 | 4.00% | 83.952 | 79.5254 | 5.57% |
| string_concat_char/4096 | 125.558 | 119.978 | 4.65% | 123.475 | 117.103 | 5.44% |
| string_concat_char/8192 | 190.43 | 187.988 | 1.30% | 189.181 | 185.174 | 2.16% |
| ntbs_concat_string/2/2 | 13.4975 | 6.13839 | 119.89% | 14.8623 | 11.09 | 34.02% |
| ntbs_concat_string/64/2 | 104.98 | 79.5201 | 32.02% | 112.207 | 83.7111 | 34.04% |
| ntbs_concat_string/4096/2 | 2085.66 | 1098.63 | 89.84% | 2815.19 | 1456.08 | 93.34% |
| ntbs_concat_string/8192/2 | 3899.27 | 2099.61 | 85.71% | 5544.52 | 2765.16 | 100.51% |
| ntbs_concat_string/2/64 | 71.4983 | 62.779 | 13.89% | 72.6602 | 63.1953 | 14.98% |
| ntbs_concat_string/64/64 | 104.98 | 80.2176 | 30.87% | 111.073 | 81.8413 | 35.72% |
| ntbs_concat_string/4096/64 | 2085.66 | 1074.22 | 94.16% | 2789.73 | 1318.7 | 111.55% |
| ntbs_concat_string/8192/64 | 3989.95 | 2085.66 | 91.30% | 5486.85 | 2693.83 | 103.68% |
| ntbs_concat_string/2/4096 | 136.719 | 128.348 | 6.52% | 122.605 | 114.44 | 7.13% |
| ntbs_concat_string/64/4096 | 167.411 | 142.997 | 17.07% | 168.572 | 138.566 | 21.65% |
| ntbs_concat_string/4096/40 | 2099.61 | 1171.88 | 79.17% | 2923.85 | 1539.02 | 89.98% |
| ntbs_concat_string/8192/40 | 4098.07 | 2246.09 | 82.45% | 5669.34 | 3005.25 | 88.65% |
| ntbs_concat_string/2/8192 | 213.1 | 199.498 | 6.82% | 178.197 | 168.532 | 5.73% |
| ntbs_concat_string/64/8192 | 223.214 | 214.844 | 3.90% | 232.263 | 203.722 | 14.01% |
| ntbs_concat_string/4096/81 | 2148.44 | 1255.58 | 71.11% | 2980.78 | 1612.97 | 84.80% |
| ntbs_concat_string/8192/81 | 4237.58 | 2406.53 | 76.09% | 5775.55 | 3067.94 | 88.25% |
| char_concat_string/2 | 11.1607 | 3.60631 | 209.48% | 11.2101 | 10.7192 | 4.58% |
| char_concat_string/8 | 11.4746 | 3.52958 | 225.10% | 11.4595 | 10.709 | 7.01% |
| char_concat_string/64 | 65.5692 | 66.9643 | -2.08% | 66.6272 | 60.8601 | 9.48% |
| char_concat_string/512 | 68.0106 | 73.2422 | -7.14% | 91.1946 | 83.0791 | 9.77% |
| char_concat_string/4096 | 125.558 | 122.768 | 2.27% | 119.432 | 110.031 | 8.54% |
| char_concat_string/8192 | 199.498 | 199.498 | 0.00% | 171.895 | 169.173 | 1.61% |
Code size:
```
#include <string>
std::string strings(const std::string& a, const std::string& b) {
return a + b;
}
std::string string_ntbs(const std::string& a, const char * b) {
return a + b;
}
std::string string_char(const std::string& a, char b) {
return a + b;
}
std::string ntbs_string(const char * a, const std::string& b) {
return a + b;
}
std::string char_string(char a, const std::string& b) {
return a + b;
}
```
Sizes are in bytes for the `.obj`, "Times Original" is New/Old, `cl /EHsc /W4 /WX /c /O2 .\code_size.cpp`:
| Bytes | Before | After | Times Original |
| ----- | ------ | ------ | -------------- |
| x64 | 70,290 | 34,192 | 0.486 |
| x86 | 47,152 | 28,792 | 0.611 |
2020-02-01 03:45:39 +03:00
|
|
|
return _Lhs == _Rhs;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-02 00:32:39 +03:00
|
|
|
// FUNCTION TEMPLATE remove
|
|
|
|
template <class _FwdIt, class _Ty>
|
2020-01-23 04:57:27 +03:00
|
|
|
_NODISCARD _CONSTEXPR20 _FwdIt remove(_FwdIt _First, const _FwdIt _Last, const _Ty& _Val) {
|
|
|
|
// remove each matching _Val
|
2019-11-02 00:32:39 +03:00
|
|
|
_Adl_verify_range(_First, _Last);
|
|
|
|
auto _UFirst = _Get_unwrapped(_First);
|
|
|
|
const auto _ULast = _Get_unwrapped(_Last);
|
|
|
|
_UFirst = _Find_unchecked(_UFirst, _ULast, _Val);
|
|
|
|
auto _UNext = _UFirst;
|
|
|
|
if (_UFirst != _ULast) {
|
|
|
|
while (++_UFirst != _ULast) {
|
|
|
|
if (!(*_UFirst == _Val)) {
|
|
|
|
*_UNext = _STD move(*_UFirst);
|
|
|
|
++_UNext;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_Seek_wrapped(_First, _UNext);
|
|
|
|
return _First;
|
|
|
|
}
|
|
|
|
|
|
|
|
// FUNCTION TEMPLATE remove_if
|
|
|
|
template <class _FwdIt, class _Pr>
|
2020-01-23 04:57:27 +03:00
|
|
|
_NODISCARD _CONSTEXPR20 _FwdIt remove_if(_FwdIt _First, const _FwdIt _Last, _Pr _Pred) {
|
|
|
|
// remove each satisfying _Pred
|
2019-11-02 00:32:39 +03:00
|
|
|
_Adl_verify_range(_First, _Last);
|
|
|
|
auto _UFirst = _Get_unwrapped(_First);
|
|
|
|
const auto _ULast = _Get_unwrapped(_Last);
|
|
|
|
_UFirst = _STD find_if(_UFirst, _ULast, _Pass_fn(_Pred));
|
|
|
|
auto _UNext = _UFirst;
|
|
|
|
if (_UFirst != _ULast) {
|
|
|
|
while (++_UFirst != _ULast) {
|
|
|
|
if (!_Pred(*_UFirst)) {
|
|
|
|
*_UNext = _STD move(*_UFirst);
|
|
|
|
++_UNext;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_Seek_wrapped(_First, _UNext);
|
|
|
|
return _First;
|
|
|
|
}
|
|
|
|
|
|
|
|
// FUNCTION TEMPLATE _Erase_remove
|
|
|
|
template <class _Container, class _Uty>
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20_DYNALLOC typename _Container::size_type _Erase_remove(_Container& _Cont, const _Uty& _Val) {
|
|
|
|
// erase each element matching _Val
|
2020-03-01 01:35:24 +03:00
|
|
|
auto _First = _Cont.begin();
|
|
|
|
const auto _Last = _Cont.end();
|
|
|
|
const auto _Old_size = _Cont.size();
|
2019-11-02 00:32:39 +03:00
|
|
|
_Seek_wrapped(_First, _STD remove(_Get_unwrapped(_First), _Get_unwrapped(_Last), _Val));
|
|
|
|
_Cont.erase(_First, _Last);
|
2020-03-01 01:35:24 +03:00
|
|
|
return _Old_size - _Cont.size();
|
2019-11-02 00:32:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// FUNCTION TEMPLATE _Erase_remove_if
|
|
|
|
template <class _Container, class _Pr>
|
2021-02-04 00:54:37 +03:00
|
|
|
_CONSTEXPR20_DYNALLOC typename _Container::size_type _Erase_remove_if(_Container& _Cont, _Pr _Pred) {
|
|
|
|
// erase each element satisfying _Pred
|
2020-03-01 01:35:24 +03:00
|
|
|
auto _First = _Cont.begin();
|
|
|
|
const auto _Last = _Cont.end();
|
|
|
|
const auto _Old_size = _Cont.size();
|
2019-11-02 00:32:39 +03:00
|
|
|
_Seek_wrapped(_First, _STD remove_if(_Get_unwrapped(_First), _Get_unwrapped(_Last), _Pred));
|
|
|
|
_Cont.erase(_First, _Last);
|
2020-03-01 01:35:24 +03:00
|
|
|
return _Old_size - _Cont.size();
|
2019-11-02 00:32:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// FUNCTION TEMPLATE _Erase_nodes_if
|
|
|
|
template <class _Container, class _Pr>
|
2021-02-04 00:54:37 +03:00
|
|
|
typename _Container::size_type _Erase_nodes_if(_Container& _Cont, _Pr _Pred) {
|
|
|
|
// erase each element satisfying _Pred
|
2020-03-01 01:35:24 +03:00
|
|
|
auto _First = _Cont.begin();
|
|
|
|
const auto _Last = _Cont.end();
|
|
|
|
const auto _Old_size = _Cont.size();
|
2019-11-02 00:32:39 +03:00
|
|
|
while (_First != _Last) {
|
|
|
|
if (_Pred(*_First)) {
|
|
|
|
_First = _Cont.erase(_First);
|
|
|
|
} else {
|
|
|
|
++_First;
|
|
|
|
}
|
|
|
|
}
|
2020-03-01 01:35:24 +03:00
|
|
|
return _Old_size - _Cont.size();
|
2019-11-02 00:32:39 +03:00
|
|
|
}
|
2021-02-26 05:26:14 +03:00
|
|
|
|
|
|
|
#if _HAS_CXX20
|
|
|
|
template <class _Ty, class _Alloc, class... _Types, enable_if_t<!_Is_specialization_v<_Ty, pair>, int> = 0>
|
|
|
|
_NODISCARD constexpr auto uses_allocator_construction_args(const _Alloc& _Al, _Types&&... _Args) noexcept {
|
|
|
|
if constexpr (!uses_allocator_v<_Ty, _Alloc>) {
|
|
|
|
static_assert(is_constructible_v<_Ty, _Types...>,
|
|
|
|
"If uses_allocator_v<T, Alloc> does not hold, T must be constructible from Types...");
|
|
|
|
(void) _Al;
|
|
|
|
return _STD forward_as_tuple(_STD forward<_Types>(_Args)...);
|
|
|
|
} else if constexpr (is_constructible_v<_Ty, allocator_arg_t, const _Alloc&, _Types...>) {
|
|
|
|
using _ReturnType = tuple<allocator_arg_t, const _Alloc&, _Types&&...>;
|
|
|
|
return _ReturnType{allocator_arg, _Al, _STD forward<_Types>(_Args)...};
|
|
|
|
} else if constexpr (is_constructible_v<_Ty, _Types..., const _Alloc&>) {
|
|
|
|
return _STD forward_as_tuple(_STD forward<_Types>(_Args)..., _Al);
|
|
|
|
} else {
|
|
|
|
static_assert(_Always_false<_Ty>,
|
|
|
|
"T must be constructible from either (allocator_arg_t, const Alloc&, Types...) "
|
|
|
|
"or (Types..., const Alloc&) if uses_allocator_v<T, Alloc> is true");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Ty, class _Alloc, class _Tuple1, class _Tuple2, enable_if_t<_Is_specialization_v<_Ty, pair>, int> = 0>
|
|
|
|
_NODISCARD constexpr auto uses_allocator_construction_args(
|
|
|
|
const _Alloc& _Al, piecewise_construct_t, _Tuple1&& _Tup1, _Tuple2&& _Tup2) noexcept {
|
|
|
|
return _STD make_tuple(piecewise_construct,
|
|
|
|
_STD apply(
|
|
|
|
[&_Al](auto&&... _Tuple_args) {
|
|
|
|
return _STD uses_allocator_construction_args<typename _Ty::first_type>(
|
|
|
|
_Al, _STD forward<decltype(_Tuple_args)>(_Tuple_args)...);
|
|
|
|
},
|
|
|
|
_STD forward<_Tuple1>(_Tup1)),
|
|
|
|
_STD apply(
|
|
|
|
[&_Al](auto&&... _Tuple_args) {
|
|
|
|
return _STD uses_allocator_construction_args<typename _Ty::second_type>(
|
|
|
|
_Al, _STD forward<decltype(_Tuple_args)>(_Tuple_args)...);
|
|
|
|
},
|
|
|
|
_STD forward<_Tuple2>(_Tup2)));
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Ty, class _Alloc, enable_if_t<_Is_specialization_v<_Ty, pair>, int> = 0>
|
|
|
|
_NODISCARD constexpr auto uses_allocator_construction_args(const _Alloc& _Al) noexcept {
|
|
|
|
// equivalent to
|
|
|
|
// return _STD uses_allocator_construction_args<_Ty>(_Al, piecewise_construct, tuple<>{}, tuple<>{});
|
|
|
|
return _STD make_tuple(piecewise_construct, _STD uses_allocator_construction_args<typename _Ty::first_type>(_Al),
|
|
|
|
_STD uses_allocator_construction_args<typename _Ty::second_type>(_Al));
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Ty, class _Alloc, class _Uty1, class _Uty2, enable_if_t<_Is_specialization_v<_Ty, pair>, int> = 0>
|
|
|
|
_NODISCARD constexpr auto uses_allocator_construction_args(const _Alloc& _Al, _Uty1&& _Val1, _Uty2&& _Val2) noexcept {
|
|
|
|
// equivalent to
|
|
|
|
// return _STD uses_allocator_construction_args<_Ty>(_Al, piecewise_construct,
|
|
|
|
// _STD forward_as_tuple(_STD forward<_Uty1>(_Val1)), _STD forward_as_tuple(_STD forward<_Uty2>(_Val2)));
|
|
|
|
return _STD make_tuple(piecewise_construct,
|
|
|
|
_STD uses_allocator_construction_args<typename _Ty::first_type>(_Al, _STD forward<_Uty1>(_Val1)),
|
|
|
|
_STD uses_allocator_construction_args<typename _Ty::second_type>(_Al, _STD forward<_Uty2>(_Val2)));
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Ty, class _Alloc, class _Uty1, class _Uty2, enable_if_t<_Is_specialization_v<_Ty, pair>, int> = 0>
|
|
|
|
_NODISCARD constexpr auto uses_allocator_construction_args(
|
|
|
|
const _Alloc& _Al, const pair<_Uty1, _Uty2>& _Pair) noexcept {
|
|
|
|
// equivalent to
|
|
|
|
// return _STD uses_allocator_construction_args<_Ty>(_Al, piecewise_construct,
|
|
|
|
// _STD forward_as_tuple(_Pair.first), _STD forward_as_tuple(_Pair.second));
|
|
|
|
return _STD make_tuple(piecewise_construct,
|
|
|
|
_STD uses_allocator_construction_args<typename _Ty::first_type>(_Al, _Pair.first),
|
|
|
|
_STD uses_allocator_construction_args<typename _Ty::second_type>(_Al, _Pair.second));
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Ty, class _Alloc, class _Uty1, class _Uty2, enable_if_t<_Is_specialization_v<_Ty, pair>, int> = 0>
|
|
|
|
_NODISCARD constexpr auto uses_allocator_construction_args(const _Alloc& _Al, pair<_Uty1, _Uty2>&& _Pair) noexcept {
|
|
|
|
// equivalent to
|
|
|
|
// return _STD uses_allocator_construction_args<_Ty>(_Al, piecewise_construct,
|
|
|
|
// _STD forward_as_tuple(_STD move(_Pair).first), _STD forward_as_tuple(_STD move(_Pair).second));
|
|
|
|
return _STD make_tuple(piecewise_construct,
|
|
|
|
_STD uses_allocator_construction_args<typename _Ty::first_type>(_Al, _STD move(_Pair).first),
|
|
|
|
_STD uses_allocator_construction_args<typename _Ty::second_type>(_Al, _STD move(_Pair).second));
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Ty, class _Alloc, class... _Types>
|
|
|
|
_NODISCARD constexpr _Ty make_obj_using_allocator(const _Alloc& _Al, _Types&&... _Args) {
|
|
|
|
return _STD make_from_tuple<_Ty>(_STD uses_allocator_construction_args<_Ty>(_Al, _STD forward<_Types>(_Args)...));
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Ty, class _Alloc, class... _Types>
|
|
|
|
constexpr _Ty* uninitialized_construct_using_allocator(_Ty* _Ptr, const _Alloc& _Al, _Types&&... _Args) {
|
|
|
|
return _STD apply(
|
|
|
|
[&](auto&&... _Construct_args) {
|
|
|
|
return _STD construct_at(_Ptr, _STD forward<decltype(_Construct_args)>(_Construct_args)...);
|
|
|
|
},
|
|
|
|
_STD uses_allocator_construction_args<_Ty>(_Al, _STD forward<_Types>(_Args)...));
|
|
|
|
}
|
|
|
|
#endif // _HAS_CXX20
|
2019-09-05 01:57:56 +03:00
|
|
|
_STD_END
|
|
|
|
|
|
|
|
#pragma pop_macro("new")
|
|
|
|
_STL_RESTORE_CLANG_WARNINGS
|
|
|
|
#pragma warning(pop)
|
|
|
|
#pragma pack(pop)
|
|
|
|
#endif // _STL_COMPILER_PREPROCESSOR
|
|
|
|
#endif // _XMEMORY_
|