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