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