diff --git a/stl/inc/xpolymorphic_allocator.h b/stl/inc/xpolymorphic_allocator.h index 63bece9c8..d34da64fe 100644 --- a/stl/inc/xpolymorphic_allocator.h +++ b/stl/inc/xpolymorphic_allocator.h @@ -186,7 +186,11 @@ namespace pmr { } // CLASS TEMPLATE polymorphic_allocator +#if _HAS_CXX20 && defined(__cpp_lib_byte) + template +#else template +#endif // _HAS_CXX20 && defined(__cpp_lib_byte) class polymorphic_allocator { public: template @@ -222,6 +226,47 @@ namespace pmr { _Resource->deallocate(_Ptr, _Count * sizeof(_Ty), alignof(_Ty)); } +#if _HAS_CXX20 + _NODISCARD __declspec(allocator) void* allocate_bytes( + const size_t _Bytes, const size_t _Align = alignof(max_align_t)) { + return _Resource->allocate(_Bytes, _Align); + } + + void deallocate_bytes(void* const _Ptr, const size_t _Bytes, + const size_t _Align = alignof(max_align_t)) noexcept /* strengthened */ { + _Resource->deallocate(_Ptr, _Bytes, _Align); + } + + template + _NODISCARD __declspec(allocator) _Uty* allocate_object(_CRT_GUARDOVERFLOW const size_t _Count = 1) { + void* const _Vp = allocate_bytes(_Get_size_of_n(_Count), alignof(_Uty)); + return static_cast<_Uty*>(_Vp); + } + + template + void deallocate_object(_Uty* const _Ptr, const size_t _Count = 1) noexcept /* strengthened */ { + deallocate_bytes(_Ptr, _Count * sizeof(_Uty), alignof(_Uty)); + } + + template + _NODISCARD __declspec(allocator) _Uty* new_object(_Types&&... _Args) { + _Uty* const _Ptr = allocate_object<_Uty>(); + _TRY_BEGIN + construct(_Ptr, _STD forward<_Types>(_Args)...); + _CATCH_ALL + deallocate_object(_Ptr); + _RERAISE; + _CATCH_END + return _Ptr; + } + + template + void delete_object(_Uty* const _Ptr) noexcept /* strengthened */ { + _Destroy_in_place(*_Ptr); + deallocate_object(_Ptr); + } +#endif // _HAS_CXX20 + template void construct(_Uty* const _Ptr, _Types&&... _Args) { // propagate allocator *this if uses_allocator_v<_Uty, polymorphic_allocator> diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 123e4a46d..1745cf5a0 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -137,6 +137,7 @@ // P0202R3 constexpr For And exchange() // P0318R1 unwrap_reference, unwrap_ref_decay // P0325R4 to_array() +// P0339R6 polymorphic_allocator<> // P0356R5 bind_front() // P0357R3 Supporting Incomplete Types In reference_wrapper // P0415R1 constexpr For (Again) @@ -1203,6 +1204,7 @@ #define __cpp_lib_latch 201907L #define __cpp_lib_list_remove_return_type 201806L #define __cpp_lib_math_constants 201907L +#define __cpp_lib_polymorphic_allocator 201902L #define __cpp_lib_remove_cvref 201711L #define __cpp_lib_semaphore 201907L #define __cpp_lib_shift 201806L diff --git a/tests/std/test.lst b/tests/std/test.lst index 3f2fc7c9e..84533ac11 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -218,6 +218,7 @@ tests\P0220R1_sample tests\P0220R1_searchers tests\P0220R1_string_view tests\P0325R4_to_array +tests\P0339R6_polymorphic_allocator tests\P0356R5_bind_front tests\P0357R3_supporting_incomplete_types_in_reference_wrapper tests\P0414R2_shared_ptr_for_arrays diff --git a/tests/std/tests/P0339R6_polymorphic_allocator/env.lst b/tests/std/tests/P0339R6_polymorphic_allocator/env.lst new file mode 100644 index 000000000..642f530ff --- /dev/null +++ b/tests/std/tests/P0339R6_polymorphic_allocator/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_latest_matrix.lst diff --git a/tests/std/tests/P0339R6_polymorphic_allocator/test.cpp b/tests/std/tests/P0339R6_polymorphic_allocator/test.cpp new file mode 100644 index 000000000..374ec7d0b --- /dev/null +++ b/tests/std/tests/P0339R6_polymorphic_allocator/test.cpp @@ -0,0 +1,106 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include + +using std::pmr::polymorphic_allocator; + +void allocate_bytes_test() { + constexpr int N = 5; + + polymorphic_allocator<> alloc{}; + + void* vp = alloc.allocate_bytes(sizeof(int) * N, alignof(int)); + + int* arr = static_cast(vp); + + for (int i = 0; i < N; ++i) { + alloc.construct(arr + i, i); + } + + for (int i = 0; i < N; ++i) { + assert(arr[i] == i); + } + + std::destroy(arr, arr + N); + + alloc.deallocate_bytes(vp, sizeof(int) * N, alignof(int)); + + void* vp2 = alloc.allocate_bytes(sizeof(int)); + assert(reinterpret_cast(vp2) % alignof(std::max_align_t) == 0); + alloc.deallocate_bytes(vp2, sizeof(int)); +} + +void allocate_object_test() { + constexpr int N = 10; + + polymorphic_allocator<> alloc{}; + + int* arr = alloc.allocate_object(N); + + for (int i = 0; i < N; ++i) { + alloc.construct(arr + i, i); + } + + for (int i = 0; i < N; ++i) { + assert(arr[i] == i); + } + + std::destroy(arr, arr + N); + + alloc.deallocate_object(arr, N); + + // N = 1 + int* p = alloc.allocate_object(); + alloc.construct(p, 20); + assert(*p == 20); + std::destroy_at(p); + alloc.deallocate_object(p); +} + +void allocate_object_overflow_test() { + constexpr auto threshold = std::numeric_limits::max() / sizeof(int); + + polymorphic_allocator<> alloc{}; + + try { + int* vp = alloc.allocate_object(threshold); + alloc.deallocate_object(vp, threshold); + } catch (const std::bad_alloc&) { + } catch (...) { + assert(false); + } + + try { + [[maybe_unused]] int* vp = alloc.allocate_object(threshold + 1); + } catch (const std::bad_array_new_length&) { + return; + } catch (...) { + assert(false); + } + assert(false); +} + +void new_object_test() { + polymorphic_allocator<> alloc{}; + + int* p = alloc.new_object(20); + + assert(*p == 20); + + alloc.delete_object(p); +} + + +int main() { + allocate_bytes_test(); + allocate_object_test(); + allocate_object_overflow_test(); + new_object_test(); +} diff --git a/tests/std/tests/VSO_0157762_feature_test_macros/test.cpp b/tests/std/tests/VSO_0157762_feature_test_macros/test.cpp index e81dd2968..153a5e821 100644 --- a/tests/std/tests/VSO_0157762_feature_test_macros/test.cpp +++ b/tests/std/tests/VSO_0157762_feature_test_macros/test.cpp @@ -1092,6 +1092,20 @@ STATIC_ASSERT(__cpp_lib_parallel_algorithm == 201603L); #endif #endif +#if _HAS_CXX20 +#ifndef __cpp_lib_polymorphic_allocator +#error __cpp_lib_polymorphic_allocator is not defined +#elif __cpp_lib_polymorphic_allocator != 201902L +#error __cpp_lib_polymorphic_allocator is not 201902L +#else +STATIC_ASSERT(__cpp_lib_polymorphic_allocator == 201902L); +#endif +#else +#ifdef __cpp_lib_polymorphic_allocator +#error __cpp_lib_polymorphic_allocator is defined +#endif +#endif + #ifndef __cpp_lib_quoted_string_io #error __cpp_lib_quoted_string_io is not defined #elif __cpp_lib_quoted_string_io != 201304L