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 _LIBCPP___MEMORY_USES_ALLOCATOR_CONSTRUCTION_H
10 #define _LIBCPP___MEMORY_USES_ALLOCATOR_CONSTRUCTION_H
11 
12 #include <__config>
13 #include <__memory/construct_at.h>
14 #include <__memory/uses_allocator.h>
15 #include <__tuple/pair_like.h>
16 #include <__type_traits/enable_if.h>
17 #include <__type_traits/is_same.h>
18 #include <__type_traits/remove_cv.h>
19 #include <__utility/declval.h>
20 #include <__utility/pair.h>
21 #include <tuple>
22 
23 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
24 #  pragma GCC system_header
25 #endif
26 
27 _LIBCPP_PUSH_MACROS
28 #include <__undef_macros>
29 
30 _LIBCPP_BEGIN_NAMESPACE_STD
31 
32 #if _LIBCPP_STD_VER >= 17
33 
34 template <class _Type>
35 inline constexpr bool __is_std_pair = false;
36 
37 template <class _Type1, class _Type2>
38 inline constexpr bool __is_std_pair<pair<_Type1, _Type2>> = true;
39 
40 template <class _Tp>
41 inline constexpr bool __is_cv_std_pair = __is_std_pair<remove_cv_t<_Tp>>;
42 
43 template <class _Type, class _Alloc, class... _Args, __enable_if_t<!__is_cv_std_pair<_Type>, int> = 0>
44 _LIBCPP_HIDE_FROM_ABI constexpr auto
__uses_allocator_construction_args(const _Alloc & __alloc,_Args &&...__args)45 __uses_allocator_construction_args(const _Alloc& __alloc, _Args&&... __args) noexcept {
46   if constexpr (!uses_allocator_v<remove_cv_t<_Type>, _Alloc> && is_constructible_v<_Type, _Args...>) {
47     return std::forward_as_tuple(std::forward<_Args>(__args)...);
48   } else if constexpr (uses_allocator_v<remove_cv_t<_Type>, _Alloc> &&
49                        is_constructible_v<_Type, allocator_arg_t, const _Alloc&, _Args...>) {
50     return tuple<allocator_arg_t, const _Alloc&, _Args&&...>(allocator_arg, __alloc, std::forward<_Args>(__args)...);
51   } else if constexpr (uses_allocator_v<remove_cv_t<_Type>, _Alloc> &&
52                        is_constructible_v<_Type, _Args..., const _Alloc&>) {
53     return std::forward_as_tuple(std::forward<_Args>(__args)..., __alloc);
54   } else {
55     static_assert(
56         sizeof(_Type) + 1 == 0, "If uses_allocator_v<Type> is true, the type has to be allocator-constructible");
57   }
58 }
59 
60 template <class _Pair, class _Alloc, class _Tuple1, class _Tuple2, __enable_if_t<__is_cv_std_pair<_Pair>, int> = 0>
__uses_allocator_construction_args(const _Alloc & __alloc,piecewise_construct_t,_Tuple1 && __x,_Tuple2 && __y)61 _LIBCPP_HIDE_FROM_ABI constexpr auto __uses_allocator_construction_args(
62     const _Alloc& __alloc, piecewise_construct_t, _Tuple1&& __x, _Tuple2&& __y) noexcept {
63   return std::make_tuple(
64       piecewise_construct,
65       std::apply(
66           [&__alloc](auto&&... __args1) {
67             return std::__uses_allocator_construction_args<typename _Pair::first_type>(
68                 __alloc, std::forward<decltype(__args1)>(__args1)...);
69           },
70           std::forward<_Tuple1>(__x)),
71       std::apply(
72           [&__alloc](auto&&... __args2) {
73             return std::__uses_allocator_construction_args<typename _Pair::second_type>(
74                 __alloc, std::forward<decltype(__args2)>(__args2)...);
75           },
76           std::forward<_Tuple2>(__y)));
77 }
78 
79 template <class _Pair, class _Alloc, __enable_if_t<__is_cv_std_pair<_Pair>, int> = 0>
__uses_allocator_construction_args(const _Alloc & __alloc)80 _LIBCPP_HIDE_FROM_ABI constexpr auto __uses_allocator_construction_args(const _Alloc& __alloc) noexcept {
81   return std::__uses_allocator_construction_args<_Pair>(__alloc, piecewise_construct, tuple<>{}, tuple<>{});
82 }
83 
84 template <class _Pair, class _Alloc, class _Up, class _Vp, __enable_if_t<__is_cv_std_pair<_Pair>, int> = 0>
85 _LIBCPP_HIDE_FROM_ABI constexpr auto
__uses_allocator_construction_args(const _Alloc & __alloc,_Up && __u,_Vp && __v)86 __uses_allocator_construction_args(const _Alloc& __alloc, _Up&& __u, _Vp&& __v) noexcept {
87   return std::__uses_allocator_construction_args<_Pair>(
88       __alloc,
89       piecewise_construct,
90       std::forward_as_tuple(std::forward<_Up>(__u)),
91       std::forward_as_tuple(std::forward<_Vp>(__v)));
92 }
93 
94 #  if _LIBCPP_STD_VER >= 23
95 template <class _Pair, class _Alloc, class _Up, class _Vp, __enable_if_t<__is_cv_std_pair<_Pair>, int> = 0>
96 _LIBCPP_HIDE_FROM_ABI constexpr auto
__uses_allocator_construction_args(const _Alloc & __alloc,pair<_Up,_Vp> & __pair)97 __uses_allocator_construction_args(const _Alloc& __alloc, pair<_Up, _Vp>& __pair) noexcept {
98   return std::__uses_allocator_construction_args<_Pair>(
99       __alloc, piecewise_construct, std::forward_as_tuple(__pair.first), std::forward_as_tuple(__pair.second));
100 }
101 #  endif
102 
103 template <class _Pair, class _Alloc, class _Up, class _Vp, __enable_if_t<__is_cv_std_pair<_Pair>, int> = 0>
104 _LIBCPP_HIDE_FROM_ABI constexpr auto
__uses_allocator_construction_args(const _Alloc & __alloc,const pair<_Up,_Vp> & __pair)105 __uses_allocator_construction_args(const _Alloc& __alloc, const pair<_Up, _Vp>& __pair) noexcept {
106   return std::__uses_allocator_construction_args<_Pair>(
107       __alloc, piecewise_construct, std::forward_as_tuple(__pair.first), std::forward_as_tuple(__pair.second));
108 }
109 
110 template <class _Pair, class _Alloc, class _Up, class _Vp, __enable_if_t<__is_cv_std_pair<_Pair>, int> = 0>
111 _LIBCPP_HIDE_FROM_ABI constexpr auto
__uses_allocator_construction_args(const _Alloc & __alloc,pair<_Up,_Vp> && __pair)112 __uses_allocator_construction_args(const _Alloc& __alloc, pair<_Up, _Vp>&& __pair) noexcept {
113   return std::__uses_allocator_construction_args<_Pair>(
114       __alloc,
115       piecewise_construct,
116       std::forward_as_tuple(std::get<0>(std::move(__pair))),
117       std::forward_as_tuple(std::get<1>(std::move(__pair))));
118 }
119 
120 #  if _LIBCPP_STD_VER >= 23
121 template <class _Pair, class _Alloc, class _Up, class _Vp, __enable_if_t<__is_cv_std_pair<_Pair>, int> = 0>
122 _LIBCPP_HIDE_FROM_ABI constexpr auto
__uses_allocator_construction_args(const _Alloc & __alloc,const pair<_Up,_Vp> && __pair)123 __uses_allocator_construction_args(const _Alloc& __alloc, const pair<_Up, _Vp>&& __pair) noexcept {
124   return std::__uses_allocator_construction_args<_Pair>(
125       __alloc,
126       piecewise_construct,
127       std::forward_as_tuple(std::get<0>(std::move(__pair))),
128       std::forward_as_tuple(std::get<1>(std::move(__pair))));
129 }
130 
131 template < class _Pair,
132            class _Alloc,
133            __pair_like _PairLike,
134            __enable_if_t<__is_cv_std_pair<_Pair> && !__is_specialization_of_subrange<remove_cvref_t<_PairLike>>::value,
135                          int> = 0>
136 _LIBCPP_HIDE_FROM_ABI constexpr auto
__uses_allocator_construction_args(const _Alloc & __alloc,_PairLike && __p)137 __uses_allocator_construction_args(const _Alloc& __alloc, _PairLike&& __p) noexcept {
138   return std::__uses_allocator_construction_args<_Pair>(
139       __alloc,
140       piecewise_construct,
141       std::forward_as_tuple(std::get<0>(std::forward<_PairLike>(__p))),
142       std::forward_as_tuple(std::get<1>(std::forward<_PairLike>(__p))));
143 }
144 #  endif
145 
146 namespace __uses_allocator_detail {
147 
148 template <class _Ap, class _Bp>
149 void __fun(const pair<_Ap, _Bp>&);
150 
151 template <class _Tp>
152 decltype(__uses_allocator_detail::__fun(std::declval<_Tp>()), true_type()) __convertible_to_const_pair_ref_impl(int);
153 
154 template <class>
155 false_type __convertible_to_const_pair_ref_impl(...);
156 
157 template <class _Tp>
158 inline constexpr bool __convertible_to_const_pair_ref =
159     decltype(__uses_allocator_detail::__convertible_to_const_pair_ref_impl<_Tp>(0))::value;
160 
161 #  if _LIBCPP_STD_VER >= 23
162 template <class _Tp, class _Up>
163 inline constexpr bool __uses_allocator_constraints =
164     __is_cv_std_pair<_Tp> &&
165     (__is_specialization_of_subrange<remove_cvref_t<_Up>>::value ||
166      (!__pair_like<_Up> && !__convertible_to_const_pair_ref<_Up>));
167 #  else
168 template <class _Tp, class _Up>
169 inline constexpr bool __uses_allocator_constraints = __is_cv_std_pair<_Tp> && !__convertible_to_const_pair_ref<_Up>;
170 #  endif
171 
172 } // namespace __uses_allocator_detail
173 
174 template < class _Pair,
175            class _Alloc,
176            class _Type,
177            __enable_if_t<__uses_allocator_detail::__uses_allocator_constraints<_Pair, _Type>, int> = 0>
178 _LIBCPP_HIDE_FROM_ABI constexpr auto
179 __uses_allocator_construction_args(const _Alloc& __alloc, _Type&& __value) noexcept;
180 
181 template <class _Type, class _Alloc, class... _Args>
182 _LIBCPP_HIDE_FROM_ABI constexpr _Type __make_obj_using_allocator(const _Alloc& __alloc, _Args&&... __args);
183 
184 template < class _Pair,
185            class _Alloc,
186            class _Type,
187            __enable_if_t< __uses_allocator_detail::__uses_allocator_constraints<_Pair, _Type>, int>>
188 _LIBCPP_HIDE_FROM_ABI constexpr auto
__uses_allocator_construction_args(const _Alloc & __alloc,_Type && __value)189 __uses_allocator_construction_args(const _Alloc& __alloc, _Type&& __value) noexcept {
190   struct __pair_constructor {
191     using _PairMutable = remove_cv_t<_Pair>;
192 
193     _LIBCPP_HIDE_FROM_ABI constexpr auto __do_construct(const _PairMutable& __pair) const {
194       return std::__make_obj_using_allocator<_PairMutable>(__alloc_, __pair);
195     }
196 
197     _LIBCPP_HIDE_FROM_ABI constexpr auto __do_construct(_PairMutable&& __pair) const {
198       return std::__make_obj_using_allocator<_PairMutable>(__alloc_, std::move(__pair));
199     }
200 
201     const _Alloc& __alloc_;
202     _Type& __value_;
203 
204     _LIBCPP_HIDE_FROM_ABI constexpr operator _PairMutable() const {
205       return __do_construct(std::forward<_Type>(this->__value_));
206     }
207   };
208 
209   return std::make_tuple(__pair_constructor{__alloc, __value});
210 }
211 
212 template <class _Type, class _Alloc, class... _Args>
__make_obj_using_allocator(const _Alloc & __alloc,_Args &&...__args)213 _LIBCPP_HIDE_FROM_ABI constexpr _Type __make_obj_using_allocator(const _Alloc& __alloc, _Args&&... __args) {
214   return std::make_from_tuple<_Type>(
215       std::__uses_allocator_construction_args<_Type>(__alloc, std::forward<_Args>(__args)...));
216 }
217 
218 template <class _Type, class _Alloc, class... _Args>
219 _LIBCPP_HIDE_FROM_ABI constexpr _Type*
__uninitialized_construct_using_allocator(_Type * __ptr,const _Alloc & __alloc,_Args &&...__args)220 __uninitialized_construct_using_allocator(_Type* __ptr, const _Alloc& __alloc, _Args&&... __args) {
221   return std::apply(
222       [&__ptr](auto&&... __xs) { return std::__construct_at(__ptr, std::forward<decltype(__xs)>(__xs)...); },
223       std::__uses_allocator_construction_args<_Type>(__alloc, std::forward<_Args>(__args)...));
224 }
225 
226 #endif // _LIBCPP_STD_VER >= 17
227 
228 #if _LIBCPP_STD_VER >= 20
229 
230 template <class _Type, class _Alloc, class... _Args>
231 _LIBCPP_HIDE_FROM_ABI constexpr auto uses_allocator_construction_args(const _Alloc& __alloc, _Args&&... __args) noexcept
232     -> decltype(std::__uses_allocator_construction_args<_Type>(__alloc, std::forward<_Args>(__args)...)) {
233   return /*--*/ std::__uses_allocator_construction_args<_Type>(__alloc, std::forward<_Args>(__args)...);
234 }
235 
236 template <class _Type, class _Alloc, class... _Args>
237 _LIBCPP_HIDE_FROM_ABI constexpr auto make_obj_using_allocator(const _Alloc& __alloc, _Args&&... __args)
238     -> decltype(std::__make_obj_using_allocator<_Type>(__alloc, std::forward<_Args>(__args)...)) {
239   return /*--*/ std::__make_obj_using_allocator<_Type>(__alloc, std::forward<_Args>(__args)...);
240 }
241 
242 template <class _Type, class _Alloc, class... _Args>
243 _LIBCPP_HIDE_FROM_ABI constexpr auto
244 uninitialized_construct_using_allocator(_Type* __ptr, const _Alloc& __alloc, _Args&&... __args)
245     -> decltype(std::__uninitialized_construct_using_allocator(__ptr, __alloc, std::forward<_Args>(__args)...)) {
246   return /*--*/ std::__uninitialized_construct_using_allocator(__ptr, __alloc, std::forward<_Args>(__args)...);
247 }
248 
249 #endif // _LIBCPP_STD_VER >= 20
250 
251 _LIBCPP_END_NAMESPACE_STD
252 
253 _LIBCPP_POP_MACROS
254 
255 #endif // _LIBCPP___MEMORY_USES_ALLOCATOR_CONSTRUCTION_H
256