1// Pointer Traits -*- C++ -*-
2
3// Copyright (C) 2011-2020 Free Software Foundation, Inc.
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 bits/ptr_traits.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 _PTR_TRAITS_H
31#define _PTR_TRAITS_H 1
32
33#if __cplusplus >= 201103L
34
35#include <bits/move.h>
36
37#if __cplusplus > 201703L
38#define __cpp_lib_constexpr_memory 201811L
39namespace __gnu_debug { struct _Safe_iterator_base; }
40#endif
41
42namespace std _GLIBCXX_VISIBILITY(default)
43{
44_GLIBCXX_BEGIN_NAMESPACE_VERSION
45
46  class __undefined;
47
48  // Given Template<T, ...> return T, otherwise invalid.
49  template<typename _Tp>
50    struct __get_first_arg
51    { using type = __undefined; };
52
53  template<template<typename, typename...> class _Template, typename _Tp,
54           typename... _Types>
55    struct __get_first_arg<_Template<_Tp, _Types...>>
56    { using type = _Tp; };
57
58  template<typename _Tp>
59    using __get_first_arg_t = typename __get_first_arg<_Tp>::type;
60
61  // Given Template<T, ...> and U return Template<U, ...>, otherwise invalid.
62  template<typename _Tp, typename _Up>
63    struct __replace_first_arg
64    { };
65
66  template<template<typename, typename...> class _Template, typename _Up,
67           typename _Tp, typename... _Types>
68    struct __replace_first_arg<_Template<_Tp, _Types...>, _Up>
69    { using type = _Template<_Up, _Types...>; };
70
71  template<typename _Tp, typename _Up>
72    using __replace_first_arg_t = typename __replace_first_arg<_Tp, _Up>::type;
73
74  template<typename _Tp>
75    using __make_not_void
76      = typename conditional<is_void<_Tp>::value, __undefined, _Tp>::type;
77
78  /**
79   * @brief  Uniform interface to all pointer-like types
80   * @ingroup pointer_abstractions
81  */
82  template<typename _Ptr>
83    struct pointer_traits
84    {
85    private:
86      template<typename _Tp>
87	using __element_type = typename _Tp::element_type;
88
89      template<typename _Tp>
90	using __difference_type = typename _Tp::difference_type;
91
92      template<typename _Tp, typename _Up, typename = void>
93	struct __rebind : __replace_first_arg<_Tp, _Up> { };
94
95      template<typename _Tp, typename _Up>
96	struct __rebind<_Tp, _Up, __void_t<typename _Tp::template rebind<_Up>>>
97	{ using type = typename _Tp::template rebind<_Up>; };
98
99    public:
100      /// The pointer type.
101      using pointer = _Ptr;
102
103      /// The type pointed to.
104      using element_type
105	= __detected_or_t<__get_first_arg_t<_Ptr>, __element_type, _Ptr>;
106
107      /// The type used to represent the difference between two pointers.
108      using difference_type
109	= __detected_or_t<ptrdiff_t, __difference_type, _Ptr>;
110
111      /// A pointer to a different type.
112      template<typename _Up>
113        using rebind = typename __rebind<_Ptr, _Up>::type;
114
115      static _Ptr
116      pointer_to(__make_not_void<element_type>& __e)
117      { return _Ptr::pointer_to(__e); }
118
119      static_assert(!is_same<element_type, __undefined>::value,
120	  "pointer type defines element_type or is like SomePointer<T, Args>");
121    };
122
123  /**
124   * @brief  Partial specialization for built-in pointers.
125   * @ingroup pointer_abstractions
126  */
127  template<typename _Tp>
128    struct pointer_traits<_Tp*>
129    {
130      /// The pointer type
131      typedef _Tp* pointer;
132      /// The type pointed to
133      typedef _Tp  element_type;
134      /// Type used to represent the difference between two pointers
135      typedef ptrdiff_t difference_type;
136
137      template<typename _Up>
138        using rebind = _Up*;
139
140      /**
141       *  @brief  Obtain a pointer to an object
142       *  @param  __r  A reference to an object of type @c element_type
143       *  @return @c addressof(__r)
144      */
145      static _GLIBCXX20_CONSTEXPR pointer
146      pointer_to(__make_not_void<element_type>& __r) noexcept
147      { return std::addressof(__r); }
148    };
149
150  /// Convenience alias for rebinding pointers.
151  template<typename _Ptr, typename _Tp>
152    using __ptr_rebind = typename pointer_traits<_Ptr>::template rebind<_Tp>;
153
154  template<typename _Tp>
155    constexpr _Tp*
156    __to_address(_Tp* __ptr) noexcept
157    {
158      static_assert(!std::is_function<_Tp>::value, "not a function pointer");
159      return __ptr;
160    }
161
162#if __cplusplus <= 201703L
163  template<typename _Ptr>
164    constexpr typename std::pointer_traits<_Ptr>::element_type*
165    __to_address(const _Ptr& __ptr)
166    { return std::__to_address(__ptr.operator->()); }
167#else
168  template<typename _Ptr>
169    constexpr auto
170    __to_address(const _Ptr& __ptr) noexcept
171    -> decltype(std::pointer_traits<_Ptr>::to_address(__ptr))
172    { return std::pointer_traits<_Ptr>::to_address(__ptr); }
173
174  template<typename _Ptr, typename... _None>
175    constexpr auto
176    __to_address(const _Ptr& __ptr, _None...) noexcept
177    {
178      if constexpr (is_base_of_v<__gnu_debug::_Safe_iterator_base, _Ptr>)
179	return std::__to_address(__ptr.base().operator->());
180      else
181	return std::__to_address(__ptr.operator->());
182    }
183
184#define __cpp_lib_to_address 201711L
185
186  /**
187   * @brief Obtain address referenced by a pointer to an object
188   * @param __ptr A pointer to an object
189   * @return @c __ptr
190   * @ingroup pointer_abstractions
191  */
192  template<typename _Tp>
193    constexpr _Tp*
194    to_address(_Tp* __ptr) noexcept
195    { return std::__to_address(__ptr); }
196
197  /**
198   * @brief Obtain address referenced by a pointer to an object
199   * @param __ptr A pointer to an object
200   * @return @c pointer_traits<_Ptr>::to_address(__ptr) if that expression is
201             well-formed, otherwise @c to_address(__ptr.operator->())
202   * @ingroup pointer_abstractions
203  */
204  template<typename _Ptr>
205    constexpr auto
206    to_address(const _Ptr& __ptr) noexcept
207    { return std::__to_address(__ptr); }
208#endif // C++2a
209
210_GLIBCXX_END_NAMESPACE_VERSION
211} // namespace std
212
213#endif
214
215#endif
216