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 // <memory>
10
11 // template <class Alloc>
12 // struct allocator_traits
13 // {
14 // template <class Ptr>
15 // static constexpr void destroy(allocator_type& a, Ptr p);
16 // ...
17 // };
18
19 #include <memory>
20 #include <cassert>
21 #include <cstddef>
22
23 #include "test_macros.h"
24 #include "incomplete_type_helper.h"
25
26 template <class T>
27 struct NoDestroy
28 {
29 typedef T value_type;
30
allocateNoDestroy31 TEST_CONSTEXPR_CXX20 T* allocate(std::size_t n)
32 {
33 return std::allocator<T>().allocate(n);
34 }
35
deallocateNoDestroy36 TEST_CONSTEXPR_CXX20 void deallocate(T* p, std::size_t n)
37 {
38 return std::allocator<T>().deallocate(p, n);
39 }
40 };
41
42 template <class T>
43 struct CountDestroy
44 {
CountDestroyCountDestroy45 TEST_CONSTEXPR explicit CountDestroy(int* counter)
46 : counter_(counter)
47 { }
48
49 typedef T value_type;
50
allocateCountDestroy51 TEST_CONSTEXPR_CXX20 T* allocate(std::size_t n)
52 {
53 return std::allocator<T>().allocate(n);
54 }
55
deallocateCountDestroy56 TEST_CONSTEXPR_CXX20 void deallocate(T* p, std::size_t n)
57 {
58 return std::allocator<T>().deallocate(p, n);
59 }
60
61 template <class U>
destroyCountDestroy62 TEST_CONSTEXPR_CXX20 void destroy(U* p)
63 {
64 ++*counter_;
65 p->~U();
66 }
67
68 int* counter_;
69 };
70
71 struct CountDestructor
72 {
CountDestructorCountDestructor73 TEST_CONSTEXPR explicit CountDestructor(int* counter)
74 : counter_(counter)
75 { }
76
~CountDestructorCountDestructor77 TEST_CONSTEXPR_CXX20 ~CountDestructor() { ++*counter_; }
78
79 int* counter_;
80 };
81
test()82 TEST_CONSTEXPR_CXX20 bool test()
83 {
84 {
85 typedef NoDestroy<CountDestructor> Alloc;
86 int destructors = 0;
87 Alloc alloc;
88 CountDestructor* pool = std::allocator_traits<Alloc>::allocate(alloc, 1);
89
90 std::allocator_traits<Alloc>::construct(alloc, pool, &destructors);
91 assert(destructors == 0);
92
93 std::allocator_traits<Alloc>::destroy(alloc, pool);
94 assert(destructors == 1);
95
96 std::allocator_traits<Alloc>::deallocate(alloc, pool, 1);
97 }
98 {
99 typedef IncompleteHolder* T;
100 typedef NoDestroy<T> Alloc;
101 Alloc alloc;
102 T* pool = std::allocator_traits<Alloc>::allocate(alloc, 1);
103 std::allocator_traits<Alloc>::construct(alloc, pool, nullptr);
104 std::allocator_traits<Alloc>::destroy(alloc, pool);
105 std::allocator_traits<Alloc>::deallocate(alloc, pool, 1);
106 }
107 {
108 typedef CountDestroy<CountDestructor> Alloc;
109 int destroys_called = 0;
110 int destructors_called = 0;
111 Alloc alloc(&destroys_called);
112
113 CountDestructor* pool = std::allocator_traits<Alloc>::allocate(alloc, 1);
114 std::allocator_traits<Alloc>::construct(alloc, pool, &destructors_called);
115 assert(destroys_called == 0);
116 assert(destructors_called == 0);
117
118 std::allocator_traits<Alloc>::destroy(alloc, pool);
119 assert(destroys_called == 1);
120 assert(destructors_called == 1);
121
122 std::allocator_traits<Alloc>::deallocate(alloc, pool, 1);
123 }
124 return true;
125 }
126
main(int,char **)127 int main(int, char**)
128 {
129 test();
130 #if TEST_STD_VER > 17
131 static_assert(test());
132 #endif
133 return 0;
134 }
135