forked from OSchip/llvm-project
[libc++] Implement P0401R6 (allocate_at_least)
Reviewed By: ldionne, var-const, #libc Spies: mgorny, libcxx-commits, arichardson Differential Revision: https://reviews.llvm.org/D122877
This commit is contained in:
parent
97ee923248
commit
a96443edde
|
@ -300,7 +300,7 @@ Status
|
|||
-------------------------------------------------------------------
|
||||
``__cpp_lib_adaptor_iterator_pair_constructor`` ``202106L``
|
||||
------------------------------------------------- -----------------
|
||||
``__cpp_lib_allocate_at_least`` *unimplemented*
|
||||
``__cpp_lib_allocate_at_least`` ``202106L``
|
||||
------------------------------------------------- -----------------
|
||||
``__cpp_lib_associative_heterogeneous_erasure`` *unimplemented*
|
||||
------------------------------------------------- -----------------
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
"`P2212R2 <https://wg21.link/P2212R2>`__","LWG","Relax Requirements for time_point::clock","February 2021","",""
|
||||
"`P2259R1 <https://wg21.link/P2259R1>`__","LWG","Repairing input range adaptors and counted_iterator","February 2021","",""
|
||||
"","","","","",""
|
||||
"`P0401R6 <https://wg21.link/P0401R6>`__","LWG","Providing size feedback in the Allocator interface","June 2021","",""
|
||||
"`P0401R6 <https://wg21.link/P0401R6>`__","LWG","Providing size feedback in the Allocator interface","June 2021","|Complete|","15.0"
|
||||
"`P0448R4 <https://wg21.link/P0448R4>`__","LWG","A strstream replacement using span<charT> as buffer","June 2021","",""
|
||||
"`P1132R8 <https://wg21.link/P1132R8>`__","LWG","out_ptr - a scalable output pointer abstraction","June 2021","",""
|
||||
"`P1328R1 <https://wg21.link/P1328R1>`__","LWG","Making std::type_info::operator== constexpr","June 2021","",""
|
||||
|
|
|
|
@ -286,6 +286,7 @@ set(files
|
|||
__locale
|
||||
__mbstate_t.h
|
||||
__memory/addressof.h
|
||||
__memory/allocate_at_least.h
|
||||
__memory/allocation_guard.h
|
||||
__memory/allocator.h
|
||||
__memory/allocator_arg_t.h
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef _LIBCPP___MEMORY_ALLOCATE_AT_LEAST_H
|
||||
#define _LIBCPP___MEMORY_ALLOCATE_AT_LEAST_H
|
||||
|
||||
#include <__config>
|
||||
#include <__memory/allocator_traits.h>
|
||||
#include <cstddef>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
#endif
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
#if _LIBCPP_STD_VER > 20
|
||||
template <class _Pointer>
|
||||
struct allocation_result {
|
||||
_Pointer ptr;
|
||||
size_t count;
|
||||
};
|
||||
|
||||
template <class _Alloc>
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr
|
||||
allocation_result<typename allocator_traits<_Alloc>::pointer> allocate_at_least(_Alloc& __alloc, size_t __n) {
|
||||
if constexpr (requires { __alloc.allocate_at_least(__n); }) {
|
||||
return __alloc.allocate_at_least(__n);
|
||||
} else {
|
||||
return {__alloc.allocate(__n), __n};
|
||||
}
|
||||
}
|
||||
|
||||
template <class _Alloc>
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr
|
||||
auto __allocate_at_least(_Alloc& __alloc, size_t __n) {
|
||||
return std::allocate_at_least(__alloc, __n);
|
||||
}
|
||||
#else
|
||||
template <class _Pointer>
|
||||
struct __allocation_result {
|
||||
_Pointer ptr;
|
||||
size_t count;
|
||||
};
|
||||
|
||||
template <class _Alloc>
|
||||
_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR
|
||||
__allocation_result<typename allocator_traits<_Alloc>::pointer> __allocate_at_least(_Alloc& __alloc, size_t __n) {
|
||||
return {__alloc.allocate(__n), __n};
|
||||
}
|
||||
|
||||
#endif // _LIBCPP_STD_VER > 20
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP___MEMORY_ALLOCATE_AT_LEAST_H
|
|
@ -11,6 +11,7 @@
|
|||
#define _LIBCPP___MEMORY_ALLOCATOR_H
|
||||
|
||||
#include <__config>
|
||||
#include <__memory/allocate_at_least.h>
|
||||
#include <__memory/allocator_traits.h>
|
||||
#include <__utility/forward.h>
|
||||
#include <cstddef>
|
||||
|
@ -106,6 +107,13 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
#if _LIBCPP_STD_VER > 20
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr
|
||||
allocation_result<_Tp*> allocate_at_least(size_t __n) {
|
||||
return {allocate(__n), __n};
|
||||
}
|
||||
#endif
|
||||
|
||||
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||
void deallocate(_Tp* __p, size_t __n) _NOEXCEPT {
|
||||
if (__libcpp_is_constant_evaluated()) {
|
||||
|
@ -188,6 +196,13 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
#if _LIBCPP_STD_VER > 20
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr
|
||||
allocation_result<const _Tp*> allocate_at_least(size_t __n) {
|
||||
return {allocate(__n), __n};
|
||||
}
|
||||
#endif
|
||||
|
||||
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||
void deallocate(const _Tp* __p, size_t __n) {
|
||||
if (__libcpp_is_constant_evaluated()) {
|
||||
|
|
|
@ -319,7 +319,13 @@ template <class _Tp, class _Allocator>
|
|||
__split_buffer<_Tp, _Allocator>::__split_buffer(size_type __cap, size_type __start, __alloc_rr& __a)
|
||||
: __end_cap_(nullptr, __a)
|
||||
{
|
||||
__first_ = __cap != 0 ? __alloc_traits::allocate(__alloc(), __cap) : nullptr;
|
||||
if (__cap == 0) {
|
||||
__first_ = nullptr;
|
||||
} else {
|
||||
auto __allocation = std::__allocate_at_least(__alloc(), __cap);
|
||||
__first_ = __allocation.ptr;
|
||||
__cap = __allocation.count;
|
||||
}
|
||||
__begin_ = __end_ = __first_ + __start;
|
||||
__end_cap() = __first_ + __cap;
|
||||
}
|
||||
|
@ -385,10 +391,10 @@ __split_buffer<_Tp, _Allocator>::__split_buffer(__split_buffer&& __c, const __al
|
|||
}
|
||||
else
|
||||
{
|
||||
size_type __cap = __c.size();
|
||||
__first_ = __alloc_traits::allocate(__alloc(), __cap);
|
||||
auto __allocation = std::__allocate_at_least(__alloc(), __c.size());
|
||||
__first_ = __allocation.ptr;
|
||||
__begin_ = __end_ = __first_;
|
||||
__end_cap() = __first_ + __cap;
|
||||
__end_cap() = __first_ + __allocation.count;
|
||||
typedef move_iterator<iterator> _Ip;
|
||||
__construct_at_end(_Ip(__c.begin()), _Ip(__c.end()));
|
||||
}
|
||||
|
|
|
@ -98,6 +98,16 @@ struct allocator_traits
|
|||
static allocator_type select_on_container_copy_construction(const allocator_type& a); // constexpr in C++20
|
||||
};
|
||||
|
||||
template<class Pointer>
|
||||
struct allocation_result {
|
||||
Pointer ptr;
|
||||
size_t count;
|
||||
}; // since C++23
|
||||
|
||||
template<class Allocator>
|
||||
[[nodiscard]] constexpr allocation_result<typename allocator_traits<Allocator>::pointer>
|
||||
allocate_at_least(Allocator& a, size_t n); // since C++23
|
||||
|
||||
template <>
|
||||
class allocator<void> // removed in C++20
|
||||
{
|
||||
|
@ -827,6 +837,7 @@ void* align(size_t alignment, size_t size, void*& ptr, size_t& space);
|
|||
#include <__assert> // all public C++ headers provide the assertion handler
|
||||
#include <__config>
|
||||
#include <__memory/addressof.h>
|
||||
#include <__memory/allocate_at_least.h>
|
||||
#include <__memory/allocation_guard.h>
|
||||
#include <__memory/allocator.h>
|
||||
#include <__memory/allocator_arg_t.h>
|
||||
|
|
|
@ -708,6 +708,7 @@ module std [system] {
|
|||
|
||||
module __memory {
|
||||
module addressof { private header "__memory/addressof.h" }
|
||||
module allocate_at_least { private header "__memory/allocate_at_least.h" }
|
||||
module allocation_guard { private header "__memory/allocation_guard.h" }
|
||||
module allocator { private header "__memory/allocator.h" }
|
||||
module allocator_arg_t { private header "__memory/allocator_arg_t.h" }
|
||||
|
|
|
@ -528,6 +528,7 @@ basic_string<char32_t> operator "" s( const char32_t *str, size_t len ); // C++1
|
|||
#include <__format/enable_insertable.h>
|
||||
#include <__ios/fpos.h>
|
||||
#include <__iterator/wrap_iter.h>
|
||||
#include <__memory/allocate_at_least.h>
|
||||
#include <__utility/auto_cast.h>
|
||||
#include <__utility/move.h>
|
||||
#include <__utility/swap.h>
|
||||
|
@ -1623,11 +1624,11 @@ private:
|
|||
else
|
||||
{
|
||||
allocator_type __a = __str.__alloc();
|
||||
pointer __p = __alloc_traits::allocate(__a, __str.__get_long_cap());
|
||||
auto __allocation = std::__allocate_at_least(__a, __str.__get_long_cap());
|
||||
__clear_and_shrink();
|
||||
__alloc() = _VSTD::move(__a);
|
||||
__set_long_pointer(__p);
|
||||
__set_long_cap(__str.__get_long_cap());
|
||||
__set_long_pointer(__allocation.ptr);
|
||||
__set_long_cap(__allocation.count);
|
||||
__set_long_size(__str.size());
|
||||
}
|
||||
}
|
||||
|
@ -1841,10 +1842,10 @@ void basic_string<_CharT, _Traits, _Allocator>::__init(const value_type* __s,
|
|||
}
|
||||
else
|
||||
{
|
||||
size_type __cap = __recommend(__reserve);
|
||||
__p = __alloc_traits::allocate(__alloc(), __cap+1);
|
||||
auto __allocation = std::__allocate_at_least(__alloc(), __recommend(__reserve) + 1);
|
||||
__p = __allocation.ptr;
|
||||
__set_long_pointer(__p);
|
||||
__set_long_cap(__cap+1);
|
||||
__set_long_cap(__allocation.count);
|
||||
__set_long_size(__sz);
|
||||
}
|
||||
traits_type::copy(_VSTD::__to_address(__p), __s, __sz);
|
||||
|
@ -1865,10 +1866,10 @@ basic_string<_CharT, _Traits, _Allocator>::__init(const value_type* __s, size_ty
|
|||
}
|
||||
else
|
||||
{
|
||||
size_type __cap = __recommend(__sz);
|
||||
__p = __alloc_traits::allocate(__alloc(), __cap+1);
|
||||
auto __allocation = std::__allocate_at_least(__alloc(), __recommend(__sz) + 1);
|
||||
__p = __allocation.ptr;
|
||||
__set_long_pointer(__p);
|
||||
__set_long_cap(__cap+1);
|
||||
__set_long_cap(__allocation.count);
|
||||
__set_long_size(__sz);
|
||||
}
|
||||
traits_type::copy(_VSTD::__to_address(__p), __s, __sz);
|
||||
|
@ -1940,10 +1941,10 @@ void basic_string<_CharT, _Traits, _Allocator>::__init_copy_ctor_external(
|
|||
} else {
|
||||
if (__sz > max_size())
|
||||
__throw_length_error();
|
||||
size_t __cap = __recommend(__sz);
|
||||
__p = __alloc_traits::allocate(__alloc(), __cap + 1);
|
||||
auto __allocation = std::__allocate_at_least(__alloc(), __recommend(__sz) + 1);
|
||||
__p = __allocation.ptr;
|
||||
__set_long_pointer(__p);
|
||||
__set_long_cap(__cap + 1);
|
||||
__set_long_cap(__allocation.count);
|
||||
__set_long_size(__sz);
|
||||
}
|
||||
traits_type::copy(_VSTD::__to_address(__p), __s, __sz + 1);
|
||||
|
@ -2004,10 +2005,10 @@ basic_string<_CharT, _Traits, _Allocator>::__init(size_type __n, value_type __c)
|
|||
}
|
||||
else
|
||||
{
|
||||
size_type __cap = __recommend(__n);
|
||||
__p = __alloc_traits::allocate(__alloc(), __cap+1);
|
||||
auto __allocation = std::__allocate_at_least(__alloc(), __recommend(__n) + 1);
|
||||
__p = __allocation.ptr;
|
||||
__set_long_pointer(__p);
|
||||
__set_long_cap(__cap+1);
|
||||
__set_long_cap(__allocation.count);
|
||||
__set_long_size(__n);
|
||||
}
|
||||
traits_type::assign(_VSTD::__to_address(__p), __n, __c);
|
||||
|
@ -2135,10 +2136,10 @@ basic_string<_CharT, _Traits, _Allocator>::__init(_ForwardIterator __first, _For
|
|||
}
|
||||
else
|
||||
{
|
||||
size_type __cap = __recommend(__sz);
|
||||
__p = __alloc_traits::allocate(__alloc(), __cap+1);
|
||||
auto __allocation = std::__allocate_at_least(__alloc(), __recommend(__sz) + 1);
|
||||
__p = __allocation.ptr;
|
||||
__set_long_pointer(__p);
|
||||
__set_long_cap(__cap+1);
|
||||
__set_long_cap(__allocation.count);
|
||||
__set_long_size(__sz);
|
||||
}
|
||||
|
||||
|
@ -2230,7 +2231,8 @@ basic_string<_CharT, _Traits, _Allocator>::__grow_by_and_replace
|
|||
size_type __cap = __old_cap < __ms / 2 - __alignment ?
|
||||
__recommend(_VSTD::max(__old_cap + __delta_cap, 2 * __old_cap)) :
|
||||
__ms - 1;
|
||||
pointer __p = __alloc_traits::allocate(__alloc(), __cap+1);
|
||||
auto __allocation = std::__allocate_at_least(__alloc(), __cap + 1);
|
||||
pointer __p = __allocation.ptr;
|
||||
__invalidate_all_iterators();
|
||||
if (__n_copy != 0)
|
||||
traits_type::copy(_VSTD::__to_address(__p),
|
||||
|
@ -2244,7 +2246,7 @@ basic_string<_CharT, _Traits, _Allocator>::__grow_by_and_replace
|
|||
if (__old_cap+1 != __min_cap)
|
||||
__alloc_traits::deallocate(__alloc(), __old_p, __old_cap+1);
|
||||
__set_long_pointer(__p);
|
||||
__set_long_cap(__cap+1);
|
||||
__set_long_cap(__allocation.count);
|
||||
__old_sz = __n_copy + __n_add + __sec_cp_sz;
|
||||
__set_long_size(__old_sz);
|
||||
traits_type::assign(__p[__old_sz], value_type());
|
||||
|
@ -2262,7 +2264,8 @@ basic_string<_CharT, _Traits, _Allocator>::__grow_by(size_type __old_cap, size_t
|
|||
size_type __cap = __old_cap < __ms / 2 - __alignment ?
|
||||
__recommend(_VSTD::max(__old_cap + __delta_cap, 2 * __old_cap)) :
|
||||
__ms - 1;
|
||||
pointer __p = __alloc_traits::allocate(__alloc(), __cap+1);
|
||||
auto __allocation = std::__allocate_at_least(__alloc(), __cap + 1);
|
||||
pointer __p = __allocation.ptr;
|
||||
__invalidate_all_iterators();
|
||||
if (__n_copy != 0)
|
||||
traits_type::copy(_VSTD::__to_address(__p),
|
||||
|
@ -2275,7 +2278,7 @@ basic_string<_CharT, _Traits, _Allocator>::__grow_by(size_type __old_cap, size_t
|
|||
if (__old_cap+1 != __min_cap)
|
||||
__alloc_traits::deallocate(__alloc(), __old_p, __old_cap+1);
|
||||
__set_long_pointer(__p);
|
||||
__set_long_cap(__cap+1);
|
||||
__set_long_cap(__allocation.count);
|
||||
}
|
||||
|
||||
// assign
|
||||
|
@ -3257,15 +3260,20 @@ basic_string<_CharT, _Traits, _Allocator>::__shrink_or_extend(size_type __target
|
|||
}
|
||||
else
|
||||
{
|
||||
if (__target_capacity > __cap)
|
||||
__new_data = __alloc_traits::allocate(__alloc(), __target_capacity+1);
|
||||
if (__target_capacity > __cap) {
|
||||
auto __allocation = std::__allocate_at_least(__alloc(), __target_capacity + 1);
|
||||
__new_data = __allocation.ptr;
|
||||
__target_capacity = __allocation.count - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef _LIBCPP_NO_EXCEPTIONS
|
||||
try
|
||||
{
|
||||
#endif // _LIBCPP_NO_EXCEPTIONS
|
||||
__new_data = __alloc_traits::allocate(__alloc(), __target_capacity+1);
|
||||
auto __allocation = std::__allocate_at_least(__alloc(), __target_capacity + 1);
|
||||
__new_data = __allocation.ptr;
|
||||
__target_capacity = __allocation.count - 1;
|
||||
#ifndef _LIBCPP_NO_EXCEPTIONS
|
||||
}
|
||||
catch (...)
|
||||
|
|
|
@ -287,6 +287,7 @@ erase_if(vector<T, Allocator>& c, Predicate pred); // C++20
|
|||
#include <__functional/hash.h>
|
||||
#include <__iterator/iterator_traits.h>
|
||||
#include <__iterator/wrap_iter.h>
|
||||
#include <__memory/allocate_at_least.h>
|
||||
#include <__split_buffer>
|
||||
#include <__utility/forward.h>
|
||||
#include <__utility/move.h>
|
||||
|
@ -673,7 +674,25 @@ private:
|
|||
|
||||
_LIBCPP_INLINE_VISIBILITY void __invalidate_all_iterators();
|
||||
_LIBCPP_INLINE_VISIBILITY void __invalidate_iterators_past(pointer __new_last);
|
||||
void __vallocate(size_type __n);
|
||||
|
||||
|
||||
// Allocate space for __n objects
|
||||
// throws length_error if __n > max_size()
|
||||
// throws (probably bad_alloc) if memory run out
|
||||
// Precondition: __begin_ == __end_ == __end_cap() == 0
|
||||
// Precondition: __n > 0
|
||||
// Postcondition: capacity() >= __n
|
||||
// Postcondition: size() == 0
|
||||
_LIBCPP_HIDE_FROM_ABI void __vallocate(size_type __n) {
|
||||
if (__n > max_size())
|
||||
__throw_length_error();
|
||||
auto __allocation = std::__allocate_at_least(__alloc(), __n);
|
||||
__begin_ = __allocation.ptr;
|
||||
__end_ = __allocation.ptr;
|
||||
__end_cap() = __begin_ + __allocation.count;
|
||||
__annotate_new(0);
|
||||
}
|
||||
|
||||
void __vdeallocate() _NOEXCEPT;
|
||||
_LIBCPP_INLINE_VISIBILITY size_type __recommend(size_type __new_size) const;
|
||||
void __construct_at_end(size_type __n);
|
||||
|
@ -926,24 +945,6 @@ vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer<value_type, a
|
|||
return __r;
|
||||
}
|
||||
|
||||
// Allocate space for __n objects
|
||||
// throws length_error if __n > max_size()
|
||||
// throws (probably bad_alloc) if memory run out
|
||||
// Precondition: __begin_ == __end_ == __end_cap() == 0
|
||||
// Precondition: __n > 0
|
||||
// Postcondition: capacity() == __n
|
||||
// Postcondition: size() == 0
|
||||
template <class _Tp, class _Allocator>
|
||||
void
|
||||
vector<_Tp, _Allocator>::__vallocate(size_type __n)
|
||||
{
|
||||
if (__n > max_size())
|
||||
this->__throw_length_error();
|
||||
this->__begin_ = this->__end_ = __alloc_traits::allocate(this->__alloc(), __n);
|
||||
this->__end_cap() = this->__begin_ + __n;
|
||||
__annotate_new(0);
|
||||
}
|
||||
|
||||
template <class _Tp, class _Allocator>
|
||||
void
|
||||
vector<_Tp, _Allocator>::__vdeallocate() _NOEXCEPT
|
||||
|
@ -2329,8 +2330,23 @@ private:
|
|||
_VSTD::__throw_out_of_range("vector");
|
||||
}
|
||||
|
||||
// Allocate space for __n objects
|
||||
// throws length_error if __n > max_size()
|
||||
// throws (probably bad_alloc) if memory run out
|
||||
// Precondition: __begin_ == __end_ == __cap() == 0
|
||||
// Precondition: __n > 0
|
||||
// Postcondition: capacity() >= __n
|
||||
// Postcondition: size() == 0
|
||||
_LIBCPP_INLINE_VISIBILITY void __invalidate_all_iterators();
|
||||
void __vallocate(size_type __n);
|
||||
_LIBCPP_HIDE_FROM_ABI void __vallocate(size_type __n) {
|
||||
if (__n > max_size())
|
||||
__throw_length_error();
|
||||
auto __allocation = std::__allocate_at_least(__alloc(), __external_cap_to_internal(__n));
|
||||
__begin_ = __allocation.ptr;
|
||||
__size_ = 0;
|
||||
__cap() = __allocation.count;
|
||||
}
|
||||
|
||||
void __vdeallocate() _NOEXCEPT;
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
static size_type __align_it(size_type __new_size) _NOEXCEPT
|
||||
|
@ -2416,25 +2432,6 @@ vector<bool, _Allocator>::__invalidate_all_iterators()
|
|||
{
|
||||
}
|
||||
|
||||
// Allocate space for __n objects
|
||||
// throws length_error if __n > max_size()
|
||||
// throws (probably bad_alloc) if memory run out
|
||||
// Precondition: __begin_ == __end_ == __cap() == 0
|
||||
// Precondition: __n > 0
|
||||
// Postcondition: capacity() == __n
|
||||
// Postcondition: size() == 0
|
||||
template <class _Allocator>
|
||||
void
|
||||
vector<bool, _Allocator>::__vallocate(size_type __n)
|
||||
{
|
||||
if (__n > max_size())
|
||||
this->__throw_length_error();
|
||||
__n = __external_cap_to_internal(__n);
|
||||
this->__begin_ = __storage_traits::allocate(this->__alloc(), __n);
|
||||
this->__size_ = 0;
|
||||
this->__cap() = __n;
|
||||
}
|
||||
|
||||
template <class _Allocator>
|
||||
void
|
||||
vector<bool, _Allocator>::__vdeallocate() _NOEXCEPT
|
||||
|
|
|
@ -374,7 +374,7 @@ __cpp_lib_void_t 201411L <type_traits>
|
|||
|
||||
#if _LIBCPP_STD_VER > 20
|
||||
# define __cpp_lib_adaptor_iterator_pair_constructor 202106L
|
||||
// # define __cpp_lib_allocate_at_least 202106L
|
||||
# define __cpp_lib_allocate_at_least 202106L
|
||||
// # define __cpp_lib_associative_heterogeneous_erasure 202110L
|
||||
// # define __cpp_lib_bind_back 202202L
|
||||
# define __cpp_lib_byteswap 202110L
|
||||
|
|
|
@ -317,6 +317,7 @@ END-SCRIPT
|
|||
#include <__locale> // expected-error@*:* {{use of private header from outside its module: '__locale'}}
|
||||
#include <__mbstate_t.h> // expected-error@*:* {{use of private header from outside its module: '__mbstate_t.h'}}
|
||||
#include <__memory/addressof.h> // expected-error@*:* {{use of private header from outside its module: '__memory/addressof.h'}}
|
||||
#include <__memory/allocate_at_least.h> // expected-error@*:* {{use of private header from outside its module: '__memory/allocate_at_least.h'}}
|
||||
#include <__memory/allocation_guard.h> // expected-error@*:* {{use of private header from outside its module: '__memory/allocation_guard.h'}}
|
||||
#include <__memory/allocator.h> // expected-error@*:* {{use of private header from outside its module: '__memory/allocator.h'}}
|
||||
#include <__memory/allocator_arg_t.h> // expected-error@*:* {{use of private header from outside its module: '__memory/allocator_arg_t.h'}}
|
||||
|
|
|
@ -422,17 +422,11 @@
|
|||
# error "__cpp_lib_addressof_constexpr should have the value 201603L in c++2b"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_allocate_at_least
|
||||
# error "__cpp_lib_allocate_at_least should be defined in c++2b"
|
||||
# endif
|
||||
# if __cpp_lib_allocate_at_least != 202106L
|
||||
# error "__cpp_lib_allocate_at_least should have the value 202106L in c++2b"
|
||||
# endif
|
||||
# else // _LIBCPP_VERSION
|
||||
# ifdef __cpp_lib_allocate_at_least
|
||||
# error "__cpp_lib_allocate_at_least should not be defined because it is unimplemented in libc++!"
|
||||
# endif
|
||||
# ifndef __cpp_lib_allocate_at_least
|
||||
# error "__cpp_lib_allocate_at_least should be defined in c++2b"
|
||||
# endif
|
||||
# if __cpp_lib_allocate_at_least != 202106L
|
||||
# error "__cpp_lib_allocate_at_least should have the value 202106L in c++2b"
|
||||
# endif
|
||||
|
||||
# ifndef __cpp_lib_allocator_traits_is_always_equal
|
||||
|
|
|
@ -3614,17 +3614,11 @@
|
|||
# error "__cpp_lib_addressof_constexpr should have the value 201603L in c++2b"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_allocate_at_least
|
||||
# error "__cpp_lib_allocate_at_least should be defined in c++2b"
|
||||
# endif
|
||||
# if __cpp_lib_allocate_at_least != 202106L
|
||||
# error "__cpp_lib_allocate_at_least should have the value 202106L in c++2b"
|
||||
# endif
|
||||
# else // _LIBCPP_VERSION
|
||||
# ifdef __cpp_lib_allocate_at_least
|
||||
# error "__cpp_lib_allocate_at_least should not be defined because it is unimplemented in libc++!"
|
||||
# endif
|
||||
# ifndef __cpp_lib_allocate_at_least
|
||||
# error "__cpp_lib_allocate_at_least should be defined in c++2b"
|
||||
# endif
|
||||
# if __cpp_lib_allocate_at_least != 202106L
|
||||
# error "__cpp_lib_allocate_at_least should have the value 202106L in c++2b"
|
||||
# endif
|
||||
|
||||
# ifndef __cpp_lib_allocator_traits_is_always_equal
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
||||
|
||||
// <memory>
|
||||
|
||||
// template<class Allocator>
|
||||
// [[nodiscard]] constexpr allocation_result<typename allocator_traits<Allocator>::pointer>
|
||||
// allocate_at_least(Allocator& a, size_t n);
|
||||
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
|
||||
// check that std::allocation_result exists and isn't restricted to pointers
|
||||
using AllocResult = std::allocation_result<int>;
|
||||
|
||||
template <class T>
|
||||
struct no_allocate_at_least {
|
||||
using value_type = T;
|
||||
T t;
|
||||
|
||||
constexpr T* allocate(size_t) { return &t; }
|
||||
constexpr void deallocate(T*, size_t) {}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct has_allocate_at_least {
|
||||
using value_type = T;
|
||||
T t1;
|
||||
T t2;
|
||||
|
||||
constexpr T* allocate(size_t) { return &t1; }
|
||||
constexpr void deallocate(T*, size_t) {}
|
||||
constexpr std::allocation_result<T*> allocate_at_least(size_t) {
|
||||
return {&t2, 2};
|
||||
}
|
||||
};
|
||||
|
||||
constexpr bool test() {
|
||||
{ // check that std::allocate_at_least forwards to allocator::allocate if no allocate_at_least exists
|
||||
no_allocate_at_least<int> alloc;
|
||||
std::same_as<std::allocation_result<int*>> decltype(auto) ret = std::allocate_at_least(alloc, 1);
|
||||
assert(ret.count == 1);
|
||||
assert(ret.ptr == &alloc.t);
|
||||
}
|
||||
|
||||
{ // check that std::allocate_at_least forwards to allocator::allocate_at_least if allocate_at_least exists
|
||||
has_allocate_at_least<int> alloc;
|
||||
std::same_as<std::allocation_result<int*>> decltype(auto) ret = std::allocate_at_least(alloc, 1);
|
||||
assert(ret.count == 2);
|
||||
assert(ret.ptr == &alloc.t2);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main() {
|
||||
test();
|
||||
static_assert(test());
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
||||
|
||||
// <memory>
|
||||
|
||||
// allocation_result<T*> allocate_at_least(size_t n)
|
||||
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
|
||||
#include "count_new.h"
|
||||
|
||||
#ifdef TEST_HAS_NO_ALIGNED_ALLOCATION
|
||||
static const bool UsingAlignedNew = false;
|
||||
#else
|
||||
static const bool UsingAlignedNew = true;
|
||||
#endif
|
||||
|
||||
#ifdef __STDCPP_DEFAULT_NEW_ALIGNMENT__
|
||||
static const size_t MaxAligned = __STDCPP_DEFAULT_NEW_ALIGNMENT__;
|
||||
#else
|
||||
static const size_t MaxAligned = std::alignment_of<std::max_align_t>::value;
|
||||
#endif
|
||||
|
||||
static const size_t OverAligned = MaxAligned * 2;
|
||||
|
||||
template <size_t Align>
|
||||
struct alignas(Align) AlignedType {
|
||||
char data;
|
||||
static int constructed;
|
||||
AlignedType() { ++constructed; }
|
||||
AlignedType(AlignedType const&) { ++constructed; }
|
||||
~AlignedType() { --constructed; }
|
||||
};
|
||||
template <size_t Align>
|
||||
int AlignedType<Align>::constructed = 0;
|
||||
|
||||
|
||||
template <size_t Align>
|
||||
void test_aligned() {
|
||||
typedef AlignedType<Align> T;
|
||||
T::constructed = 0;
|
||||
globalMemCounter.reset();
|
||||
std::allocator<T> a;
|
||||
const bool IsOverAlignedType = Align > MaxAligned;
|
||||
const bool ExpectAligned = IsOverAlignedType && UsingAlignedNew;
|
||||
{
|
||||
assert(globalMemCounter.checkOutstandingNewEq(0));
|
||||
assert(T::constructed == 0);
|
||||
globalMemCounter.last_new_size = 0;
|
||||
globalMemCounter.last_new_align = 0;
|
||||
std::same_as<std::allocation_result<T*>> decltype(auto) ap = a.allocate_at_least(3);
|
||||
assert(ap.count >= 3);
|
||||
DoNotOptimize(ap);
|
||||
assert(globalMemCounter.checkOutstandingNewEq(1));
|
||||
assert(globalMemCounter.checkNewCalledEq(1));
|
||||
assert(globalMemCounter.checkAlignedNewCalledEq(ExpectAligned));
|
||||
assert(globalMemCounter.checkLastNewSizeEq(3 * sizeof(T)));
|
||||
assert(globalMemCounter.checkLastNewAlignEq(ExpectAligned ? Align : 0));
|
||||
assert(T::constructed == 0);
|
||||
globalMemCounter.last_delete_align = 0;
|
||||
a.deallocate(ap.ptr, 3);
|
||||
assert(globalMemCounter.checkOutstandingNewEq(0));
|
||||
assert(globalMemCounter.checkDeleteCalledEq(1));
|
||||
assert(globalMemCounter.checkAlignedDeleteCalledEq(ExpectAligned));
|
||||
assert(globalMemCounter.checkLastDeleteAlignEq(ExpectAligned ? Align : 0));
|
||||
assert(T::constructed == 0);
|
||||
}
|
||||
}
|
||||
|
||||
template <size_t Align>
|
||||
constexpr bool test_aligned_constexpr() {
|
||||
typedef AlignedType<Align> T;
|
||||
std::allocator<T> a;
|
||||
std::same_as<std::allocation_result<T*>> decltype(auto) ap = a.allocate_at_least(3);
|
||||
assert(ap.count >= 3);
|
||||
a.deallocate(ap.ptr, 3);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test_aligned<1>();
|
||||
test_aligned<2>();
|
||||
test_aligned<4>();
|
||||
test_aligned<8>();
|
||||
test_aligned<16>();
|
||||
test_aligned<MaxAligned>();
|
||||
test_aligned<OverAligned>();
|
||||
test_aligned<OverAligned * 2>();
|
||||
|
||||
static_assert(test_aligned_constexpr<1>());
|
||||
static_assert(test_aligned_constexpr<2>());
|
||||
static_assert(test_aligned_constexpr<4>());
|
||||
static_assert(test_aligned_constexpr<8>());
|
||||
static_assert(test_aligned_constexpr<16>());
|
||||
static_assert(test_aligned_constexpr<MaxAligned>());
|
||||
static_assert(test_aligned_constexpr<OverAligned>());
|
||||
static_assert(test_aligned_constexpr<OverAligned * 2>());
|
||||
return 0;
|
||||
}
|
|
@ -74,7 +74,6 @@ feature_test_macros = [ add_version_header(x) for x in [
|
|||
"name": "__cpp_lib_allocate_at_least",
|
||||
"values": { "c++2b": 202106 },
|
||||
"headers": ["memory"],
|
||||
"unimplemented": True,
|
||||
}, {
|
||||
"name": "__cpp_lib_allocator_traits_is_always_equal",
|
||||
"values": { "c++17": 201411 },
|
||||
|
|
Loading…
Reference in New Issue