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
__uses_allocator_construction_args(const _Alloc & __alloc,_Args &&...__args)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>
__uses_allocator_construction_args(const _Alloc & __alloc,piecewise_construct_t,_Tuple1 && __x,_Tuple2 && __y)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>
__uses_allocator_construction_args(const _Alloc & __alloc)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
__uses_allocator_construction_args(const _Alloc & __alloc,_Up && __u,_Vp && __v)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
__uses_allocator_construction_args(const _Alloc & __alloc,pair<_Up,_Vp> & __pair)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
__uses_allocator_construction_args(const _Alloc & __alloc,const pair<_Up,_Vp> & __pair)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
__uses_allocator_construction_args(const _Alloc & __alloc,pair<_Up,_Vp> && __pair)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
__uses_allocator_construction_args(const _Alloc & __alloc,const pair<_Up,_Vp> && __pair)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
__uses_allocator_construction_args(const _Alloc & __alloc,_Type && __value)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>
__make_obj_using_allocator(const _Alloc & __alloc,_Args &&...__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*
__uninitialized_construct_using_allocator(_Type * __ptr,const _Alloc & __alloc,_Args &&...__args)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