2 //===----------------------------------------------------------------------===//
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
8 //===----------------------------------------------------------------------===//
10 #ifndef _LIBCPP___MEMORY_POINTER_TRAITS_H
11 #define _LIBCPP___MEMORY_POINTER_TRAITS_H
14 #include <__cstddef/ptrdiff_t.h>
15 #include <__memory/addressof.h>
16 #include <__type_traits/conditional.h>
17 #include <__type_traits/conjunction.h>
18 #include <__type_traits/decay.h>
19 #include <__type_traits/enable_if.h>
20 #include <__type_traits/integral_constant.h>
21 #include <__type_traits/is_class.h>
22 #include <__type_traits/is_function.h>
23 #include <__type_traits/is_void.h>
24 #include <__type_traits/void_t.h>
25 #include <__utility/declval.h>
26 #include <__utility/forward.h>
28 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
29 # pragma GCC system_header
33 #include <__undef_macros>
35 _LIBCPP_BEGIN_NAMESPACE_STD
38 #define _LIBCPP_CLASS_TRAITS_HAS_XXX(NAME, PROPERTY) \
39 template <class _Tp, class = void> \
40 struct NAME : false_type {}; \
41 template <class _Tp> \
42 struct NAME<_Tp, __void_t<typename _Tp::PROPERTY> > : true_type {}
45 _LIBCPP_CLASS_TRAITS_HAS_XXX(__has_pointer
, pointer
);
46 _LIBCPP_CLASS_TRAITS_HAS_XXX(__has_element_type
, element_type
);
48 template <class _Ptr
, bool = __has_element_type
<_Ptr
>::value
>
49 struct __pointer_traits_element_type
{};
52 struct __pointer_traits_element_type
<_Ptr
, true> {
53 typedef _LIBCPP_NODEBUG typename
_Ptr::element_type type
;
56 template <template <class, class...> class _Sp
, class _Tp
, class... _Args
>
57 struct __pointer_traits_element_type
<_Sp
<_Tp
, _Args
...>, true> {
58 typedef _LIBCPP_NODEBUG typename _Sp
<_Tp
, _Args
...>::element_type type
;
61 template <template <class, class...> class _Sp
, class _Tp
, class... _Args
>
62 struct __pointer_traits_element_type
<_Sp
<_Tp
, _Args
...>, false> {
63 typedef _LIBCPP_NODEBUG _Tp type
;
66 template <class _Tp
, class = void>
67 struct __has_difference_type
: false_type
{};
70 struct __has_difference_type
<_Tp
, __void_t
<typename
_Tp::difference_type
> > : true_type
{};
72 template <class _Ptr
, bool = __has_difference_type
<_Ptr
>::value
>
73 struct __pointer_traits_difference_type
{
74 typedef _LIBCPP_NODEBUG
ptrdiff_t type
;
78 struct __pointer_traits_difference_type
<_Ptr
, true> {
79 typedef _LIBCPP_NODEBUG typename
_Ptr::difference_type type
;
82 template <class _Tp
, class _Up
>
86 static false_type
__test(...);
87 _LIBCPP_SUPPRESS_DEPRECATED_PUSH
89 static true_type
__test(typename
_Xp::template rebind
<_Up
>* = 0);
90 _LIBCPP_SUPPRESS_DEPRECATED_POP
93 static const bool value
= decltype(__test
<_Tp
>(0))::value
;
96 template <class _Tp
, class _Up
, bool = __has_rebind
<_Tp
, _Up
>::value
>
97 struct __pointer_traits_rebind
{
98 #ifndef _LIBCPP_CXX03_LANG
99 typedef _LIBCPP_NODEBUG typename
_Tp::template rebind
<_Up
> type
;
101 typedef _LIBCPP_NODEBUG typename
_Tp::template rebind
<_Up
>::other type
;
105 template <template <class, class...> class _Sp
, class _Tp
, class... _Args
, class _Up
>
106 struct __pointer_traits_rebind
<_Sp
<_Tp
, _Args
...>, _Up
, true> {
107 #ifndef _LIBCPP_CXX03_LANG
108 typedef _LIBCPP_NODEBUG typename _Sp
<_Tp
, _Args
...>::template rebind
<_Up
> type
;
110 typedef _LIBCPP_NODEBUG typename _Sp
<_Tp
, _Args
...>::template rebind
<_Up
>::other type
;
114 template <template <class, class...> class _Sp
, class _Tp
, class... _Args
, class _Up
>
115 struct __pointer_traits_rebind
<_Sp
<_Tp
, _Args
...>, _Up
, false> {
116 typedef _Sp
<_Up
, _Args
...> type
;
119 template <class _Ptr
, class = void>
120 struct __pointer_traits_impl
{};
122 template <class _Ptr
>
123 struct __pointer_traits_impl
<_Ptr
, __void_t
<typename __pointer_traits_element_type
<_Ptr
>::type
> > {
124 typedef _Ptr pointer
;
125 typedef typename __pointer_traits_element_type
<pointer
>::type element_type
;
126 typedef typename __pointer_traits_difference_type
<pointer
>::type difference_type
;
128 #ifndef _LIBCPP_CXX03_LANG
130 using rebind
= typename __pointer_traits_rebind
<pointer
, _Up
>::type
;
134 typedef typename __pointer_traits_rebind
<pointer
, _Up
>::type other
;
136 #endif // _LIBCPP_CXX03_LANG
142 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
static pointer
143 pointer_to(__conditional_t
<is_void
<element_type
>::value
, __nat
, element_type
>& __r
) {
144 return pointer::pointer_to(__r
);
148 template <class _Ptr
>
149 struct _LIBCPP_TEMPLATE_VIS pointer_traits
: __pointer_traits_impl
<_Ptr
> {};
152 struct _LIBCPP_TEMPLATE_VIS pointer_traits
<_Tp
*> {
153 typedef _Tp
* pointer
;
154 typedef _Tp element_type
;
155 typedef ptrdiff_t difference_type
;
157 #ifndef _LIBCPP_CXX03_LANG
171 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
static pointer
172 pointer_to(__conditional_t
<is_void
<element_type
>::value
, __nat
, element_type
>& __r
) _NOEXCEPT
{
173 return std::addressof(__r
);
177 #ifndef _LIBCPP_CXX03_LANG
178 template <class _From
, class _To
>
179 using __rebind_pointer_t
= typename pointer_traits
<_From
>::template rebind
<_To
>;
181 template <class _From
, class _To
>
182 using __rebind_pointer_t
= typename pointer_traits
<_From
>::template rebind
<_To
>::other
;
187 template <class _Pointer
, class = void>
188 struct __to_address_helper
;
191 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Tp
* __to_address(_Tp
* __p
) _NOEXCEPT
{
192 static_assert(!is_function
<_Tp
>::value
, "_Tp is a function type");
196 template <class _Pointer
, class = void>
197 struct _HasToAddress
: false_type
{};
199 template <class _Pointer
>
200 struct _HasToAddress
<_Pointer
, decltype((void)pointer_traits
<_Pointer
>::to_address(std::declval
<const _Pointer
&>())) >
203 template <class _Pointer
, class = void>
204 struct _HasArrow
: false_type
{};
206 template <class _Pointer
>
207 struct _HasArrow
<_Pointer
, decltype((void)std::declval
<const _Pointer
&>().operator->()) > : true_type
{};
209 template <class _Pointer
>
210 struct _IsFancyPointer
{
211 static const bool value
= _HasArrow
<_Pointer
>::value
|| _HasToAddress
<_Pointer
>::value
;
214 // enable_if is needed here to avoid instantiating checks for fancy pointers on raw pointers
215 template <class _Pointer
, __enable_if_t
< _And
<is_class
<_Pointer
>, _IsFancyPointer
<_Pointer
> >::value
, int> = 0>
216 _LIBCPP_HIDE_FROM_ABI
217 _LIBCPP_CONSTEXPR __decay_t
<decltype(__to_address_helper
<_Pointer
>::__call(std::declval
<const _Pointer
&>()))>
218 __to_address(const _Pointer
& __p
) _NOEXCEPT
{
219 return __to_address_helper
<_Pointer
>::__call(__p
);
222 template <class _Pointer
, class>
223 struct __to_address_helper
{
224 _LIBCPP_HIDE_FROM_ABI
225 _LIBCPP_CONSTEXPR
static decltype(std::__to_address(std::declval
<const _Pointer
&>().operator->()))
226 __call(const _Pointer
& __p
) _NOEXCEPT
{
227 return std::__to_address(__p
.operator->());
231 template <class _Pointer
>
232 struct __to_address_helper
<_Pointer
,
233 decltype((void)pointer_traits
<_Pointer
>::to_address(std::declval
<const _Pointer
&>()))> {
234 _LIBCPP_HIDE_FROM_ABI
235 _LIBCPP_CONSTEXPR
static decltype(pointer_traits
<_Pointer
>::to_address(std::declval
<const _Pointer
&>()))
236 __call(const _Pointer
& __p
) _NOEXCEPT
{
237 return pointer_traits
<_Pointer
>::to_address(__p
);
241 #if _LIBCPP_STD_VER >= 20
243 inline _LIBCPP_HIDE_FROM_ABI
constexpr auto to_address(_Tp
* __p
) noexcept
{
244 return std::__to_address(__p
);
247 template <class _Pointer
>
248 inline _LIBCPP_HIDE_FROM_ABI
constexpr auto
249 to_address(const _Pointer
& __p
) noexcept
-> decltype(std::__to_address(__p
)) {
250 return std::__to_address(__p
);
254 #if _LIBCPP_STD_VER >= 23
257 struct __pointer_of
{};
260 requires(__has_pointer
<_Tp
>::value
)
261 struct __pointer_of
<_Tp
> {
262 using type
= typename
_Tp::pointer
;
266 requires(!__has_pointer
<_Tp
>::value
&& __has_element_type
<_Tp
>::value
)
267 struct __pointer_of
<_Tp
> {
268 using type
= typename
_Tp::element_type
*;
272 requires(!__has_pointer
<_Tp
>::value
&& !__has_element_type
<_Tp
>::value
&&
273 __has_element_type
<pointer_traits
<_Tp
>>::value
)
274 struct __pointer_of
<_Tp
> {
275 using type
= typename pointer_traits
<_Tp
>::element_type
*;
278 template <typename _Tp
>
279 using __pointer_of_t
= typename __pointer_of
<_Tp
>::type
;
281 template <class _Tp
, class _Up
>
282 struct __pointer_of_or
{
283 using type _LIBCPP_NODEBUG
= _Up
;
286 template <class _Tp
, class _Up
>
287 requires requires
{ typename __pointer_of_t
<_Tp
>; }
288 struct __pointer_of_or
<_Tp
, _Up
> {
289 using type _LIBCPP_NODEBUG
= __pointer_of_t
<_Tp
>;
292 template <typename _Tp
, typename _Up
>
293 using __pointer_of_or_t
= typename __pointer_of_or
<_Tp
, _Up
>::type
;
295 template <class _Smart
>
296 concept __resettable_smart_pointer
= requires(_Smart __s
) { __s
.reset(); };
298 template <class _Smart
, class _Pointer
, class... _Args
>
299 concept __resettable_smart_pointer_with_args
= requires(_Smart __s
, _Pointer __p
, _Args
... __args
) {
300 __s
.reset(static_cast<__pointer_of_or_t
<_Smart
, _Pointer
>>(__p
), std::forward
<_Args
>(__args
)...);
305 _LIBCPP_END_NAMESPACE_STD
309 #endif // _LIBCPP___MEMORY_POINTER_TRAITS_H