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/is_same.h> 18 #include <__type_traits/remove_cv.h> 19 #include <__utility/declval.h> 20 #include <__utility/pair.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 34 template <class _Type> 35 inline constexpr bool __is_std_pair = false; 36 37 template <class _Type1, class _Type2> 38 inline constexpr bool __is_std_pair<pair<_Type1, _Type2>> = true; 39 40 template <class _Tp> 41 inline constexpr bool __is_cv_std_pair = __is_std_pair<remove_cv_t<_Tp>>; 42 43 template <class _Tp, class = void> 44 struct __uses_allocator_construction_args; 45 46 namespace __uses_allocator_detail { 47 48 template <class _Ap, class _Bp> 49 void __fun(const pair<_Ap, _Bp>&); 50 51 template <class _Tp> 52 decltype(__uses_allocator_detail::__fun(std::declval<_Tp>()), true_type()) __convertible_to_const_pair_ref_impl(int); 53 54 template <class> 55 false_type __convertible_to_const_pair_ref_impl(...); 56 57 template <class _Tp> 58 inline constexpr bool __convertible_to_const_pair_ref = 59 decltype(__uses_allocator_detail::__convertible_to_const_pair_ref_impl<_Tp>(0))::value; 60 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>; 65 # else 66 template <class _Tp, class _Up> 67 inline constexpr bool __uses_allocator_constraints = __is_cv_std_pair<_Tp> && !__convertible_to_const_pair_ref<_Up>; 68 # endif 69 70 } // namespace __uses_allocator_detail 71 72 template <class _Type, class _Alloc, class... _Args> 73 _LIBCPP_HIDE_FROM_ABI constexpr _Type __make_obj_using_allocator(const _Alloc& __alloc, _Args&&... __args); 74 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( 81 piecewise_construct, 82 std::apply( 83 [&__alloc](auto&&... __args1) { 84 return __uses_allocator_construction_args<typename _Pair::first_type>::__apply( 85 __alloc, std::forward<decltype(__args1)>(__args1)...); 86 }, 87 std::forward<_Tuple1>(__x)), 88 std::apply( 89 [&__alloc](auto&&... __args2) { 90 return __uses_allocator_construction_args<typename _Pair::second_type>::__apply( 91 __alloc, std::forward<decltype(__args2)>(__args2)...); 92 }, 93 std::forward<_Tuple2>(__y))); 94 } 95 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<>{}); 99 } 100 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( 104 __alloc, 105 piecewise_construct, 106 std::forward_as_tuple(std::forward<_Up>(__u)), 107 std::forward_as_tuple(std::forward<_Vp>(__v))); 108 } 109 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)); 115 } 116 # endif 117 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)); 122 } 123 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( 127 __alloc, 128 piecewise_construct, 129 std::forward_as_tuple(std::get<0>(std::move(__pair))), 130 std::forward_as_tuple(std::get<1>(std::move(__pair)))); 131 } 132 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( 137 __alloc, 138 piecewise_construct, 139 std::forward_as_tuple(std::get<0>(std::move(__pair))), 140 std::forward_as_tuple(std::get<1>(std::move(__pair)))); 141 } 142 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( 146 __alloc, 147 piecewise_construct, 148 std::forward_as_tuple(std::get<0>(std::forward<_PairLike>(__p))), 149 std::forward_as_tuple(std::get<1>(std::forward<_PairLike>(__p)))); 150 } 151 # endif 152 153 template <class _Alloc, 154 class _Type, 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>; 159 160 _LIBCPP_HIDDEN constexpr auto __do_construct(const _PairMutable& __pair) const { 161 return std::__make_obj_using_allocator<_PairMutable>(__alloc_, __pair); 162 } 163 164 _LIBCPP_HIDDEN constexpr auto __do_construct(_PairMutable&& __pair) const { 165 return std::__make_obj_using_allocator<_PairMutable>(__alloc_, std::move(__pair)); 166 } 167 168 const _Alloc& __alloc_; 169 _Type& __value_; 170 171 _LIBCPP_HIDDEN constexpr operator _PairMutable() const { return __do_construct(std::forward<_Type>(__value_)); } 172 }; 173 174 return std::make_tuple(__pair_constructor{__alloc, __value}); 175 } 176 }; 177 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); 190 } else { 191 static_assert( 192 sizeof(_Type) + 1 == 0, "If uses_allocator_v<Type> is true, the type has to be allocator-constructible"); 193 } 194 } 195 }; 196 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)...)); 201 } 202 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) { 206 return std::apply( 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)...)); 209 } 210 211 #endif // _LIBCPP_STD_VER >= 17 212 213 #if _LIBCPP_STD_VER >= 20 214 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)...); 219 } 220 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)...); 225 } 226 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)...); 232 } 233 234 #endif // _LIBCPP_STD_VER >= 20 235 236 _LIBCPP_END_NAMESPACE_STD 237 238 _LIBCPP_POP_MACROS 239 240 #endif // _LIBCPP___MEMORY_USES_ALLOCATOR_CONSTRUCTION_H 241