1// Uses-allocator Construction -*- C++ -*-
2
3// Copyright (C) 2010-2022 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#ifndef _USES_ALLOCATOR_H
26#define _USES_ALLOCATOR_H 1
27
28#if __cplusplus < 201103L
29# include <bits/c++0x_warning.h>
30#else
31
32#include <type_traits>
33#include <bits/move.h>
34
35namespace std _GLIBCXX_VISIBILITY(default)
36{
37_GLIBCXX_BEGIN_NAMESPACE_VERSION
38/// @cond undocumented
39
40 // This is used for std::experimental::erased_type from Library Fundamentals.
41 struct __erased_type { };
42
43 // This also supports the "type-erased allocator" protocol from the
44 // Library Fundamentals TS, where allocator_type is erased_type.
45 // The second condition will always be false for types not using the TS.
46 template<typename _Alloc, typename _Tp>
47 using __is_erased_or_convertible
48 = __or_<is_convertible<_Alloc, _Tp>, is_same<_Tp, __erased_type>>;
49
50 /// [allocator.tag]
51 struct allocator_arg_t { explicit allocator_arg_t() = default; };
52
53 _GLIBCXX17_INLINE constexpr allocator_arg_t allocator_arg =
54 allocator_arg_t();
55
56 template<typename _Tp, typename _Alloc, typename = __void_t<>>
57 struct __uses_allocator_helper
58 : false_type { };
59
60 template<typename _Tp, typename _Alloc>
61 struct __uses_allocator_helper<_Tp, _Alloc,
62 __void_t<typename _Tp::allocator_type>>
63 : __is_erased_or_convertible<_Alloc, typename _Tp::allocator_type>::type
64 { };
65
66 /// [allocator.uses.trait]
67 template<typename _Tp, typename _Alloc>
68 struct uses_allocator
69 : __uses_allocator_helper<_Tp, _Alloc>::type
70 { };
71
72 struct __uses_alloc_base { };
73
74 struct __uses_alloc0 : __uses_alloc_base
75 {
76 struct _Sink { void _GLIBCXX20_CONSTEXPR operator=(const void*) { } } _M_a;
77 };
78
79 template<typename _Alloc>
80 struct __uses_alloc1 : __uses_alloc_base { const _Alloc* _M_a; };
81
82 template<typename _Alloc>
83 struct __uses_alloc2 : __uses_alloc_base { const _Alloc* _M_a; };
84
85 template<bool, typename _Tp, typename _Alloc, typename... _Args>
86 struct __uses_alloc;
87
88 template<typename _Tp, typename _Alloc, typename... _Args>
89 struct __uses_alloc<true, _Tp, _Alloc, _Args...>
90 : __conditional_t<
91 is_constructible<_Tp, allocator_arg_t, const _Alloc&, _Args...>::value,
92 __uses_alloc1<_Alloc>,
93 __uses_alloc2<_Alloc>>
94 {
95 // _GLIBCXX_RESOLVE_LIB_DEFECTS
96 // 2586. Wrong value category used in scoped_allocator_adaptor::construct
97 static_assert(__or_<
98 is_constructible<_Tp, allocator_arg_t, const _Alloc&, _Args...>,
99 is_constructible<_Tp, _Args..., const _Alloc&>>::value,
100 "construction with an allocator must be possible"
101 " if uses_allocator is true");
102 };
103
104 template<typename _Tp, typename _Alloc, typename... _Args>
105 struct __uses_alloc<false, _Tp, _Alloc, _Args...>
106 : __uses_alloc0 { };
107
108 template<typename _Tp, typename _Alloc, typename... _Args>
109 using __uses_alloc_t =
110 __uses_alloc<uses_allocator<_Tp, _Alloc>::value, _Tp, _Alloc, _Args...>;
111
112 template<typename _Tp, typename _Alloc, typename... _Args>
113 _GLIBCXX20_CONSTEXPR
114 inline __uses_alloc_t<_Tp, _Alloc, _Args...>
115 __use_alloc(const _Alloc& __a)
116 {
117 __uses_alloc_t<_Tp, _Alloc, _Args...> __ret;
118 __ret._M_a = std::__addressof(__a);
119 return __ret;
120 }
121
122 template<typename _Tp, typename _Alloc, typename... _Args>
123 void
124 __use_alloc(const _Alloc&&) = delete;
125
126#if __cplusplus > 201402L
127 template <typename _Tp, typename _Alloc>
128 inline constexpr bool uses_allocator_v =
129 uses_allocator<_Tp, _Alloc>::value;
130#endif // C++17
131
132 template<template<typename...> class _Predicate,
133 typename _Tp, typename _Alloc, typename... _Args>
134 struct __is_uses_allocator_predicate
135 : __conditional_t<uses_allocator<_Tp, _Alloc>::value,
136 __or_<_Predicate<_Tp, allocator_arg_t, _Alloc, _Args...>,
137 _Predicate<_Tp, _Args..., _Alloc>>,
138 _Predicate<_Tp, _Args...>> { };
139
140 template<typename _Tp, typename _Alloc, typename... _Args>
141 struct __is_uses_allocator_constructible
142 : __is_uses_allocator_predicate<is_constructible, _Tp, _Alloc, _Args...>
143 { };
144
145#if __cplusplus >= 201402L
146 template<typename _Tp, typename _Alloc, typename... _Args>
147 _GLIBCXX17_INLINE constexpr bool __is_uses_allocator_constructible_v =
148 __is_uses_allocator_constructible<_Tp, _Alloc, _Args...>::value;
149#endif // C++14
150
151 template<typename _Tp, typename _Alloc, typename... _Args>
152 struct __is_nothrow_uses_allocator_constructible
153 : __is_uses_allocator_predicate<is_nothrow_constructible,
154 _Tp, _Alloc, _Args...>
155 { };
156
157
158#if __cplusplus >= 201402L
159 template<typename _Tp, typename _Alloc, typename... _Args>
160 _GLIBCXX17_INLINE constexpr bool
161 __is_nothrow_uses_allocator_constructible_v =
162 __is_nothrow_uses_allocator_constructible<_Tp, _Alloc, _Args...>::value;
163#endif // C++14
164
165 template<typename _Tp, typename... _Args>
166 void __uses_allocator_construct_impl(__uses_alloc0 __a, _Tp* __ptr,
167 _Args&&... __args)
168 { ::new ((void*)__ptr) _Tp(std::forward<_Args>(__args)...); }
169
170 template<typename _Tp, typename _Alloc, typename... _Args>
171 void __uses_allocator_construct_impl(__uses_alloc1<_Alloc> __a, _Tp* __ptr,
172 _Args&&... __args)
173 {
174 ::new ((void*)__ptr) _Tp(allocator_arg, *__a._M_a,
175 std::forward<_Args>(__args)...);
176 }
177
178 template<typename _Tp, typename _Alloc, typename... _Args>
179 void __uses_allocator_construct_impl(__uses_alloc2<_Alloc> __a, _Tp* __ptr,
180 _Args&&... __args)
181 { ::new ((void*)__ptr) _Tp(std::forward<_Args>(__args)..., *__a._M_a); }
182
183 template<typename _Tp, typename _Alloc, typename... _Args>
184 void __uses_allocator_construct(const _Alloc& __a, _Tp* __ptr,
185 _Args&&... __args)
186 {
187 std::__uses_allocator_construct_impl(
188 std::__use_alloc<_Tp, _Alloc, _Args...>(__a), __ptr,
189 std::forward<_Args>(__args)...);
190 }
191
192/// @endcond
193_GLIBCXX_END_NAMESPACE_VERSION
194} // namespace std
195
196#endif
197#endif
198