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