1 //===----------------------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #ifndef _LIBCPP___MEMORY_USES_ALLOCATOR_CONSTRUCTION_H
10 #define _LIBCPP___MEMORY_USES_ALLOCATOR_CONSTRUCTION_H
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/is_same.h>
18 #include <__type_traits/remove_cv.h>
19 #include <__utility/declval.h>
20 #include <__utility/pair.h>
23 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
24 # pragma GCC system_header
28 #include <__undef_macros>
30 _LIBCPP_BEGIN_NAMESPACE_STD
32 #if _LIBCPP_STD_VER >= 17
34 template <class _Type
>
35 inline constexpr bool __is_std_pair
= false;
37 template <class _Type1
, class _Type2
>
38 inline constexpr bool __is_std_pair
<pair
<_Type1
, _Type2
>> = true;
41 inline constexpr bool __is_cv_std_pair
= __is_std_pair
<remove_cv_t
<_Tp
>>;
43 template <class _Tp
, class = void>
44 struct __uses_allocator_construction_args
;
46 namespace __uses_allocator_detail
{
48 template <class _Ap
, class _Bp
>
49 void __fun(const pair
<_Ap
, _Bp
>&);
52 decltype(__uses_allocator_detail::__fun(std::declval
<_Tp
>()), true_type()) __convertible_to_const_pair_ref_impl(int);
55 false_type
__convertible_to_const_pair_ref_impl(...);
58 inline constexpr bool __convertible_to_const_pair_ref
=
59 decltype(__uses_allocator_detail::__convertible_to_const_pair_ref_impl
<_Tp
>(0))::value
;
61 # if _LIBCPP_STD_VER >= 23
62 template <class _Tp
, class _Up
>
63 inline constexpr bool __uses_allocator_constraints
=
64 __is_cv_std_pair
<_Tp
> && !__pair_like_no_subrange
<_Up
> && !__convertible_to_const_pair_ref
<_Up
>;
66 template <class _Tp
, class _Up
>
67 inline constexpr bool __uses_allocator_constraints
= __is_cv_std_pair
<_Tp
> && !__convertible_to_const_pair_ref
<_Up
>;
70 } // namespace __uses_allocator_detail
72 template <class _Type
, class _Alloc
, class... _Args
>
73 _LIBCPP_HIDE_FROM_ABI
constexpr _Type
__make_obj_using_allocator(const _Alloc
& __alloc
, _Args
&&... __args
);
75 template <class _Pair
>
76 struct __uses_allocator_construction_args
<_Pair
, __enable_if_t
<__is_cv_std_pair
<_Pair
>>> {
77 template <class _Alloc
, class _Tuple1
, class _Tuple2
>
78 static _LIBCPP_HIDE_FROM_ABI
constexpr auto
79 __apply(const _Alloc
& __alloc
, piecewise_construct_t
, _Tuple1
&& __x
, _Tuple2
&& __y
) noexcept
{
80 return std::make_tuple(
83 [&__alloc
](auto&&... __args1
) {
84 return __uses_allocator_construction_args
<typename
_Pair::first_type
>::__apply(
85 __alloc
, std::forward
<decltype(__args1
)>(__args1
)...);
87 std::forward
<_Tuple1
>(__x
)),
89 [&__alloc
](auto&&... __args2
) {
90 return __uses_allocator_construction_args
<typename
_Pair::second_type
>::__apply(
91 __alloc
, std::forward
<decltype(__args2
)>(__args2
)...);
93 std::forward
<_Tuple2
>(__y
)));
96 template <class _Alloc
>
97 static _LIBCPP_HIDE_FROM_ABI
constexpr auto __apply(const _Alloc
& __alloc
) noexcept
{
98 return __uses_allocator_construction_args
<_Pair
>::__apply(__alloc
, piecewise_construct
, tuple
<>{}, tuple
<>{});
101 template <class _Alloc
, class _Up
, class _Vp
>
102 static _LIBCPP_HIDE_FROM_ABI
constexpr auto __apply(const _Alloc
& __alloc
, _Up
&& __u
, _Vp
&& __v
) noexcept
{
103 return __uses_allocator_construction_args
<_Pair
>::__apply(
106 std::forward_as_tuple(std::forward
<_Up
>(__u
)),
107 std::forward_as_tuple(std::forward
<_Vp
>(__v
)));
110 # if _LIBCPP_STD_VER >= 23
111 template <class _Alloc
, class _Up
, class _Vp
>
112 static _LIBCPP_HIDE_FROM_ABI
constexpr auto __apply(const _Alloc
& __alloc
, pair
<_Up
, _Vp
>& __pair
) noexcept
{
113 return __uses_allocator_construction_args
<_Pair
>::__apply(
114 __alloc
, piecewise_construct
, std::forward_as_tuple(__pair
.first
), std::forward_as_tuple(__pair
.second
));
118 template <class _Alloc
, class _Up
, class _Vp
>
119 static _LIBCPP_HIDE_FROM_ABI
constexpr auto __apply(const _Alloc
& __alloc
, const pair
<_Up
, _Vp
>& __pair
) noexcept
{
120 return __uses_allocator_construction_args
<_Pair
>::__apply(
121 __alloc
, piecewise_construct
, std::forward_as_tuple(__pair
.first
), std::forward_as_tuple(__pair
.second
));
124 template <class _Alloc
, class _Up
, class _Vp
>
125 static _LIBCPP_HIDE_FROM_ABI
constexpr auto __apply(const _Alloc
& __alloc
, pair
<_Up
, _Vp
>&& __pair
) noexcept
{
126 return __uses_allocator_construction_args
<_Pair
>::__apply(
129 std::forward_as_tuple(std::get
<0>(std::move(__pair
))),
130 std::forward_as_tuple(std::get
<1>(std::move(__pair
))));
133 # if _LIBCPP_STD_VER >= 23
134 template <class _Alloc
, class _Up
, class _Vp
>
135 static _LIBCPP_HIDE_FROM_ABI
constexpr auto __apply(const _Alloc
& __alloc
, const pair
<_Up
, _Vp
>&& __pair
) noexcept
{
136 return __uses_allocator_construction_args
<_Pair
>::__apply(
139 std::forward_as_tuple(std::get
<0>(std::move(__pair
))),
140 std::forward_as_tuple(std::get
<1>(std::move(__pair
))));
143 template < class _Alloc
, __pair_like_no_subrange _PairLike
>
144 static _LIBCPP_HIDE_FROM_ABI
constexpr auto __apply(const _Alloc
& __alloc
, _PairLike
&& __p
) noexcept
{
145 return __uses_allocator_construction_args
<_Pair
>::__apply(
148 std::forward_as_tuple(std::get
<0>(std::forward
<_PairLike
>(__p
))),
149 std::forward_as_tuple(std::get
<1>(std::forward
<_PairLike
>(__p
))));
153 template <class _Alloc
,
155 __enable_if_t
<__uses_allocator_detail::__uses_allocator_constraints
<_Pair
, _Type
>, int> = 0>
156 static _LIBCPP_HIDE_FROM_ABI
constexpr auto __apply(const _Alloc
& __alloc
, _Type
&& __value
) noexcept
{
157 struct __pair_constructor
{
158 using _PairMutable
= remove_cv_t
<_Pair
>;
160 _LIBCPP_HIDDEN
constexpr auto __do_construct(const _PairMutable
& __pair
) const {
161 return std::__make_obj_using_allocator
<_PairMutable
>(__alloc_
, __pair
);
164 _LIBCPP_HIDDEN
constexpr auto __do_construct(_PairMutable
&& __pair
) const {
165 return std::__make_obj_using_allocator
<_PairMutable
>(__alloc_
, std::move(__pair
));
168 const _Alloc
& __alloc_
;
171 _LIBCPP_HIDDEN
constexpr operator _PairMutable() const { return __do_construct(std::forward
<_Type
>(__value_
)); }
174 return std::make_tuple(__pair_constructor
{__alloc
, __value
});
178 template <class _Type
>
179 struct __uses_allocator_construction_args
<_Type
, __enable_if_t
<!__is_cv_std_pair
<_Type
>>> {
180 template <class _Alloc
, class... _Args
>
181 static _LIBCPP_HIDE_FROM_ABI
constexpr auto __apply(const _Alloc
& __alloc
, _Args
&&... __args
) noexcept
{
182 if constexpr (!uses_allocator_v
<remove_cv_t
<_Type
>, _Alloc
> && is_constructible_v
<_Type
, _Args
...>) {
183 return std::forward_as_tuple(std::forward
<_Args
>(__args
)...);
184 } else if constexpr (uses_allocator_v
<remove_cv_t
<_Type
>, _Alloc
> &&
185 is_constructible_v
<_Type
, allocator_arg_t
, const _Alloc
&, _Args
...>) {
186 return tuple
<allocator_arg_t
, const _Alloc
&, _Args
&&...>(allocator_arg
, __alloc
, std::forward
<_Args
>(__args
)...);
187 } else if constexpr (uses_allocator_v
<remove_cv_t
<_Type
>, _Alloc
> &&
188 is_constructible_v
<_Type
, _Args
..., const _Alloc
&>) {
189 return std::forward_as_tuple(std::forward
<_Args
>(__args
)..., __alloc
);
192 sizeof(_Type
) + 1 == 0, "If uses_allocator_v<Type> is true, the type has to be allocator-constructible");
197 template <class _Type
, class _Alloc
, class... _Args
>
198 _LIBCPP_HIDE_FROM_ABI
constexpr _Type
__make_obj_using_allocator(const _Alloc
& __alloc
, _Args
&&... __args
) {
199 return std::make_from_tuple
<_Type
>(
200 __uses_allocator_construction_args
<_Type
>::__apply(__alloc
, std::forward
<_Args
>(__args
)...));
203 template <class _Type
, class _Alloc
, class... _Args
>
204 _LIBCPP_HIDE_FROM_ABI
constexpr _Type
*
205 __uninitialized_construct_using_allocator(_Type
* __ptr
, const _Alloc
& __alloc
, _Args
&&... __args
) {
207 [&__ptr
](auto&&... __xs
) { return std::__construct_at(__ptr
, std::forward
<decltype(__xs
)>(__xs
)...); },
208 __uses_allocator_construction_args
<_Type
>::__apply(__alloc
, std::forward
<_Args
>(__args
)...));
211 #endif // _LIBCPP_STD_VER >= 17
213 #if _LIBCPP_STD_VER >= 20
215 template <class _Type
, class _Alloc
, class... _Args
>
216 _LIBCPP_HIDE_FROM_ABI
constexpr auto uses_allocator_construction_args(const _Alloc
& __alloc
, _Args
&&... __args
) noexcept
217 -> decltype(__uses_allocator_construction_args
<_Type
>::__apply(__alloc
, std::forward
<_Args
>(__args
)...)) {
218 return /*--*/ __uses_allocator_construction_args
<_Type
>::__apply(__alloc
, std::forward
<_Args
>(__args
)...);
221 template <class _Type
, class _Alloc
, class... _Args
>
222 _LIBCPP_HIDE_FROM_ABI
constexpr auto make_obj_using_allocator(const _Alloc
& __alloc
, _Args
&&... __args
)
223 -> decltype(std::__make_obj_using_allocator
<_Type
>(__alloc
, std::forward
<_Args
>(__args
)...)) {
224 return /*--*/ std::__make_obj_using_allocator
<_Type
>(__alloc
, std::forward
<_Args
>(__args
)...);
227 template <class _Type
, class _Alloc
, class... _Args
>
228 _LIBCPP_HIDE_FROM_ABI
constexpr auto
229 uninitialized_construct_using_allocator(_Type
* __ptr
, const _Alloc
& __alloc
, _Args
&&... __args
)
230 -> decltype(std::__uninitialized_construct_using_allocator(__ptr
, __alloc
, std::forward
<_Args
>(__args
)...)) {
231 return /*--*/ std::__uninitialized_construct_using_allocator(__ptr
, __alloc
, std::forward
<_Args
>(__args
)...);
234 #endif // _LIBCPP_STD_VER >= 20
236 _LIBCPP_END_NAMESPACE_STD
240 #endif // _LIBCPP___MEMORY_USES_ALLOCATOR_CONSTRUCTION_H