1// Uses-allocator Construction -*- C++ -*-
2
3// Copyright (C) 2010-2024 Free Software Foundation, Inc.
4//
5// This file is part of the GNU ISO C++ Library. This library is free
6// software; you can redistribute it and/or modify it under the
7// terms of the GNU General Public License as published by the
8// Free Software Foundation; either version 3, or (at your option)
9// any later version.
10
11// This library is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// Under Section 7 of GPL version 3, you are granted additional
17// permissions described in the GCC Runtime Library Exception, version
18// 3.1, as published by the Free Software Foundation.
19
20// You should have received a copy of the GNU General Public License and
21// a copy of the GCC Runtime Library Exception along with this program;
22// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23// <http://www.gnu.org/licenses/>.
24
25/** @file include/bits/uses_allocator_args.h
26 * This is an internal header file, included by other library headers.
27 * Do not attempt to use it directly. @headername{memory}
28 */
29
30#ifndef _USES_ALLOCATOR_H
31#define _USES_ALLOCATOR_H 1
32
33#if __cplusplus < 201103L
34# include <bits/c++0x_warning.h>
35#else
36
37#include <type_traits>
38#include <bits/move.h>
39
40namespace std _GLIBCXX_VISIBILITY(default)
41{
42_GLIBCXX_BEGIN_NAMESPACE_VERSION
43/// @cond undocumented
44
45 // This is used for std::experimental::erased_type from Library Fundamentals.
46 struct __erased_type { };
47
48 // This also supports the "type-erased allocator" protocol from the
49 // Library Fundamentals TS, where allocator_type is erased_type.
50 // The second condition will always be false for types not using the TS.
51 template<typename _Alloc, typename _Tp>
52 using __is_erased_or_convertible
53 = __or_<is_convertible<_Alloc, _Tp>, is_same<_Tp, __erased_type>>;
54
55 /// [allocator.tag]
56 struct allocator_arg_t { explicit allocator_arg_t() = default; };
57
58 _GLIBCXX17_INLINE constexpr allocator_arg_t allocator_arg =
59 allocator_arg_t();
60
61 template<typename _Tp, typename _Alloc, typename = __void_t<>>
62 struct __uses_allocator_helper
63 : false_type { };
64
65 template<typename _Tp, typename _Alloc>
66 struct __uses_allocator_helper<_Tp, _Alloc,
67 __void_t<typename _Tp::allocator_type>>
68 : __is_erased_or_convertible<_Alloc, typename _Tp::allocator_type>::type
69 { };
70
71 /// [allocator.uses.trait]
72 template<typename _Tp, typename _Alloc>
73 struct uses_allocator
74 : __uses_allocator_helper<_Tp, _Alloc>::type
75 { };
76
77 struct __uses_alloc_base { };
78
79 struct __uses_alloc0 : __uses_alloc_base
80 {
81 struct _Sink { void _GLIBCXX20_CONSTEXPR operator=(const void*) { } } _M_a;
82 };
83
84 template<typename _Alloc>
85 struct __uses_alloc1 : __uses_alloc_base { const _Alloc* _M_a; };
86
87 template<typename _Alloc>
88 struct __uses_alloc2 : __uses_alloc_base { const _Alloc* _M_a; };
89
90 template<bool, typename _Tp, typename _Alloc, typename... _Args>
91 struct __uses_alloc;
92
93 template<typename _Tp, typename _Alloc, typename... _Args>
94 struct __uses_alloc<true, _Tp, _Alloc, _Args...>
95 : __conditional_t<
96 is_constructible<_Tp, allocator_arg_t, const _Alloc&, _Args...>::value,
97 __uses_alloc1<_Alloc>,
98 __uses_alloc2<_Alloc>>
99 {
100 // _GLIBCXX_RESOLVE_LIB_DEFECTS
101 // 2586. Wrong value category used in scoped_allocator_adaptor::construct
102 static_assert(__or_<
103 is_constructible<_Tp, allocator_arg_t, const _Alloc&, _Args...>,
104 is_constructible<_Tp, _Args..., const _Alloc&>>::value,
105 "construction with an allocator must be possible"
106 " if uses_allocator is true");
107 };
108
109 template<typename _Tp, typename _Alloc, typename... _Args>
110 struct __uses_alloc<false, _Tp, _Alloc, _Args...>
111 : __uses_alloc0 { };
112
113 template<typename _Tp, typename _Alloc, typename... _Args>
114 using __uses_alloc_t =
115 __uses_alloc<uses_allocator<_Tp, _Alloc>::value, _Tp, _Alloc, _Args...>;
116
117 template<typename _Tp, typename _Alloc, typename... _Args>
118 _GLIBCXX20_CONSTEXPR
119 inline __uses_alloc_t<_Tp, _Alloc, _Args...>
120 __use_alloc(const _Alloc& __a)
121 {
122 __uses_alloc_t<_Tp, _Alloc, _Args...> __ret;
123 __ret._M_a = std::__addressof(__a);
124 return __ret;
125 }
126
127 template<typename _Tp, typename _Alloc, typename... _Args>
128 void
129 __use_alloc(const _Alloc&&) = delete;
130
131#if __cplusplus > 201402L
132 template <typename _Tp, typename _Alloc>
133 inline constexpr bool uses_allocator_v =
134 uses_allocator<_Tp, _Alloc>::value;
135#endif // C++17
136
137 template<template<typename...> class _Predicate,
138 typename _Tp, typename _Alloc, typename... _Args>
139 struct __is_uses_allocator_predicate
140 : __conditional_t<uses_allocator<_Tp, _Alloc>::value,
141 __or_<_Predicate<_Tp, allocator_arg_t, _Alloc, _Args...>,
142 _Predicate<_Tp, _Args..., _Alloc>>,
143 _Predicate<_Tp, _Args...>> { };
144
145 template<typename _Tp, typename _Alloc, typename... _Args>
146 struct __is_uses_allocator_constructible
147 : __is_uses_allocator_predicate<is_constructible, _Tp, _Alloc, _Args...>
148 { };
149
150#if __cplusplus >= 201402L
151 template<typename _Tp, typename _Alloc, typename... _Args>
152 _GLIBCXX17_INLINE constexpr bool __is_uses_allocator_constructible_v =
153 __is_uses_allocator_constructible<_Tp, _Alloc, _Args...>::value;
154#endif // C++14
155
156 template<typename _Tp, typename _Alloc, typename... _Args>
157 struct __is_nothrow_uses_allocator_constructible
158 : __is_uses_allocator_predicate<is_nothrow_constructible,
159 _Tp, _Alloc, _Args...>
160 { };
161
162
163#if __cplusplus >= 201402L
164 template<typename _Tp, typename _Alloc, typename... _Args>
165 _GLIBCXX17_INLINE constexpr bool
166 __is_nothrow_uses_allocator_constructible_v =
167 __is_nothrow_uses_allocator_constructible<_Tp, _Alloc, _Args...>::value;
168#endif // C++14
169
170 template<typename _Tp, typename... _Args>
171 void __uses_allocator_construct_impl(__uses_alloc0, _Tp* __ptr,
172 _Args&&... __args)
173 { ::new ((void*)__ptr) _Tp(std::forward<_Args>(__args)...); }
174
175 template<typename _Tp, typename _Alloc, typename... _Args>
176 void __uses_allocator_construct_impl(__uses_alloc1<_Alloc> __a, _Tp* __ptr,
177 _Args&&... __args)
178 {
179 ::new ((void*)__ptr) _Tp(allocator_arg, *__a._M_a,
180 std::forward<_Args>(__args)...);
181 }
182
183 template<typename _Tp, typename _Alloc, typename... _Args>
184 void __uses_allocator_construct_impl(__uses_alloc2<_Alloc> __a, _Tp* __ptr,
185 _Args&&... __args)
186 { ::new ((void*)__ptr) _Tp(std::forward<_Args>(__args)..., *__a._M_a); }
187
188 template<typename _Tp, typename _Alloc, typename... _Args>
189 void __uses_allocator_construct(const _Alloc& __a, _Tp* __ptr,
190 _Args&&... __args)
191 {
192 std::__uses_allocator_construct_impl(
193 std::__use_alloc<_Tp, _Alloc, _Args...>(__a), __ptr,
194 std::forward<_Args>(__args)...);
195 }
196
197/// @endcond
198_GLIBCXX_END_NAMESPACE_VERSION
199} // namespace std
200
201#endif
202#endif
203