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