1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 // UNSUPPORTED: c++03, c++11, c++14
10 // TODO: Change to XFAIL once https://github.com/llvm/llvm-project/issues/40340 is fixed
11 // UNSUPPORTED: availability-pmr-missing
12 
13 // test_memory_resource requires RTTI for dynamic_cast
14 // UNSUPPORTED: no-rtti
15 
16 // <memory_resource>
17 
18 // template <class T> class polymorphic_allocator
19 
20 // T* polymorphic_allocator<T>::allocate(size_t n)
21 
22 #include <memory_resource>
23 #include <cassert>
24 #include <exception>
25 #include <limits>
26 #include <memory>
27 #include <type_traits>
28 
29 #include "test_macros.h"
30 #include "test_std_memory_resource.h"
31 
32 template <std::size_t S, size_t Align>
testForSizeAndAlign()33 void testForSizeAndAlign() {
34   struct T {
35     alignas(Align) std::byte buf[S];
36   };
37 
38   TestResource R;
39   std::pmr::polymorphic_allocator<T> a(&R);
40 
41   for (int N = 1; N <= 5; ++N) {
42     auto ret = a.allocate(N);
43     assert(R.checkAlloc(ret, N * sizeof(T), alignof(T)));
44 
45     a.deallocate(ret, N);
46     R.reset();
47   }
48 }
49 
50 #ifndef TEST_HAS_NO_EXCEPTIONS
51 template <std::size_t S>
testAllocForSizeThrows()52 void testAllocForSizeThrows() {
53   struct T {
54     std::byte buf[S];
55   };
56 
57   using Alloc  = std::pmr::polymorphic_allocator<T>;
58   using Traits = std::allocator_traits<Alloc>;
59   NullResource R;
60   Alloc a(&R);
61 
62   // Test that allocating exactly the max size does not throw.
63   std::size_t maxSize = Traits::max_size(a);
64   std::size_t sizeTypeMax = std::numeric_limits<std::size_t>::max();
65   if (maxSize != sizeTypeMax) {
66     // Test that allocating size_t(~0) throws bad alloc.
67     try {
68       (void)a.allocate(sizeTypeMax);
69       assert(false);
70     } catch (const std::exception&) {
71     }
72 
73     // Test that allocating even one more than the max size does throw.
74     std::size_t overSize = maxSize + 1;
75     try {
76       (void)a.allocate(overSize);
77       assert(false);
78     } catch (const std::exception&) {
79     }
80   }
81 }
82 #endif // TEST_HAS_NO_EXCEPTIONS
83 
main(int,char **)84 int main(int, char**) {
85   {
86     std::pmr::polymorphic_allocator<int> a;
87     ASSERT_SAME_TYPE(decltype(a.allocate(0)), int*);
88     static_assert(!noexcept(a.allocate(0)), "");
89   }
90   {
91     constexpr std::size_t MA = alignof(std::max_align_t);
92     testForSizeAndAlign<1, 1>();
93     testForSizeAndAlign<1, 2>();
94     testForSizeAndAlign<1, MA>();
95     testForSizeAndAlign<2, 2>();
96     testForSizeAndAlign<73, alignof(void*)>();
97     testForSizeAndAlign<73, MA>();
98     testForSizeAndAlign<13, MA>();
99   }
100 #ifndef TEST_HAS_NO_EXCEPTIONS
101   {
102     testAllocForSizeThrows<1>();
103     testAllocForSizeThrows<2>();
104     testAllocForSizeThrows<4>();
105     testAllocForSizeThrows<8>();
106     testAllocForSizeThrows<16>();
107     testAllocForSizeThrows<73>();
108     testAllocForSizeThrows<13>();
109   }
110 #endif
111 
112   return 0;
113 }
114