diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -300,7 +300,7 @@ ------------------------------------------------------------------- ``__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* ------------------------------------------------- ----------------- diff --git a/libcxx/docs/Status/Cxx2bPapers.csv b/libcxx/docs/Status/Cxx2bPapers.csv --- a/libcxx/docs/Status/Cxx2bPapers.csv +++ b/libcxx/docs/Status/Cxx2bPapers.csv @@ -11,7 +11,7 @@ "`P2212R2 `__","LWG","Relax Requirements for time_point::clock","February 2021","","" "`P2259R1 `__","LWG","Repairing input range adaptors and counted_iterator","February 2021","","" "","","","","","" -"`P0401R6 `__","LWG","Providing size feedback in the Allocator interface","June 2021","","" +"`P0401R6 `__","LWG","Providing size feedback in the Allocator interface","June 2021","|Complete|","15.0" "`P0448R4 `__","LWG","A strstream replacement using span as buffer","June 2021","","" "`P1132R8 `__","LWG","out_ptr - a scalable output pointer abstraction","June 2021","","" "`P1328R1 `__","LWG","Making std::type_info::operator== constexpr","June 2021","","" diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -286,6 +286,7 @@ __locale __mbstate_t.h __memory/addressof.h + __memory/allocate_at_least.h __memory/allocation_guard.h __memory/allocator.h __memory/allocator_arg_t.h diff --git a/libcxx/include/__memory/allocate_at_least.h b/libcxx/include/__memory/allocate_at_least.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__memory/allocate_at_least.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 + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER > 20 +template +struct allocation_result { + _Pointer ptr; + size_t count; +}; + +template +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr +allocation_result::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 +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr +auto __allocate_at_least(_Alloc& __alloc, size_t __n) { + return std::allocate_at_least(__alloc, __n); +} +#else +template +struct __allocation_result { + _Pointer ptr; + size_t count; +}; + +template +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR +__allocation_result::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 diff --git a/libcxx/include/__memory/allocator.h b/libcxx/include/__memory/allocator.h --- a/libcxx/include/__memory/allocator.h +++ b/libcxx/include/__memory/allocator.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 @@ -106,6 +107,13 @@ } } +#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 @@ } } +#if _LIBCPP_STD_VER > 20 + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr + allocation_result 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()) { diff --git a/libcxx/include/__split_buffer b/libcxx/include/__split_buffer --- a/libcxx/include/__split_buffer +++ b/libcxx/include/__split_buffer @@ -319,7 +319,13 @@ __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 @@ } 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 _Ip; __construct_at_end(_Ip(__c.begin()), _Ip(__c.end())); } diff --git a/libcxx/include/memory b/libcxx/include/memory --- a/libcxx/include/memory +++ b/libcxx/include/memory @@ -98,6 +98,16 @@ static allocator_type select_on_container_copy_construction(const allocator_type& a); // constexpr in C++20 }; +template +struct allocation_result { + Pointer ptr; + size_t count; +}; // since C++23 + +template +[[nodiscard]] constexpr allocation_result::pointer> + allocate_at_least(Allocator& a, size_t n); // since C++23 + template <> class allocator // removed in C++20 { @@ -827,6 +837,7 @@ #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> diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -708,6 +708,7 @@ 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" } diff --git a/libcxx/include/string b/libcxx/include/string --- a/libcxx/include/string +++ b/libcxx/include/string @@ -528,6 +528,7 @@ #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 @@ 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 @@ } 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 @@ } 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 @@ } 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 @@ } 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 @@ } 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ } 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 (...) diff --git a/libcxx/include/vector b/libcxx/include/vector --- a/libcxx/include/vector +++ b/libcxx/include/vector @@ -287,6 +287,7 @@ #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 @@ _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 @@ 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 -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 void vector<_Tp, _Allocator>::__vdeallocate() _NOEXCEPT @@ -2329,8 +2330,23 @@ _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 @@ { } -// 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 -void -vector::__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 void vector::__vdeallocate() _NOEXCEPT diff --git a/libcxx/include/version b/libcxx/include/version --- a/libcxx/include/version +++ b/libcxx/include/version @@ -374,7 +374,7 @@ #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 diff --git a/libcxx/test/libcxx/private_headers.verify.cpp b/libcxx/test/libcxx/private_headers.verify.cpp --- a/libcxx/test/libcxx/private_headers.verify.cpp +++ b/libcxx/test/libcxx/private_headers.verify.cpp @@ -317,6 +317,7 @@ #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'}} diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.pass.cpp --- a/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.pass.cpp @@ -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 diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp --- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp @@ -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 diff --git a/libcxx/test/std/utilities/memory/allocator.traits/allocate_at_least.pass.cpp b/libcxx/test/std/utilities/memory/allocator.traits/allocate_at_least.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/memory/allocator.traits/allocate_at_least.pass.cpp @@ -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 + +// + +// template +// [[nodiscard]] constexpr allocation_result::pointer> +// allocate_at_least(Allocator& a, size_t n); + +#include +#include + +// check that std::allocation_result exists and isn't restricted to pointers +using AllocResult = std::allocation_result; + +template +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 +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 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 alloc; + std::same_as> 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 alloc; + std::same_as> 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()); +} diff --git a/libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate_at_least.pass.cpp b/libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate_at_least.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate_at_least.pass.cpp @@ -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 + +// + +// allocation_result allocate_at_least(size_t n) + +#include +#include + +#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::value; +#endif + +static const size_t OverAligned = MaxAligned * 2; + +template +struct alignas(Align) AlignedType { + char data; + static int constructed; + AlignedType() { ++constructed; } + AlignedType(AlignedType const&) { ++constructed; } + ~AlignedType() { --constructed; } +}; +template +int AlignedType::constructed = 0; + + +template +void test_aligned() { + typedef AlignedType T; + T::constructed = 0; + globalMemCounter.reset(); + std::allocator 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> 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 +constexpr bool test_aligned_constexpr() { + typedef AlignedType T; + std::allocator a; + std::same_as> 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(); + test_aligned(); + test_aligned(); + + 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()); + static_assert(test_aligned_constexpr()); + static_assert(test_aligned_constexpr()); + return 0; +} diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -74,7 +74,6 @@ "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 },