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 #ifndef ALLOCATORS_H
10 #define ALLOCATORS_H
11 
12 #include <type_traits>
13 #include <utility>
14 
15 #include "test_macros.h"
16 
17 #if TEST_STD_VER >= 11
18 
19 template <class T>
20 class A1
21 {
22     int id_;
23 public:
24     explicit A1(int id = 0) TEST_NOEXCEPT : id_(id) {}
25 
26     typedef T value_type;
27 
28     int id() const {return id_;}
29 
30     static bool copy_called;
31     static bool move_called;
32     static bool allocate_called;
33     static std::pair<T*, std::size_t> deallocate_called;
34 
35     A1(const A1& a) TEST_NOEXCEPT : id_(a.id()) {copy_called = true;}
36     A1(A1&& a)      TEST_NOEXCEPT : id_(a.id()) {move_called = true;}
37     A1& operator=(const A1& a) TEST_NOEXCEPT { id_ = a.id(); copy_called = true; return *this;}
38     A1& operator=(A1&& a)      TEST_NOEXCEPT { id_ = a.id(); move_called = true; return *this;}
39 
40     template <class U>
41         A1(const A1<U>& a) TEST_NOEXCEPT : id_(a.id()) {copy_called = true;}
42     template <class U>
43         A1(A1<U>&& a) TEST_NOEXCEPT : id_(a.id()) {move_called = true;}
44 
45     T* allocate(std::size_t n)
46     {
47         allocate_called = true;
48         return (T*)n;
49     }
50 
51     void deallocate(T* p, std::size_t n)
52     {
53         deallocate_called = std::pair<T*, std::size_t>(p, n);
54     }
55 
56     std::size_t max_size() const {return id_;}
57 };
58 
59 template <class T> bool A1<T>::copy_called = false;
60 template <class T> bool A1<T>::move_called = false;
61 template <class T> bool A1<T>::allocate_called = false;
62 template <class T> std::pair<T*, std::size_t> A1<T>::deallocate_called;
63 
64 template <class T, class U>
65 inline
66 bool operator==(const A1<T>& x, const A1<U>& y)
67 {
68     return x.id() == y.id();
69 }
70 
71 template <class T, class U>
72 inline
73 bool operator!=(const A1<T>& x, const A1<U>& y)
74 {
75     return !(x == y);
76 }
77 
78 template <class T>
79 class A2
80 {
81     int id_;
82 public:
83     explicit A2(int id = 0) TEST_NOEXCEPT : id_(id) {}
84 
85     typedef T value_type;
86 
87     typedef unsigned size_type;
88     typedef int difference_type;
89 
90     typedef std::true_type propagate_on_container_move_assignment;
91 
92     int id() const {return id_;}
93 
94     static bool copy_called;
95     static bool move_called;
96     static bool allocate_called;
97 
98     A2(const A2& a) TEST_NOEXCEPT : id_(a.id()) {copy_called = true;}
99     A2(A2&& a)      TEST_NOEXCEPT : id_(a.id()) {move_called = true;}
100     A2& operator=(const A2& a) TEST_NOEXCEPT { id_ = a.id(); copy_called = true; return *this;}
101     A2& operator=(A2&& a)      TEST_NOEXCEPT { id_ = a.id(); move_called = true; return *this;}
102 
103     T* allocate(std::size_t, const void* hint)
104     {
105         allocate_called = true;
106         return (T*) const_cast<void *>(hint);
107     }
108 };
109 
110 template <class T> bool A2<T>::copy_called = false;
111 template <class T> bool A2<T>::move_called = false;
112 template <class T> bool A2<T>::allocate_called = false;
113 
114 template <class T, class U>
115 inline
116 bool operator==(const A2<T>& x, const A2<U>& y)
117 {
118     return x.id() == y.id();
119 }
120 
121 template <class T, class U>
122 inline
123 bool operator!=(const A2<T>& x, const A2<U>& y)
124 {
125     return !(x == y);
126 }
127 
128 template <class T>
129 class A3
130 {
131     int id_;
132 public:
133     explicit A3(int id = 0) TEST_NOEXCEPT : id_(id) {}
134 
135     typedef T value_type;
136 
137     typedef std::true_type propagate_on_container_copy_assignment;
138     typedef std::true_type propagate_on_container_swap;
139 
140     int id() const {return id_;}
141 
142     static bool copy_called;
143     static bool move_called;
144     static bool constructed;
145     static bool destroy_called;
146 
147     A3(const A3& a) TEST_NOEXCEPT : id_(a.id()) {copy_called = true;}
148     A3(A3&& a)      TEST_NOEXCEPT : id_(a.id())  {move_called = true;}
149     A3& operator=(const A3& a) TEST_NOEXCEPT { id_ = a.id(); copy_called = true; return *this;}
150     A3& operator=(A3&& a)      TEST_NOEXCEPT { id_ = a.id(); move_called = true; return *this;}
151 
152     template <class U, class ...Args>
153     void construct(U* p, Args&& ...args)
154     {
155         ::new (p) U(std::forward<Args>(args)...);
156         constructed = true;
157     }
158 
159     template <class U>
160     void destroy(U* p)
161     {
162         p->~U();
163         destroy_called = true;
164     }
165 
166     A3 select_on_container_copy_construction() const {return A3(-1);}
167 };
168 
169 template <class T> bool A3<T>::copy_called = false;
170 template <class T> bool A3<T>::move_called = false;
171 template <class T> bool A3<T>::constructed = false;
172 template <class T> bool A3<T>::destroy_called = false;
173 
174 template <class T, class U>
175 inline
176 bool operator==(const A3<T>& x, const A3<U>& y)
177 {
178     return x.id() == y.id();
179 }
180 
181 template <class T, class U>
182 inline
183 bool operator!=(const A3<T>& x, const A3<U>& y)
184 {
185     return !(x == y);
186 }
187 
188 template <class T, bool POCCAValue>
189 class MaybePOCCAAllocator {
190     int id_ = 0;
191     bool* copy_assigned_into_ = nullptr;
192 public:
193     typedef std::integral_constant<bool, POCCAValue> propagate_on_container_copy_assignment;
194     typedef T value_type;
195 
196     MaybePOCCAAllocator() = default;
197     MaybePOCCAAllocator(int id, bool* copy_assigned_into)
198         : id_(id), copy_assigned_into_(copy_assigned_into) {}
199 
200     MaybePOCCAAllocator(const MaybePOCCAAllocator&) = default;
201     MaybePOCCAAllocator& operator=(const MaybePOCCAAllocator& a)
202     {
203         id_ = a.id();
204         if (copy_assigned_into_)
205             *copy_assigned_into_ = true;
206         return *this;
207     }
208 
209     T* allocate(std::size_t n)
210     {
211         return static_cast<T*>(::operator new(n * sizeof(T)));
212     }
213 
214     void deallocate(T* ptr, std::size_t)
215     {
216         ::operator delete(ptr);
217     }
218 
219     int id() const { return id_; }
220 
221     friend bool operator==(const MaybePOCCAAllocator& lhs, const MaybePOCCAAllocator& rhs)
222     {
223         return lhs.id() == rhs.id();
224     }
225 
226     friend bool operator!=(const MaybePOCCAAllocator& lhs, const MaybePOCCAAllocator& rhs)
227     {
228         return !(lhs == rhs);
229     }
230 };
231 
232 template <class T>
233 using POCCAAllocator = MaybePOCCAAllocator<T, /*POCCAValue = */true>;
234 template <class T>
235 using NonPOCCAAllocator = MaybePOCCAAllocator<T, /*POCCAValue = */false>;
236 
237 #endif // TEST_STD_VER >= 11
238 
239 #endif // ALLOCATORS_H
240