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