1 // Smart pointer adaptors -*- C++ -*-
3 // Copyright The GNU Toolchain Authors.
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)
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.
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.
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/>.
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}
30 #ifndef _GLIBCXX_OUT_PTR_H
31 #define _GLIBCXX_OUT_PTR_H 1
33 #pragma GCC system_header
35 #include <bits/version.h>
37 #ifdef __glibcxx_out_ptr // C++ >= 23
40 #include <bits/ptr_traits.h>
42 namespace std
_GLIBCXX_VISIBILITY(default)
44 _GLIBCXX_BEGIN_NAMESPACE_VERSION
46 /// Smart pointer adaptor for functions taking an output pointer parameter.
48 * @tparam _Smart The type of pointer to adapt.
49 * @tparam _Pointer The type of pointer to convert to.
50 * @tparam _Args... Argument types used when resetting the smart pointer.
52 * @headerfile <memory>
54 template<typename _Smart
, typename _Pointer
, typename
... _Args
>
58 static_assert(!__is_shared_ptr
<_Smart
> || sizeof...(_Args
) != 0,
59 "a deleter must be used when adapting std::shared_ptr "
65 out_ptr_t(_Smart
& __smart
, _Args
... __args
)
66 : _M_impl
{__smart
, std::forward
<_Args
>(__args
)...}
68 if constexpr (requires
{ _M_impl
._M_out_init(); })
69 _M_impl
._M_out_init();
72 out_ptr_t(const out_ptr_t
&) = delete;
74 ~out_ptr_t() = default;
76 operator _Pointer
*() const noexcept
77 { return _M_impl
._M_get(); }
79 operator void**() const noexcept
requires (!same_as
<_Pointer
, void*>)
81 static_assert(is_pointer_v
<_Pointer
>);
82 _Pointer
* __p
= *this;
83 return static_cast<void**>(static_cast<void*>(__p
));
87 // TODO: Move this to namespace scope? e.g. __detail::_Ptr_adapt_impl
88 template<typename
, typename
, typename
...>
91 // This constructor must not modify __s because out_ptr_t and
92 // inout_ptr_t want to do different things. After construction
93 // they call _M_out_init() or _M_inout_init() respectively.
94 _Impl(_Smart
& __s
, _Args
&&... __args
)
95 : _M_smart(__s
), _M_args(std::forward
<_Args
>(__args
)...)
98 // Called by out_ptr_t to clear the smart pointer before using it.
102 // _GLIBCXX_RESOLVE_LIB_DEFECTS
103 // 3734. Inconsistency in inout_ptr and out_ptr for empty case
104 if constexpr (requires
{ _M_smart
.reset(); })
110 // Called by inout_ptr_t to copy the smart pointer's value
111 // to the pointer that is returned from _M_get().
114 { _M_ptr
= _M_smart
.release(); }
116 // The pointer value returned by operator Pointer*().
119 { return __builtin_addressof(const_cast<_Pointer
&>(_M_ptr
)); }
121 // Finalize the effects on the smart pointer.
122 ~_Impl() noexcept(false);
125 [[no_unique_address
]] _Pointer _M_ptr
{};
126 [[no_unique_address
]] tuple
<_Args
...> _M_args
;
129 // Partial specialization for raw pointers.
130 template<typename _Tp
>
131 struct _Impl
<_Tp
*, _Tp
*>
143 { return __builtin_addressof(const_cast<_Tp
*&>(_M_p
)); }
148 // Partial specialization for raw pointers, with conversion.
149 template<typename _Tp
, typename _Ptr
> requires (!is_same_v
<_Ptr
, _Tp
*>)
150 struct _Impl
<_Tp
*, _Ptr
>
167 { return __builtin_addressof(const_cast<_Pointer
&>(_M_ptr
)); }
169 ~_Impl() { _M_p
= static_cast<_Tp
*>(_M_ptr
); }
175 // Partial specialization for std::unique_ptr.
176 // This specialization gives direct access to the private member
177 // of the unique_ptr, avoiding the overhead of storing a separate
178 // pointer and then resetting the unique_ptr in the destructor.
179 // FIXME: constrain to only match the primary template,
180 // not program-defined specializations of unique_ptr.
181 template<typename _Tp
, typename _Del
>
182 struct _Impl
<unique_ptr
<_Tp
, _Del
>,
183 typename unique_ptr
<_Tp
, _Del
>::pointer
>
187 { _M_smart
.reset(); }
190 _M_get() const noexcept
191 { return __builtin_addressof(_M_smart
._M_t
._M_ptr()); }
196 // Partial specialization for std::unique_ptr with replacement deleter.
197 // FIXME: constrain to only match the primary template,
198 // not program-defined specializations of unique_ptr.
199 template<typename _Tp
, typename _Del
, typename _Del2
>
200 struct _Impl
<unique_ptr
<_Tp
, _Del
>,
201 typename unique_ptr
<_Tp
, _Del
>::pointer
, _Del2
>
205 { _M_smart
.reset(); }
208 _M_get() const noexcept
209 { return __builtin_addressof(_M_smart
._M_t
._M_ptr()); }
214 _M_smart
._M_t
._M_deleter() = std::forward
<_Del2
>(_M_del
);
218 [[no_unique_address
]] _Del2 _M_del
;
222 // Partial specialization for std::shared_ptr.
223 // This specialization gives direct access to the private member
224 // of the shared_ptr, avoiding the overhead of storing a separate
225 // pointer and then resetting the shared_ptr in the destructor.
226 // A new control block is allocated in the constructor, so that if
227 // allocation fails it doesn't throw an exception from the destructor.
228 template<typename _Tp
, typename _Del
, typename _Alloc
>
229 requires (is_base_of_v
<__shared_ptr
<_Tp
>, shared_ptr
<_Tp
>>)
230 struct _Impl
<shared_ptr
<_Tp
>,
231 typename shared_ptr
<_Tp
>::element_type
*, _Del
, _Alloc
>
233 _Impl(_Smart
& __s
, _Del __d
, _Alloc __a
= _Alloc())
236 // We know shared_ptr cannot be used with inout_ptr_t
237 // so we can do all set up here, instead of in _M_out_init().
240 // Similar to the shared_ptr(Y*, D, A) constructor, except that if
241 // the allocation throws we do not need (or want) to call deleter.
242 typename
_Scd::__allocator_type
__a2(__a
);
243 auto __mem
= __a2
.allocate(1);
244 ::new (__mem
) _Scd(nullptr, std::forward
<_Del
>(__d
),
245 std::forward
<_Alloc
>(__a
));
246 _M_smart
._M_refcount
._M_pi
= __mem
;
250 _M_get() const noexcept
251 { return __builtin_addressof(_M_smart
._M_ptr
); }
255 auto& __pi
= _M_smart
._M_refcount
._M_pi
;
257 if (_Sp __ptr
= _M_smart
.get())
258 static_cast<_Scd
*>(__pi
)->_M_impl
._M_ptr
= __ptr
;
259 else // Destroy the control block manually without invoking deleter.
260 std::__exchange(__pi
, nullptr)->_M_destroy();
265 using _Sp
= typename
_Smart::element_type
*;
266 using _Scd
= _Sp_counted_deleter
<_Sp
, decay_t
<_Del
>,
267 remove_cvref_t
<_Alloc
>,
268 __default_lock_policy
>;
271 // Partial specialization for std::shared_ptr, without custom allocator.
272 template<typename _Tp
, typename _Del
>
273 requires (is_base_of_v
<__shared_ptr
<_Tp
>, shared_ptr
<_Tp
>>)
274 struct _Impl
<shared_ptr
<_Tp
>,
275 typename shared_ptr
<_Tp
>::element_type
*, _Del
>
276 : _Impl
<_Smart
, _Pointer
, _Del
, allocator
<void>>
278 using _Impl
<_Smart
, _Pointer
, _Del
, allocator
<void>>::_Impl
;
282 using _Impl_t
= _Impl
<_Smart
, _Pointer
, _Args
...>;
286 template<typename
, typename
, typename
...> friend class inout_ptr_t
;
289 /// Smart pointer adaptor for functions taking an inout pointer parameter.
291 * @tparam _Smart The type of pointer to adapt.
292 * @tparam _Pointer The type of pointer to convert to.
293 * @tparam _Args... Argument types used when resetting the smart pointer.
295 * @headerfile <memory>
297 template<typename _Smart
, typename _Pointer
, typename
... _Args
>
301 static_assert(!__is_shared_ptr
<_Smart
>,
302 "std::inout_ptr can not be used to wrap std::shared_ptr");
307 inout_ptr_t(_Smart
& __smart
, _Args
... __args
)
308 : _M_impl
{__smart
, std::forward
<_Args
>(__args
)...}
310 if constexpr (requires
{ _M_impl
._M_inout_init(); })
311 _M_impl
._M_inout_init();
314 inout_ptr_t(const inout_ptr_t
&) = delete;
316 ~inout_ptr_t() = default;
318 operator _Pointer
*() const noexcept
319 { return _M_impl
._M_get(); }
321 operator void**() const noexcept
requires (!same_as
<_Pointer
, void*>)
323 static_assert(is_pointer_v
<_Pointer
>);
324 _Pointer
* __p
= *this;
325 return static_cast<void**>(static_cast<void*>(__p
));
330 // Avoid an invalid instantiation of out_ptr_t<shared_ptr<T>, ...>
332 = __conditional_t
<__is_shared_ptr
<_Smart
>,
333 out_ptr_t
<void*, void*>,
334 out_ptr_t
<_Smart
, _Pointer
, _Args
...>>;
336 using _Out_ptr_t
= out_ptr_t
<_Smart
, _Pointer
, _Args
...>;
338 using _Impl_t
= typename
_Out_ptr_t::_Impl_t
;
342 /// @cond undocumented
345 // POINTER_OF metafunction
346 template<typename _Tp
>
350 if constexpr (requires
{ typename
_Tp::pointer
; })
351 return type_identity
<typename
_Tp::pointer
>{};
352 else if constexpr (requires
{ typename
_Tp::element_type
; })
353 return type_identity
<typename
_Tp::element_type
*>{};
356 using _Traits
= pointer_traits
<_Tp
>;
357 if constexpr (requires
{ typename
_Traits::element_type
; })
358 return type_identity
<typename
_Traits::element_type
*>{};
360 // else POINTER_OF(S) is not a valid type, return void.
363 // POINTER_OF_OR metafunction
364 template<typename _Smart
, typename _Ptr
>
368 using _TypeId
= decltype(__detail::__pointer_of
<_Smart
>());
369 if constexpr (is_void_v
<_TypeId
>)
370 return type_identity
<_Ptr
>{};
375 // Returns Pointer if !is_void_v<Pointer>, otherwise POINTER_OF(Smart).
376 template<typename _Ptr
, typename _Smart
>
380 if constexpr (!is_void_v
<_Ptr
>)
381 return type_identity
<_Ptr
>{};
383 return __detail::__pointer_of
<_Smart
>();
386 template<typename _Smart
, typename _Sp
, typename
... _Args
>
387 concept __resettable
= requires (_Smart
& __s
) {
388 __s
.reset(std::declval
<_Sp
>(), std::declval
<_Args
>()...);
393 /// Adapt a smart pointer for functions taking an output pointer parameter.
395 * @tparam _Pointer The type of pointer to convert to.
396 * @param __s The pointer that should take ownership of the result.
397 * @param __args... Arguments to use when resetting the smart pointer.
398 * @return A std::inout_ptr_t referring to `__s`.
400 * @headerfile <memory>
402 template<typename _Pointer
= void, typename _Smart
, typename
... _Args
>
404 out_ptr(_Smart
& __s
, _Args
&&... __args
)
406 using _TypeId
= decltype(__detail::__choose_ptr
<_Pointer
, _Smart
>());
407 static_assert(!is_void_v
<_TypeId
>, "first argument to std::out_ptr "
408 "must be a pointer-like type");
410 using _Ret
= out_ptr_t
<_Smart
, typename
_TypeId::type
, _Args
&&...>;
411 return _Ret(__s
, std::forward
<_Args
>(__args
)...);
414 /// Adapt a smart pointer for functions taking an inout pointer parameter.
416 * @tparam _Pointer The type of pointer to convert to.
417 * @param __s The pointer that should take ownership of the result.
418 * @param __args... Arguments to use when resetting the smart pointer.
419 * @return A std::inout_ptr_t referring to `__s`.
421 * @headerfile <memory>
423 template<typename _Pointer
= void, typename _Smart
, typename
... _Args
>
425 inout_ptr(_Smart
& __s
, _Args
&&... __args
)
427 using _TypeId
= decltype(__detail::__choose_ptr
<_Pointer
, _Smart
>());
428 static_assert(!is_void_v
<_TypeId
>, "first argument to std::inout_ptr "
429 "must be a pointer-like type");
431 using _Ret
= inout_ptr_t
<_Smart
, typename
_TypeId::type
, _Args
&&...>;
432 return _Ret(__s
, std::forward
<_Args
>(__args
)...);
435 /// @cond undocumented
436 template<typename _Smart
, typename _Pointer
, typename
... _Args
>
437 template<typename _Smart2
, typename _Pointer2
, typename
... _Args2
>
439 out_ptr_t
<_Smart
, _Pointer
, _Args
...>::
440 _Impl
<_Smart2
, _Pointer2
, _Args2
...>::~_Impl()
442 using _TypeId
= decltype(__detail::__pointer_of_or
<_Smart
, _Pointer
>());
443 using _Sp
= typename
_TypeId::type
;
448 _Smart
& __s
= _M_smart
;
449 _Pointer
& __p
= _M_ptr
;
451 auto __reset
= [&](auto&&... __args
) {
452 if constexpr (__detail::__resettable
<_Smart
, _Sp
, _Args
...>)
453 __s
.reset(static_cast<_Sp
>(__p
), std::forward
<_Args
>(__args
)...);
454 else if constexpr (is_constructible_v
<_Smart
, _Sp
, _Args
...>)
455 __s
= _Smart(static_cast<_Sp
>(__p
), std::forward
<_Args
>(__args
)...);
457 static_assert(is_constructible_v
<_Smart
, _Sp
, _Args
...>);
460 if constexpr (sizeof...(_Args
) >= 2)
461 std::apply(__reset
, std::move(_M_args
));
462 else if constexpr (sizeof...(_Args
) == 1)
463 __reset(std::get
<0>(std::move(_M_args
)));
469 _GLIBCXX_END_NAMESPACE_VERSION
472 #endif // __glibcxx_out_ptr
473 #endif /* _GLIBCXX_OUT_PTR_H */