1// -*- C++ -*-
2//===----------------------------------------------------------------------===//
3//
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
7//
8//===----------------------------------------------------------------------===//
9
10#ifndef _LIBCPP___MEMORY_POINTER_TRAITS_H
11#define _LIBCPP___MEMORY_POINTER_TRAITS_H
12
13#include <__config>
14#include <__memory/addressof.h>
15#include <__type_traits/conditional.h>
16#include <__type_traits/conjunction.h>
17#include <__type_traits/decay.h>
18#include <__type_traits/is_class.h>
19#include <__type_traits/is_function.h>
20#include <__type_traits/is_void.h>
21#include <__type_traits/void_t.h>
22#include <__utility/declval.h>
23#include <cstddef>
24
25#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
26#  pragma GCC system_header
27#endif
28
29_LIBCPP_BEGIN_NAMESPACE_STD
30
31template <class _Tp, class = void>
32struct __has_element_type : false_type {};
33
34template <class _Tp>
35struct __has_element_type<_Tp, __void_t<typename _Tp::element_type> > : true_type {};
36
37template <class _Ptr, bool = __has_element_type<_Ptr>::value>
38struct __pointer_traits_element_type;
39
40template <class _Ptr>
41struct __pointer_traits_element_type<_Ptr, true>
42{
43    typedef _LIBCPP_NODEBUG typename _Ptr::element_type type;
44};
45
46template <template <class, class...> class _Sp, class _Tp, class ..._Args>
47struct __pointer_traits_element_type<_Sp<_Tp, _Args...>, true>
48{
49    typedef _LIBCPP_NODEBUG typename _Sp<_Tp, _Args...>::element_type type;
50};
51
52template <template <class, class...> class _Sp, class _Tp, class ..._Args>
53struct __pointer_traits_element_type<_Sp<_Tp, _Args...>, false>
54{
55    typedef _LIBCPP_NODEBUG _Tp type;
56};
57
58template <class _Tp, class = void>
59struct __has_difference_type : false_type {};
60
61template <class _Tp>
62struct __has_difference_type<_Tp, __void_t<typename _Tp::difference_type> > : true_type {};
63
64template <class _Ptr, bool = __has_difference_type<_Ptr>::value>
65struct __pointer_traits_difference_type
66{
67    typedef _LIBCPP_NODEBUG ptrdiff_t type;
68};
69
70template <class _Ptr>
71struct __pointer_traits_difference_type<_Ptr, true>
72{
73    typedef _LIBCPP_NODEBUG typename _Ptr::difference_type type;
74};
75
76template <class _Tp, class _Up>
77struct __has_rebind
78{
79private:
80    template <class _Xp> static false_type __test(...);
81    _LIBCPP_SUPPRESS_DEPRECATED_PUSH
82    template <class _Xp> static true_type __test(typename _Xp::template rebind<_Up>* = 0);
83    _LIBCPP_SUPPRESS_DEPRECATED_POP
84public:
85    static const bool value = decltype(__test<_Tp>(0))::value;
86};
87
88template <class _Tp, class _Up, bool = __has_rebind<_Tp, _Up>::value>
89struct __pointer_traits_rebind
90{
91#ifndef _LIBCPP_CXX03_LANG
92    typedef _LIBCPP_NODEBUG typename _Tp::template rebind<_Up> type;
93#else
94    typedef _LIBCPP_NODEBUG typename _Tp::template rebind<_Up>::other type;
95#endif
96};
97
98template <template <class, class...> class _Sp, class _Tp, class ..._Args, class _Up>
99struct __pointer_traits_rebind<_Sp<_Tp, _Args...>, _Up, true>
100{
101#ifndef _LIBCPP_CXX03_LANG
102    typedef _LIBCPP_NODEBUG typename _Sp<_Tp, _Args...>::template rebind<_Up> type;
103#else
104    typedef _LIBCPP_NODEBUG typename _Sp<_Tp, _Args...>::template rebind<_Up>::other type;
105#endif
106};
107
108template <template <class, class...> class _Sp, class _Tp, class ..._Args, class _Up>
109struct __pointer_traits_rebind<_Sp<_Tp, _Args...>, _Up, false>
110{
111    typedef _Sp<_Up, _Args...> type;
112};
113
114template <class _Ptr>
115struct _LIBCPP_TEMPLATE_VIS pointer_traits
116{
117    typedef _Ptr                                                     pointer;
118    typedef typename __pointer_traits_element_type<pointer>::type    element_type;
119    typedef typename __pointer_traits_difference_type<pointer>::type difference_type;
120
121#ifndef _LIBCPP_CXX03_LANG
122    template <class _Up> using rebind = typename __pointer_traits_rebind<pointer, _Up>::type;
123#else
124    template <class _Up> struct rebind
125        {typedef typename __pointer_traits_rebind<pointer, _Up>::type other;};
126#endif // _LIBCPP_CXX03_LANG
127
128private:
129    struct __nat {};
130public:
131    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
132    static pointer pointer_to(__conditional_t<is_void<element_type>::value, __nat, element_type>& __r)
133        {return pointer::pointer_to(__r);}
134};
135
136template <class _Tp>
137struct _LIBCPP_TEMPLATE_VIS pointer_traits<_Tp*>
138{
139    typedef _Tp*      pointer;
140    typedef _Tp       element_type;
141    typedef ptrdiff_t difference_type;
142
143#ifndef _LIBCPP_CXX03_LANG
144    template <class _Up> using rebind = _Up*;
145#else
146    template <class _Up> struct rebind {typedef _Up* other;};
147#endif
148
149private:
150    struct __nat {};
151public:
152    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
153    static pointer pointer_to(__conditional_t<is_void<element_type>::value, __nat, element_type>& __r) _NOEXCEPT
154        {return _VSTD::addressof(__r);}
155};
156
157#ifndef _LIBCPP_CXX03_LANG
158template <class _From, class _To>
159using __rebind_pointer_t = typename pointer_traits<_From>::template rebind<_To>;
160#else
161template <class _From, class _To>
162using __rebind_pointer_t = typename pointer_traits<_From>::template rebind<_To>::other;
163#endif
164
165// to_address
166
167template <class _Pointer, class = void>
168struct __to_address_helper;
169
170template <class _Tp>
171_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
172_Tp* __to_address(_Tp* __p) _NOEXCEPT {
173    static_assert(!is_function<_Tp>::value, "_Tp is a function type");
174    return __p;
175}
176
177template <class _Pointer, class = void>
178struct _HasToAddress : false_type {};
179
180template <class _Pointer>
181struct _HasToAddress<_Pointer,
182    decltype((void)pointer_traits<_Pointer>::to_address(std::declval<const _Pointer&>()))
183> : true_type {};
184
185template <class _Pointer, class = void>
186struct _HasArrow : false_type {};
187
188template <class _Pointer>
189struct _HasArrow<_Pointer,
190    decltype((void)std::declval<const _Pointer&>().operator->())
191> : true_type {};
192
193template <class _Pointer>
194struct _IsFancyPointer {
195  static const bool value = _HasArrow<_Pointer>::value || _HasToAddress<_Pointer>::value;
196};
197
198// enable_if is needed here to avoid instantiating checks for fancy pointers on raw pointers
199template <class _Pointer, class = __enable_if_t<
200    _And<is_class<_Pointer>, _IsFancyPointer<_Pointer> >::value
201> >
202_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
203typename decay<decltype(__to_address_helper<_Pointer>::__call(std::declval<const _Pointer&>()))>::type
204__to_address(const _Pointer& __p) _NOEXCEPT {
205    return __to_address_helper<_Pointer>::__call(__p);
206}
207
208template <class _Pointer, class>
209struct __to_address_helper {
210    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
211    static decltype(_VSTD::__to_address(std::declval<const _Pointer&>().operator->()))
212    __call(const _Pointer& __p) _NOEXCEPT {
213        return _VSTD::__to_address(__p.operator->());
214    }
215};
216
217template <class _Pointer>
218struct __to_address_helper<_Pointer, decltype((void)pointer_traits<_Pointer>::to_address(std::declval<const _Pointer&>()))> {
219    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
220    static decltype(pointer_traits<_Pointer>::to_address(std::declval<const _Pointer&>()))
221    __call(const _Pointer& __p) _NOEXCEPT {
222        return pointer_traits<_Pointer>::to_address(__p);
223    }
224};
225
226#if _LIBCPP_STD_VER > 17
227template <class _Tp>
228inline _LIBCPP_INLINE_VISIBILITY constexpr
229auto to_address(_Tp *__p) noexcept {
230    return _VSTD::__to_address(__p);
231}
232
233template <class _Pointer>
234inline _LIBCPP_INLINE_VISIBILITY constexpr
235auto to_address(const _Pointer& __p) noexcept -> decltype(std::__to_address(__p)) {
236    return _VSTD::__to_address(__p);
237}
238#endif
239
240_LIBCPP_END_NAMESPACE_STD
241
242#endif // _LIBCPP___MEMORY_POINTER_TRAITS_H
243