Where Online Learning is simpler!
The C and C++ Include Header Files
cat -n /usr/include/c++/15/bits/out_ptr.h
1 // Smart pointer adaptors -*- C++ -*- 2 3 // Copyright The GNU Toolchain Authors. 4 // 5 // This file is part of the GNU ISO C++ Library. This library is free 6 // software; you can redistribute it and/or modify it under the 7 // terms of the GNU General Public License as published by the 8 // Free Software Foundation; either version 3, or (at your option) 9 // any later version. 10 11 // This library is distributed in the hope that it will be useful, 12 // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 // GNU General Public License for more details. 15 16 // Under Section 7 of GPL version 3, you are granted additional 17 // permissions described in the GCC Runtime Library Exception, version 18 // 3.1, as published by the Free Software Foundation. 19 20 // You should have received a copy of the GNU General Public License and 21 // a copy of the GCC Runtime Library Exception along with this program; 22 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23 // <http://www.gnu.org/licenses/>. 24 25 /** @file include/bits/out_ptr.h 26 * This is an internal header file, included by other library headers. 27 * Do not attempt to use it directly. @headername{memory} 28 */ 29 30 #ifndef _GLIBCXX_OUT_PTR_H 31 #define _GLIBCXX_OUT_PTR_H 1 32 33 #ifdef _GLIBCXX_SYSHDR 34 #pragma GCC system_header 35 #endif 36 37 #include <bits/version.h> 38 39 #ifdef __glibcxx_out_ptr // C++ >= 23 40 41 #include <tuple> 42 #include <bits/ptr_traits.h> 43 44 namespace std _GLIBCXX_VISIBILITY(default) 45 { 46 _GLIBCXX_BEGIN_NAMESPACE_VERSION 47 48 /// Smart pointer adaptor for functions taking an output pointer parameter. 49 /** 50 * @tparam _Smart The type of pointer to adapt. 51 * @tparam _Pointer The type of pointer to convert to. 52 * @tparam _Args... Argument types used when resetting the smart pointer. 53 * @since C++23 54 * @headerfile <memory> 55 */ 56 template<typename _Smart, typename _Pointer, typename... _Args> 57 class out_ptr_t 58 { 59 #if _GLIBCXX_HOSTED 60 static_assert(!__is_shared_ptr<_Smart> || sizeof...(_Args) != 0, 61 "a deleter must be used when adapting std::shared_ptr " 62 "with std::out_ptr"); 63 #endif 64 65 public: 66 explicit 67 out_ptr_t(_Smart& __smart, _Args... __args) 68 : _M_impl{__smart, std::forward<_Args>(__args)...} 69 { 70 if constexpr (requires { _M_impl._M_out_init(); }) 71 _M_impl._M_out_init(); 72 } 73 74 out_ptr_t(const out_ptr_t&) = delete; 75 76 ~out_ptr_t() = default; 77 78 operator _Pointer*() const noexcept 79 { return _M_impl._M_get(); } 80 81 operator void**() const noexcept requires (!same_as<_Pointer, void*>) 82 { 83 static_assert(is_pointer_v<_Pointer>); 84 _Pointer* __p = *this; 85 return static_cast<void**>(static_cast<void*>(__p)); 86 } 87 88 private: 89 // TODO: Move this to namespace scope? e.g. __detail::_Ptr_adapt_impl 90 template<typename, typename, typename...> 91 struct _Impl 92 { 93 // This constructor must not modify __s because out_ptr_t and 94 // inout_ptr_t want to do different things. After construction 95 // they call _M_out_init() or _M_inout_init() respectively. 96 _Impl(_Smart& __s, _Args&&... __args) 97 : _M_smart(__s), _M_args(std::forward<_Args>(__args)...) 98 { } 99 100 // Called by out_ptr_t to clear the smart pointer before using it. 101 void 102 _M_out_init() 103 { 104 // _GLIBCXX_RESOLVE_LIB_DEFECTS 105 // 3734. Inconsistency in inout_ptr and out_ptr for empty case 106 if constexpr (requires { _M_smart.reset(); }) 107 _M_smart.reset(); 108 else 109 _M_smart = _Smart(); 110 } 111 112 // Called by inout_ptr_t to copy the smart pointer's value 113 // to the pointer that is returned from _M_get(). 114 void 115 _M_inout_init() 116 { _M_ptr = _M_smart.release(); } 117 118 // The pointer value returned by operator Pointer*(). 119 _Pointer* 120 _M_get() const 121 { return __builtin_addressof(const_cast<_Pointer&>(_M_ptr)); } 122 123 // Finalize the effects on the smart pointer. 124 ~_Impl() noexcept(false); 125 126 _Smart& _M_smart; 127 [[no_unique_address]] _Pointer _M_ptr{}; 128 [[no_unique_address]] tuple<_Args...> _M_args; 129 }; 130 131 // Partial specialization for raw pointers. 132 template<typename _Tp> 133 struct _Impl<_Tp*, _Tp*> 134 { 135 void 136 _M_out_init() 137 { _M_p = nullptr; } 138 139 void 140 _M_inout_init() 141 { } 142 143 _Tp** 144 _M_get() const 145 { return __builtin_addressof(const_cast<_Tp*&>(_M_p)); } 146 147 _Tp*& _M_p; 148 }; 149 150 // Partial specialization for raw pointers, with conversion. 151 template<typename _Tp, typename _Ptr> requires (!is_same_v<_Ptr, _Tp*>) 152 struct _Impl<_Tp*, _Ptr> 153 { 154 explicit 155 _Impl(_Tp*& __p) 156 : _M_p(__p) 157 { } 158 159 void 160 _M_out_init() 161 { _M_p = nullptr; } 162 163 void 164 _M_inout_init() 165 { _M_ptr = _M_p; } 166 167 _Pointer* 168 _M_get() const 169 { return __builtin_addressof(const_cast<_Pointer&>(_M_ptr)); } 170 171 ~_Impl() { _M_p = static_cast<_Tp*>(_M_ptr); } 172 173 _Tp*& _M_p; 174 _Pointer _M_ptr{}; 175 }; 176 177 // Partial specialization for std::unique_ptr. 178 // This specialization gives direct access to the private member 179 // of the unique_ptr, avoiding the overhead of storing a separate 180 // pointer and then resetting the unique_ptr in the destructor. 181 // FIXME: constrain to only match the primary template, 182 // not program-defined specializations of unique_ptr. 183 template<typename _Tp, typename _Del> 184 struct _Impl<unique_ptr<_Tp, _Del>, 185 typename unique_ptr<_Tp, _Del>::pointer> 186 { 187 void 188 _M_out_init() 189 { _M_smart.reset(); } 190 191 _Pointer* 192 _M_get() const noexcept 193 { return __builtin_addressof(_M_smart._M_t._M_ptr()); } 194 195 _Smart& _M_smart; 196 }; 197 198 // Partial specialization for std::unique_ptr with replacement deleter. 199 // FIXME: constrain to only match the primary template, 200 // not program-defined specializations of unique_ptr. 201 template<typename _Tp, typename _Del, typename _Del2> 202 struct _Impl<unique_ptr<_Tp, _Del>, 203 typename unique_ptr<_Tp, _Del>::pointer, _Del2> 204 { 205 void 206 _M_out_init() 207 { _M_smart.reset(); } 208 209 _Pointer* 210 _M_get() const noexcept 211 { return __builtin_addressof(_M_smart._M_t._M_ptr()); } 212 213 ~_Impl() 214 { 215 if (_M_smart.get()) 216 _M_smart._M_t._M_deleter() = std::forward<_Del2>(_M_del); 217 } 218 219 _Smart& _M_smart; 220 [[no_unique_address]] _Del2 _M_del; 221 }; 222 223 #if _GLIBCXX_HOSTED 224 // Partial specialization for std::shared_ptr. 225 // This specialization gives direct access to the private member 226 // of the shared_ptr, avoiding the overhead of storing a separate 227 // pointer and then resetting the shared_ptr in the destructor. 228 // A new control block is allocated in the constructor, so that if 229 // allocation fails it doesn't throw an exception from the destructor. 230 template<typename _Tp, typename _Del, typename _Alloc> 231 requires (is_base_of_v<__shared_ptr<_Tp>, shared_ptr<_Tp>>) 232 struct _Impl<shared_ptr<_Tp>, 233 typename shared_ptr<_Tp>::element_type*, _Del, _Alloc> 234 { 235 _Impl(_Smart& __s, _Del __d, _Alloc __a = _Alloc()) 236 : _M_smart(__s) 237 { 238 // We know shared_ptr cannot be used with inout_ptr_t 239 // so we can do all set up here, instead of in _M_out_init(). 240 _M_smart.reset(); 241 242 // Similar to the shared_ptr(Y*, D, A) constructor, except that if 243 // the allocation throws we do not need (or want) to call deleter. 244 typename _Scd::__allocator_type __a2(__a); 245 auto __mem = __a2.allocate(1); 246 ::new (__mem) _Scd(nullptr, std::forward<_Del>(__d), 247 std::forward<_Alloc>(__a)); 248 _M_smart._M_refcount._M_pi = __mem; 249 } 250 251 _Pointer* 252 _M_get() const noexcept 253 { return __builtin_addressof(_M_smart._M_ptr); } 254 255 ~_Impl() 256 { 257 auto& __pi = _M_smart._M_refcount._M_pi; 258 259 if (_Sp __ptr = _M_smart.get()) 260 static_cast<_Scd*>(__pi)->_M_impl._M_ptr = __ptr; 261 else // Destroy the control block manually without invoking deleter. 262 std::__exchange(__pi, nullptr)->_M_destroy(); 263 } 264 265 _Smart& _M_smart; 266 267 using _Sp = typename _Smart::element_type*; 268 using _Scd = _Sp_counted_deleter<_Sp, decay_t<_Del>, 269 remove_cvref_t<_Alloc>, 270 __default_lock_policy>; 271 }; 272 273 // Partial specialization for std::shared_ptr, without custom allocator. 274 template<typename _Tp, typename _Del> 275 requires (is_base_of_v<__shared_ptr<_Tp>, shared_ptr<_Tp>>) 276 struct _Impl<shared_ptr<_Tp>, 277 typename shared_ptr<_Tp>::element_type*, _Del> 278 : _Impl<_Smart, _Pointer, _Del, allocator<void>> 279 { 280 using _Impl<_Smart, _Pointer, _Del, allocator<void>>::_Impl; 281 }; 282 #endif 283 284 using _Impl_t = _Impl<_Smart, _Pointer, _Args...>; 285 286 _Impl_t _M_impl; 287 288 template<typename, typename, typename...> friend class inout_ptr_t; 289 }; 290 291 /// Smart pointer adaptor for functions taking an inout pointer parameter. 292 /** 293 * @tparam _Smart The type of pointer to adapt. 294 * @tparam _Pointer The type of pointer to convert to. 295 * @tparam _Args... Argument types used when resetting the smart pointer. 296 * @since C++23 297 * @headerfile <memory> 298 */ 299 template<typename _Smart, typename _Pointer, typename... _Args> 300 class inout_ptr_t 301 { 302 #if _GLIBCXX_HOSTED 303 static_assert(!__is_shared_ptr<_Smart>, 304 "std::inout_ptr can not be used to wrap std::shared_ptr"); 305 #endif 306 307 public: 308 explicit 309 inout_ptr_t(_Smart& __smart, _Args... __args) 310 : _M_impl{__smart, std::forward<_Args>(__args)...} 311 { 312 if constexpr (requires { _M_impl._M_inout_init(); }) 313 _M_impl._M_inout_init(); 314 } 315 316 inout_ptr_t(const inout_ptr_t&) = delete; 317 318 ~inout_ptr_t() = default; 319 320 operator _Pointer*() const noexcept 321 { return _M_impl._M_get(); } 322 323 operator void**() const noexcept requires (!same_as<_Pointer, void*>) 324 { 325 static_assert(is_pointer_v<_Pointer>); 326 _Pointer* __p = *this; 327 return static_cast<void**>(static_cast<void*>(__p)); 328 } 329 330 private: 331 #if _GLIBCXX_HOSTED 332 // Avoid an invalid instantiation of out_ptr_t<shared_ptr<T>, ...> 333 using _Out_ptr_t 334 = __conditional_t<__is_shared_ptr<_Smart>, 335 out_ptr_t<void*, void*>, 336 out_ptr_t<_Smart, _Pointer, _Args...>>; 337 #else 338 using _Out_ptr_t = out_ptr_t<_Smart, _Pointer, _Args...>; 339 #endif 340 using _Impl_t = typename _Out_ptr_t::_Impl_t; 341 _Impl_t _M_impl; 342 }; 343 344 /// @cond undocumented 345 namespace __detail 346 { 347 // POINTER_OF metafunction 348 template<typename _Tp> 349 consteval auto 350 __pointer_of() 351 { 352 if constexpr (requires { typename _Tp::pointer; }) 353 return type_identity<typename _Tp::pointer>{}; 354 else if constexpr (requires { typename _Tp::element_type; }) 355 return type_identity<typename _Tp::element_type*>{}; 356 else 357 { 358 using _Traits = pointer_traits<_Tp>; 359 if constexpr (requires { typename _Traits::element_type; }) 360 return type_identity<typename _Traits::element_type*>{}; 361 } 362 // else POINTER_OF(S) is not a valid type, return void. 363 } 364 365 // POINTER_OF_OR metafunction 366 template<typename _Smart, typename _Ptr> 367 consteval auto 368 __pointer_of_or() 369 { 370 using _TypeId = decltype(__detail::__pointer_of<_Smart>()); 371 if constexpr (is_void_v<_TypeId>) 372 return type_identity<_Ptr>{}; 373 else 374 return _TypeId{}; 375 } 376 377 // Returns Pointer if !is_void_v<Pointer>, otherwise POINTER_OF(Smart). 378 template<typename _Ptr, typename _Smart> 379 consteval auto 380 __choose_ptr() 381 { 382 if constexpr (!is_void_v<_Ptr>) 383 return type_identity<_Ptr>{}; 384 else 385 return __detail::__pointer_of<_Smart>(); 386 } 387 388 template<typename _Smart, typename _Sp, typename... _Args> 389 concept __resettable = requires (_Smart& __s) { 390 __s.reset(std::declval<_Sp>(), std::declval<_Args>()...); 391 }; 392 } 393 /// @endcond 394 395 /// Adapt a smart pointer for functions taking an output pointer parameter. 396 /** 397 * @tparam _Pointer The type of pointer to convert to. 398 * @param __s The pointer that should take ownership of the result. 399 * @param __args... Arguments to use when resetting the smart pointer. 400 * @return A `std::out_ptr_t` referring to `__s`. 401 * @since C++23 402 * @headerfile <memory> 403 */ 404 template<typename _Pointer = void, typename _Smart, typename... _Args> 405 inline auto 406 out_ptr(_Smart& __s, _Args&&... __args) 407 { 408 using _TypeId = decltype(__detail::__choose_ptr<_Pointer, _Smart>()); 409 static_assert(!is_void_v<_TypeId>, "first argument to std::out_ptr " 410 "must be a pointer-like type"); 411 412 using _Ret = out_ptr_t<_Smart, typename _TypeId::type, _Args&&...>; 413 return _Ret(__s, std::forward<_Args>(__args)...); 414 } 415 416 /// Adapt a smart pointer for functions taking an inout pointer parameter. 417 /** 418 * @tparam _Pointer The type of pointer to convert to. 419 * @param __s The pointer that should take ownership of the result. 420 * @param __args... Arguments to use when resetting the smart pointer. 421 * @return A `std::inout_ptr_t` referring to `__s`. 422 * @since C++23 423 * @headerfile <memory> 424 */ 425 template<typename _Pointer = void, typename _Smart, typename... _Args> 426 inline auto 427 inout_ptr(_Smart& __s, _Args&&... __args) 428 { 429 using _TypeId = decltype(__detail::__choose_ptr<_Pointer, _Smart>()); 430 static_assert(!is_void_v<_TypeId>, "first argument to std::inout_ptr " 431 "must be a pointer-like type"); 432 433 using _Ret = inout_ptr_t<_Smart, typename _TypeId::type, _Args&&...>; 434 return _Ret(__s, std::forward<_Args>(__args)...); 435 } 436 437 /// @cond undocumented 438 template<typename _Smart, typename _Pointer, typename... _Args> 439 template<typename _Smart2, typename _Pointer2, typename... _Args2> 440 inline 441 out_ptr_t<_Smart, _Pointer, _Args...>:: 442 _Impl<_Smart2, _Pointer2, _Args2...>::~_Impl() 443 { 444 using _TypeId = decltype(__detail::__pointer_of_or<_Smart, _Pointer>()); 445 using _Sp = typename _TypeId::type; 446 447 if (!_M_ptr) 448 return; 449 450 _Smart& __s = _M_smart; 451 _Pointer& __p = _M_ptr; 452 453 auto __reset = [&](auto&&... __args) { 454 if constexpr (__detail::__resettable<_Smart, _Sp, _Args...>) 455 __s.reset(static_cast<_Sp>(__p), std::forward<_Args>(__args)...); 456 else if constexpr (is_constructible_v<_Smart, _Sp, _Args...>) 457 __s = _Smart(static_cast<_Sp>(__p), std::forward<_Args>(__args)...); 458 else 459 static_assert(is_constructible_v<_Smart, _Sp, _Args...>); 460 }; 461 462 if constexpr (sizeof...(_Args) >= 2) 463 std::apply(__reset, std::move(_M_args)); 464 else if constexpr (sizeof...(_Args) == 1) 465 __reset(std::get<0>(std::move(_M_args))); 466 else 467 __reset(); 468 } 469 /// @endcond 470 471 _GLIBCXX_END_NAMESPACE_VERSION 472 } // namespace 473 474 #endif // __glibcxx_out_ptr 475 #endif /* _GLIBCXX_OUT_PTR_H */