1 | // -*- C++ -*- |
2 | //===----------------------------------------------------------------------===// |
3 | // |
4 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
5 | // See https://llvm.org/LICENSE.txt for license information. |
6 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
7 | // |
8 | //===----------------------------------------------------------------------===// |
9 | |
10 | #ifndef _LIBCPP___MEMORY_ALLOCATOR_TRAITS_H |
11 | #define _LIBCPP___MEMORY_ALLOCATOR_TRAITS_H |
12 | |
13 | #include <__config> |
14 | #include <__memory/construct_at.h> |
15 | #include <__memory/pointer_traits.h> |
16 | #include <__utility/forward.h> |
17 | #include <limits> |
18 | #include <type_traits> |
19 | |
20 | #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) |
21 | # pragma GCC system_header |
22 | #endif |
23 | |
24 | _LIBCPP_PUSH_MACROS |
25 | #include <__undef_macros> |
26 | |
27 | _LIBCPP_BEGIN_NAMESPACE_STD |
28 | |
29 | #define _LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(NAME, PROPERTY) \ |
30 | template <class _Tp, class = void> struct NAME : false_type { }; \ |
31 | template <class _Tp> struct NAME<_Tp, typename __void_t<typename _Tp:: PROPERTY >::type> : true_type { } |
32 | |
33 | // __pointer |
34 | _LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_pointer, pointer); |
35 | template <class _Tp, class _Alloc, |
36 | class _RawAlloc = typename remove_reference<_Alloc>::type, |
37 | bool = __has_pointer<_RawAlloc>::value> |
38 | struct __pointer { |
39 | using type _LIBCPP_NODEBUG = typename _RawAlloc::pointer; |
40 | }; |
41 | template <class _Tp, class _Alloc, class _RawAlloc> |
42 | struct __pointer<_Tp, _Alloc, _RawAlloc, false> { |
43 | using type _LIBCPP_NODEBUG = _Tp*; |
44 | }; |
45 | |
46 | // __const_pointer |
47 | _LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_const_pointer, const_pointer); |
48 | template <class _Tp, class _Ptr, class _Alloc, |
49 | bool = __has_const_pointer<_Alloc>::value> |
50 | struct __const_pointer { |
51 | using type _LIBCPP_NODEBUG = typename _Alloc::const_pointer; |
52 | }; |
53 | template <class _Tp, class _Ptr, class _Alloc> |
54 | struct __const_pointer<_Tp, _Ptr, _Alloc, false> { |
55 | #ifdef _LIBCPP_CXX03_LANG |
56 | using type = typename pointer_traits<_Ptr>::template rebind<const _Tp>::other; |
57 | #else |
58 | using type _LIBCPP_NODEBUG = typename pointer_traits<_Ptr>::template rebind<const _Tp>; |
59 | #endif |
60 | }; |
61 | |
62 | // __void_pointer |
63 | _LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_void_pointer, void_pointer); |
64 | template <class _Ptr, class _Alloc, |
65 | bool = __has_void_pointer<_Alloc>::value> |
66 | struct __void_pointer { |
67 | using type _LIBCPP_NODEBUG = typename _Alloc::void_pointer; |
68 | }; |
69 | template <class _Ptr, class _Alloc> |
70 | struct __void_pointer<_Ptr, _Alloc, false> { |
71 | #ifdef _LIBCPP_CXX03_LANG |
72 | using type _LIBCPP_NODEBUG = typename pointer_traits<_Ptr>::template rebind<void>::other; |
73 | #else |
74 | using type _LIBCPP_NODEBUG = typename pointer_traits<_Ptr>::template rebind<void>; |
75 | #endif |
76 | }; |
77 | |
78 | // __const_void_pointer |
79 | _LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_const_void_pointer, const_void_pointer); |
80 | template <class _Ptr, class _Alloc, |
81 | bool = __has_const_void_pointer<_Alloc>::value> |
82 | struct __const_void_pointer { |
83 | using type _LIBCPP_NODEBUG = typename _Alloc::const_void_pointer; |
84 | }; |
85 | template <class _Ptr, class _Alloc> |
86 | struct __const_void_pointer<_Ptr, _Alloc, false> { |
87 | #ifdef _LIBCPP_CXX03_LANG |
88 | using type _LIBCPP_NODEBUG = typename pointer_traits<_Ptr>::template rebind<const void>::other; |
89 | #else |
90 | using type _LIBCPP_NODEBUG = typename pointer_traits<_Ptr>::template rebind<const void>; |
91 | #endif |
92 | }; |
93 | |
94 | // __size_type |
95 | _LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_size_type, size_type); |
96 | template <class _Alloc, class _DiffType, bool = __has_size_type<_Alloc>::value> |
97 | struct __size_type : make_unsigned<_DiffType> { }; |
98 | template <class _Alloc, class _DiffType> |
99 | struct __size_type<_Alloc, _DiffType, true> { |
100 | using type _LIBCPP_NODEBUG = typename _Alloc::size_type; |
101 | }; |
102 | |
103 | // __alloc_traits_difference_type |
104 | _LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_alloc_traits_difference_type, difference_type); |
105 | template <class _Alloc, class _Ptr, bool = __has_alloc_traits_difference_type<_Alloc>::value> |
106 | struct __alloc_traits_difference_type { |
107 | using type _LIBCPP_NODEBUG = typename pointer_traits<_Ptr>::difference_type; |
108 | }; |
109 | template <class _Alloc, class _Ptr> |
110 | struct __alloc_traits_difference_type<_Alloc, _Ptr, true> { |
111 | using type _LIBCPP_NODEBUG = typename _Alloc::difference_type; |
112 | }; |
113 | |
114 | // __propagate_on_container_copy_assignment |
115 | _LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_propagate_on_container_copy_assignment, propagate_on_container_copy_assignment); |
116 | template <class _Alloc, bool = __has_propagate_on_container_copy_assignment<_Alloc>::value> |
117 | struct __propagate_on_container_copy_assignment : false_type { }; |
118 | template <class _Alloc> |
119 | struct __propagate_on_container_copy_assignment<_Alloc, true> { |
120 | using type _LIBCPP_NODEBUG = typename _Alloc::propagate_on_container_copy_assignment; |
121 | }; |
122 | |
123 | // __propagate_on_container_move_assignment |
124 | _LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_propagate_on_container_move_assignment, propagate_on_container_move_assignment); |
125 | template <class _Alloc, bool = __has_propagate_on_container_move_assignment<_Alloc>::value> |
126 | struct __propagate_on_container_move_assignment : false_type { }; |
127 | template <class _Alloc> |
128 | struct __propagate_on_container_move_assignment<_Alloc, true> { |
129 | using type _LIBCPP_NODEBUG = typename _Alloc::propagate_on_container_move_assignment; |
130 | }; |
131 | |
132 | // __propagate_on_container_swap |
133 | _LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_propagate_on_container_swap, propagate_on_container_swap); |
134 | template <class _Alloc, bool = __has_propagate_on_container_swap<_Alloc>::value> |
135 | struct __propagate_on_container_swap : false_type { }; |
136 | template <class _Alloc> |
137 | struct __propagate_on_container_swap<_Alloc, true> { |
138 | using type _LIBCPP_NODEBUG = typename _Alloc::propagate_on_container_swap; |
139 | }; |
140 | |
141 | // __is_always_equal |
142 | _LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_is_always_equal, is_always_equal); |
143 | template <class _Alloc, bool = __has_is_always_equal<_Alloc>::value> |
144 | struct __is_always_equal : is_empty<_Alloc> { }; |
145 | template <class _Alloc> |
146 | struct __is_always_equal<_Alloc, true> { |
147 | using type _LIBCPP_NODEBUG = typename _Alloc::is_always_equal; |
148 | }; |
149 | |
150 | // __allocator_traits_rebind |
151 | _LIBCPP_SUPPRESS_DEPRECATED_PUSH |
152 | template <class _Tp, class _Up, class = void> |
153 | struct __has_rebind_other : false_type { }; |
154 | template <class _Tp, class _Up> |
155 | struct __has_rebind_other<_Tp, _Up, typename __void_t< |
156 | typename _Tp::template rebind<_Up>::other |
157 | >::type> : true_type { }; |
158 | |
159 | template <class _Tp, class _Up, bool = __has_rebind_other<_Tp, _Up>::value> |
160 | struct __allocator_traits_rebind { |
161 | using type _LIBCPP_NODEBUG = typename _Tp::template rebind<_Up>::other; |
162 | }; |
163 | template <template <class, class...> class _Alloc, class _Tp, class ..._Args, class _Up> |
164 | struct __allocator_traits_rebind<_Alloc<_Tp, _Args...>, _Up, true> { |
165 | using type _LIBCPP_NODEBUG = typename _Alloc<_Tp, _Args...>::template rebind<_Up>::other; |
166 | }; |
167 | template <template <class, class...> class _Alloc, class _Tp, class ..._Args, class _Up> |
168 | struct __allocator_traits_rebind<_Alloc<_Tp, _Args...>, _Up, false> { |
169 | using type _LIBCPP_NODEBUG = _Alloc<_Up, _Args...>; |
170 | }; |
171 | _LIBCPP_SUPPRESS_DEPRECATED_POP |
172 | |
173 | template<class _Alloc, class _Tp> |
174 | using __allocator_traits_rebind_t = typename __allocator_traits_rebind<_Alloc, _Tp>::type; |
175 | |
176 | _LIBCPP_SUPPRESS_DEPRECATED_PUSH |
177 | |
178 | // __has_allocate_hint |
179 | template <class _Alloc, class _SizeType, class _ConstVoidPtr, class = void> |
180 | struct __has_allocate_hint : false_type { }; |
181 | |
182 | template <class _Alloc, class _SizeType, class _ConstVoidPtr> |
183 | struct __has_allocate_hint<_Alloc, _SizeType, _ConstVoidPtr, decltype( |
184 | (void)declval<_Alloc>().allocate(declval<_SizeType>(), declval<_ConstVoidPtr>()) |
185 | )> : true_type { }; |
186 | |
187 | // __has_construct |
188 | template <class, class _Alloc, class ..._Args> |
189 | struct __has_construct_impl : false_type { }; |
190 | |
191 | template <class _Alloc, class ..._Args> |
192 | struct __has_construct_impl<decltype( |
193 | (void)declval<_Alloc>().construct(declval<_Args>()...) |
194 | ), _Alloc, _Args...> : true_type { }; |
195 | |
196 | template <class _Alloc, class ..._Args> |
197 | struct __has_construct : __has_construct_impl<void, _Alloc, _Args...> { }; |
198 | |
199 | // __has_destroy |
200 | template <class _Alloc, class _Pointer, class = void> |
201 | struct __has_destroy : false_type { }; |
202 | |
203 | template <class _Alloc, class _Pointer> |
204 | struct __has_destroy<_Alloc, _Pointer, decltype( |
205 | (void)declval<_Alloc>().destroy(declval<_Pointer>()) |
206 | )> : true_type { }; |
207 | |
208 | // __has_max_size |
209 | template <class _Alloc, class = void> |
210 | struct __has_max_size : false_type { }; |
211 | |
212 | template <class _Alloc> |
213 | struct __has_max_size<_Alloc, decltype( |
214 | (void)declval<_Alloc&>().max_size() |
215 | )> : true_type { }; |
216 | |
217 | // __has_select_on_container_copy_construction |
218 | template <class _Alloc, class = void> |
219 | struct __has_select_on_container_copy_construction : false_type { }; |
220 | |
221 | template <class _Alloc> |
222 | struct __has_select_on_container_copy_construction<_Alloc, decltype( |
223 | (void)declval<_Alloc>().select_on_container_copy_construction() |
224 | )> : true_type { }; |
225 | |
226 | _LIBCPP_SUPPRESS_DEPRECATED_POP |
227 | |
228 | template <class _Alloc> |
229 | struct _LIBCPP_TEMPLATE_VIS allocator_traits |
230 | { |
231 | using allocator_type = _Alloc; |
232 | using value_type = typename allocator_type::value_type; |
233 | using pointer = typename __pointer<value_type, allocator_type>::type; |
234 | using const_pointer = typename __const_pointer<value_type, pointer, allocator_type>::type; |
235 | using void_pointer = typename __void_pointer<pointer, allocator_type>::type; |
236 | using const_void_pointer = typename __const_void_pointer<pointer, allocator_type>::type; |
237 | using difference_type = typename __alloc_traits_difference_type<allocator_type, pointer>::type; |
238 | using size_type = typename __size_type<allocator_type, difference_type>::type; |
239 | using propagate_on_container_copy_assignment = typename __propagate_on_container_copy_assignment<allocator_type>::type; |
240 | using propagate_on_container_move_assignment = typename __propagate_on_container_move_assignment<allocator_type>::type; |
241 | using propagate_on_container_swap = typename __propagate_on_container_swap<allocator_type>::type; |
242 | using is_always_equal = typename __is_always_equal<allocator_type>::type; |
243 | |
244 | #ifndef _LIBCPP_CXX03_LANG |
245 | template <class _Tp> |
246 | using rebind_alloc = __allocator_traits_rebind_t<allocator_type, _Tp>; |
247 | template <class _Tp> |
248 | using rebind_traits = allocator_traits<rebind_alloc<_Tp> >; |
249 | #else // _LIBCPP_CXX03_LANG |
250 | template <class _Tp> |
251 | struct rebind_alloc { |
252 | using other = __allocator_traits_rebind_t<allocator_type, _Tp>; |
253 | }; |
254 | template <class _Tp> |
255 | struct rebind_traits { |
256 | using other = allocator_traits<typename rebind_alloc<_Tp>::other>; |
257 | }; |
258 | #endif // _LIBCPP_CXX03_LANG |
259 | |
260 | _LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 |
261 | static pointer allocate(allocator_type& __a, size_type __n) { |
262 | return __a.allocate(__n); |
263 | } |
264 | |
265 | template <class _Ap = _Alloc, class = |
266 | __enable_if_t<__has_allocate_hint<_Ap, size_type, const_void_pointer>::value> > |
267 | _LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 |
268 | static pointer allocate(allocator_type& __a, size_type __n, const_void_pointer __hint) { |
269 | _LIBCPP_SUPPRESS_DEPRECATED_PUSH |
270 | return __a.allocate(__n, __hint); |
271 | _LIBCPP_SUPPRESS_DEPRECATED_POP |
272 | } |
273 | template <class _Ap = _Alloc, class = void, class = |
274 | __enable_if_t<!__has_allocate_hint<_Ap, size_type, const_void_pointer>::value> > |
275 | _LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 |
276 | static pointer allocate(allocator_type& __a, size_type __n, const_void_pointer) { |
277 | return __a.allocate(__n); |
278 | } |
279 | |
280 | _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 |
281 | static void deallocate(allocator_type& __a, pointer __p, size_type __n) _NOEXCEPT { |
282 | __a.deallocate(__p, __n); |
283 | } |
284 | |
285 | template <class _Tp, class... _Args, class = |
286 | __enable_if_t<__has_construct<allocator_type, _Tp*, _Args...>::value> > |
287 | _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 |
288 | static void construct(allocator_type& __a, _Tp* __p, _Args&&... __args) { |
289 | _LIBCPP_SUPPRESS_DEPRECATED_PUSH |
290 | __a.construct(__p, _VSTD::forward<_Args>(__args)...); |
291 | _LIBCPP_SUPPRESS_DEPRECATED_POP |
292 | } |
293 | template <class _Tp, class... _Args, class = void, class = |
294 | __enable_if_t<!__has_construct<allocator_type, _Tp*, _Args...>::value> > |
295 | _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 |
296 | static void construct(allocator_type&, _Tp* __p, _Args&&... __args) { |
297 | #if _LIBCPP_STD_VER > 17 |
298 | _VSTD::construct_at(__p, _VSTD::forward<_Args>(__args)...); |
299 | #else |
300 | ::new ((void*)__p) _Tp(_VSTD::forward<_Args>(__args)...); |
301 | #endif |
302 | } |
303 | |
304 | template <class _Tp, class = |
305 | __enable_if_t<__has_destroy<allocator_type, _Tp*>::value> > |
306 | _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 |
307 | static void destroy(allocator_type& __a, _Tp* __p) { |
308 | _LIBCPP_SUPPRESS_DEPRECATED_PUSH |
309 | __a.destroy(__p); |
310 | _LIBCPP_SUPPRESS_DEPRECATED_POP |
311 | } |
312 | template <class _Tp, class = void, class = |
313 | __enable_if_t<!__has_destroy<allocator_type, _Tp*>::value> > |
314 | _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 |
315 | static void destroy(allocator_type&, _Tp* __p) { |
316 | #if _LIBCPP_STD_VER > 17 |
317 | _VSTD::destroy_at(__p); |
318 | #else |
319 | __p->~_Tp(); |
320 | #endif |
321 | } |
322 | |
323 | template <class _Ap = _Alloc, class = |
324 | __enable_if_t<__has_max_size<const _Ap>::value> > |
325 | _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 |
326 | static size_type max_size(const allocator_type& __a) _NOEXCEPT { |
327 | _LIBCPP_SUPPRESS_DEPRECATED_PUSH |
328 | return __a.max_size(); |
329 | _LIBCPP_SUPPRESS_DEPRECATED_POP |
330 | } |
331 | template <class _Ap = _Alloc, class = void, class = |
332 | __enable_if_t<!__has_max_size<const _Ap>::value> > |
333 | _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 |
334 | static size_type max_size(const allocator_type&) _NOEXCEPT { |
335 | return numeric_limits<size_type>::max() / sizeof(value_type); |
336 | } |
337 | |
338 | template <class _Ap = _Alloc, class = |
339 | __enable_if_t<__has_select_on_container_copy_construction<const _Ap>::value> > |
340 | _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 |
341 | static allocator_type select_on_container_copy_construction(const allocator_type& __a) { |
342 | return __a.select_on_container_copy_construction(); |
343 | } |
344 | template <class _Ap = _Alloc, class = void, class = |
345 | __enable_if_t<!__has_select_on_container_copy_construction<const _Ap>::value> > |
346 | _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 |
347 | static allocator_type select_on_container_copy_construction(const allocator_type& __a) { |
348 | return __a; |
349 | } |
350 | }; |
351 | |
352 | template <class _Traits, class _Tp> |
353 | struct __rebind_alloc_helper { |
354 | #ifndef _LIBCPP_CXX03_LANG |
355 | using type _LIBCPP_NODEBUG = typename _Traits::template rebind_alloc<_Tp>; |
356 | #else |
357 | using type = typename _Traits::template rebind_alloc<_Tp>::other; |
358 | #endif |
359 | }; |
360 | |
361 | // __is_default_allocator |
362 | template <class _Tp> |
363 | struct __is_default_allocator : false_type { }; |
364 | |
365 | template <class> class allocator; |
366 | |
367 | template <class _Tp> |
368 | struct __is_default_allocator<allocator<_Tp> > : true_type { }; |
369 | |
370 | // __is_cpp17_move_insertable |
371 | template <class _Alloc, class = void> |
372 | struct __is_cpp17_move_insertable |
373 | : is_move_constructible<typename _Alloc::value_type> |
374 | { }; |
375 | |
376 | template <class _Alloc> |
377 | struct __is_cpp17_move_insertable<_Alloc, __enable_if_t< |
378 | !__is_default_allocator<_Alloc>::value && |
379 | __has_construct<_Alloc, typename _Alloc::value_type*, typename _Alloc::value_type&&>::value |
380 | > > : true_type { }; |
381 | |
382 | // __is_cpp17_copy_insertable |
383 | template <class _Alloc, class = void> |
384 | struct __is_cpp17_copy_insertable |
385 | : integral_constant<bool, |
386 | is_copy_constructible<typename _Alloc::value_type>::value && |
387 | __is_cpp17_move_insertable<_Alloc>::value |
388 | > |
389 | { }; |
390 | |
391 | template <class _Alloc> |
392 | struct __is_cpp17_copy_insertable<_Alloc, __enable_if_t< |
393 | !__is_default_allocator<_Alloc>::value && |
394 | __has_construct<_Alloc, typename _Alloc::value_type*, const typename _Alloc::value_type&>::value |
395 | > > |
396 | : __is_cpp17_move_insertable<_Alloc> |
397 | { }; |
398 | |
399 | #undef _LIBCPP_ALLOCATOR_TRAITS_HAS_XXX |
400 | |
401 | _LIBCPP_END_NAMESPACE_STD |
402 | |
403 | _LIBCPP_POP_MACROS |
404 | |
405 | #endif // _LIBCPP___MEMORY_ALLOCATOR_TRAITS_H |
406 | |