aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3/include/bits/ptr_traits.h
blob: d3c17652426814d284036dce8c387d3ced41a2d6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
// Pointer Traits -*- C++ -*-

// Copyright (C) 2011-2025 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library.  This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.

// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
// <http://www.gnu.org/licenses/>.

/** @file bits/ptr_traits.h
 *  This is an internal header file, included by other library headers.
 *  Do not attempt to use it directly. @headername{memory}
 */

#ifndef _PTR_TRAITS_H
#define _PTR_TRAITS_H 1

#if __cplusplus >= 201103L

#include <bits/move.h>

#if __cplusplus > 201703L
#include <concepts>
namespace __gnu_debug { struct _Safe_iterator_base; }
#endif

namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION

  /// @cond undocumented

  class __undefined;

  // For a specialization `SomeTemplate<T, Types...>` the member `type` is T,
  // otherwise `type` is `__undefined`.
  template<typename _Tp>
    struct __get_first_arg
    { using type = __undefined; };

  template<template<typename, typename...> class _SomeTemplate, typename _Tp,
           typename... _Types>
    struct __get_first_arg<_SomeTemplate<_Tp, _Types...>>
    { using type = _Tp; };

  // For a specialization `SomeTemplate<T, Args...>` and a type `U` the member
  // `type` is `SomeTemplate<U, Args...>`, otherwise there is no member `type`.
  template<typename _Tp, typename _Up>
    struct __replace_first_arg
    { };

  template<template<typename, typename...> class _SomeTemplate, typename _Up,
           typename _Tp, typename... _Types>
    struct __replace_first_arg<_SomeTemplate<_Tp, _Types...>, _Up>
    { using type = _SomeTemplate<_Up, _Types...>; };

  // Detect the element type of a pointer-like type.
  template<typename _Ptr, typename = void>
    struct __ptr_traits_elem : __get_first_arg<_Ptr>
    { };

  // Use _Ptr::element_type if is a valid type.
#if __cpp_concepts
  template<typename _Ptr> requires requires { typename _Ptr::element_type; }
    struct __ptr_traits_elem<_Ptr, void>
    { using type = typename _Ptr::element_type; };
#else
  template<typename _Ptr>
    struct __ptr_traits_elem<_Ptr, __void_t<typename _Ptr::element_type>>
    { using type = typename _Ptr::element_type; };
#endif

  template<typename _Ptr>
    using __ptr_traits_elem_t = typename __ptr_traits_elem<_Ptr>::type;

  /// @endcond

  // Define pointer_traits<P>::pointer_to.
  template<typename _Ptr, typename _Elt, bool = is_void<_Elt>::value>
    struct __ptr_traits_ptr_to
    {
      using pointer = _Ptr;
      using element_type = _Elt;

      /**
       *  @brief  Obtain a pointer to an object
       *  @param  __r  A reference to an object of type `element_type`
       *  @return `pointer::pointer_to(__r)`
       *  @pre `pointer::pointer_to(__r)` is a valid expression.
      */
      static pointer
      pointer_to(element_type& __r)
#if __cpp_lib_concepts
      requires requires {
	{ pointer::pointer_to(__r) } -> convertible_to<pointer>;
      }
#endif
      { return pointer::pointer_to(__r); }
    };

  // Do not define pointer_traits<P>::pointer_to if element type is void.
  template<typename _Ptr, typename _Elt>
    struct __ptr_traits_ptr_to<_Ptr, _Elt, true>
    { };

  // Partial specialization defining pointer_traits<T*>::pointer_to(T&).
  template<typename _Tp>
    struct __ptr_traits_ptr_to<_Tp*, _Tp, false>
    {
      using pointer = _Tp*;
      using element_type = _Tp;

      /**
       *  @brief  Obtain a pointer to an object
       *  @param  __r  A reference to an object of type `element_type`
       *  @return `addressof(__r)`
      */
      static _GLIBCXX20_CONSTEXPR pointer
      pointer_to(element_type& __r) noexcept
      { return std::addressof(__r); }
    };

  template<typename _Ptr, typename _Elt>
    struct __ptr_traits_impl : __ptr_traits_ptr_to<_Ptr, _Elt>
    {
    private:
      template<typename _Tp>
	using __diff_t = typename _Tp::difference_type;

      template<typename _Tp, typename _Up>
	using __rebind = __type_identity<typename _Tp::template rebind<_Up>>;

    public:
      /// The pointer type.
      using pointer = _Ptr;

      /// The type pointed to.
      using element_type = _Elt;

      /// The type used to represent the difference between two pointers.
      using difference_type = __detected_or_t<ptrdiff_t, __diff_t, _Ptr>;

      /// A pointer to a different type.
      template<typename _Up>
	using rebind = typename __detected_or_t<__replace_first_arg<_Ptr, _Up>,
						__rebind, _Ptr, _Up>::type;
    };

  // _GLIBCXX_RESOLVE_LIB_DEFECTS
  // 3545. std::pointer_traits should be SFINAE-friendly
  template<typename _Ptr>
    struct __ptr_traits_impl<_Ptr, __undefined>
    { };

  /**
   * @brief  Uniform interface to all pointer-like types
   * @headerfile memory
   * @ingroup pointer_abstractions
   * @since C++11
  */
  template<typename _Ptr>
    struct pointer_traits : __ptr_traits_impl<_Ptr, __ptr_traits_elem_t<_Ptr>>
    { };

  /**
   * @brief  Partial specialization for built-in pointers.
   * @headerfile memory
   * @ingroup pointer_abstractions
   * @since C++11
  */
  template<typename _Tp>
    struct pointer_traits<_Tp*> : __ptr_traits_ptr_to<_Tp*, _Tp>
    {
      /// The pointer type
      typedef _Tp* pointer;
      /// The type pointed to
      typedef _Tp  element_type;
      /// Type used to represent the difference between two pointers
      typedef ptrdiff_t difference_type;
      /// A pointer to a different type.
      template<typename _Up> using rebind = _Up*;
    };

  /// Convenience alias for rebinding pointers.
  template<typename _Ptr, typename _Tp>
    using __ptr_rebind = typename pointer_traits<_Ptr>::template rebind<_Tp>;

#ifndef __glibcxx_to_address // C++ < 20
  template<typename _Tp>
    [[__gnu__::__always_inline__]]
    constexpr _Tp*
    __to_address(_Tp* __ptr) noexcept
    {
      static_assert(!std::is_function<_Tp>::value, "std::to_address argument "
		    "must not be a function pointer");
      return __ptr;
    }

  // This should only be used for pointer-like types (e.g. allocator pointers)
  // and (in C++20 and later) for types satisfying std::contiguous_iterator.
  // It should not be used for arbitrary random access iterators, because
  // they might not be contiguous iterators (e.g. deque::iterator isn't).
  template<typename _Ptr>
    constexpr typename std::pointer_traits<_Ptr>::element_type*
    __to_address(const _Ptr& __ptr)
    { return std::__to_address(__ptr.operator->()); }
#else
  /**
   * @brief Obtain address referenced by a pointer to an object
   * @param __ptr A pointer to an object
   * @return @c __ptr
   * @ingroup pointer_abstractions
  */
  template<typename _Tp>
    [[__gnu__::__always_inline__]]
    constexpr _Tp*
    to_address(_Tp* __ptr) noexcept
    {
      static_assert(!is_function_v<_Tp>, "std::to_address argument "
		    "must not be a function pointer");
      return __ptr;
    }

  /**
   * @brief Obtain address referenced by a pointer to an object
   * @param __ptr A pointer to an object
   * @return @c pointer_traits<_Ptr>::to_address(__ptr) if that expression is
             well-formed, otherwise @c to_address(__ptr.operator->())
   * @ingroup pointer_abstractions
  */
  template<typename _Ptr>
    constexpr auto
    to_address(const _Ptr& __ptr) noexcept
    {
      if constexpr (requires { pointer_traits<_Ptr>::to_address(__ptr); })
	return pointer_traits<_Ptr>::to_address(__ptr);
      else if constexpr (is_base_of_v<__gnu_debug::_Safe_iterator_base, _Ptr>)
	return std::to_address(__ptr.base().operator->());
      else
	return std::to_address(__ptr.operator->());
    }

  /// @cond undocumented
  /// Compatibility for use in code that is also compiled as pre-C++20.
  template<typename _Ptr>
    [[__gnu__::__always_inline__]]
    constexpr auto
    __to_address(const _Ptr& __ptr) noexcept
    { return std::to_address(__ptr); }
  /// @endcond
#endif // __glibcxx_to_address

_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std

#endif

#endif