1  // Pointer Traits -*- C++ -*-
       2  
       3  // Copyright (C) 2011-2023 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  /* Duplicate definition with unique_ptr.h.  */
      38  #if __cplusplus > 202002L && defined(__cpp_constexpr_dynamic_alloc)
      39  # define __cpp_lib_constexpr_memory 202202L
      40  #elif __cplusplus > 201703L
      41  # define __cpp_lib_constexpr_memory 201811L
      42  #endif
      43  
      44  #if __cplusplus > 201703L
      45  #include <concepts>
      46  namespace __gnu_debug { struct _Safe_iterator_base; }
      47  #endif
      48  
      49  namespace std _GLIBCXX_VISIBILITY(default)
      50  {
      51  _GLIBCXX_BEGIN_NAMESPACE_VERSION
      52  
      53    /// @cond undocumented
      54  
      55    class __undefined;
      56  
      57    // For a specialization `SomeTemplate<T, Types...>` the member `type` is T,
      58    // otherwise `type` is `__undefined`.
      59    template<typename _Tp>
      60      struct __get_first_arg
      61      { using type = __undefined; };
      62  
      63    template<template<typename, typename...> class _SomeTemplate, typename _Tp,
      64             typename... _Types>
      65      struct __get_first_arg<_SomeTemplate<_Tp, _Types...>>
      66      { using type = _Tp; };
      67  
      68    // For a specialization `SomeTemplate<T, Args...>` and a type `U` the member
      69    // `type` is `SomeTemplate<U, Args...>`, otherwise there is no member `type`.
      70    template<typename _Tp, typename _Up>
      71      struct __replace_first_arg
      72      { };
      73  
      74    template<template<typename, typename...> class _SomeTemplate, typename _Up,
      75             typename _Tp, typename... _Types>
      76      struct __replace_first_arg<_SomeTemplate<_Tp, _Types...>, _Up>
      77      { using type = _SomeTemplate<_Up, _Types...>; };
      78  
      79    // Detect the element type of a pointer-like type.
      80    template<typename _Ptr, typename = void>
      81      struct __ptr_traits_elem : __get_first_arg<_Ptr>
      82      { };
      83  
      84    // Use _Ptr::element_type if is a valid type.
      85  #if __cpp_concepts
      86    template<typename _Ptr> requires requires { typename _Ptr::element_type; }
      87      struct __ptr_traits_elem<_Ptr, void>
      88      { using type = typename _Ptr::element_type; };
      89  #else
      90    template<typename _Ptr>
      91      struct __ptr_traits_elem<_Ptr, __void_t<typename _Ptr::element_type>>
      92      { using type = typename _Ptr::element_type; };
      93  #endif
      94  
      95    template<typename _Ptr>
      96      using __ptr_traits_elem_t = typename __ptr_traits_elem<_Ptr>::type;
      97  
      98    /// @endcond
      99  
     100    // Define pointer_traits<P>::pointer_to.
     101    template<typename _Ptr, typename _Elt, bool = is_void<_Elt>::value>
     102      struct __ptr_traits_ptr_to
     103      {
     104        using pointer = _Ptr;
     105        using element_type = _Elt;
     106  
     107        /**
     108         *  @brief  Obtain a pointer to an object
     109         *  @param  __r  A reference to an object of type `element_type`
     110         *  @return `pointer::pointer_to(__r)`
     111         *  @pre `pointer::pointer_to(__r)` is a valid expression.
     112        */
     113        static pointer
     114        pointer_to(element_type& __r)
     115  #if __cpp_lib_concepts
     116        requires requires {
     117  	{ pointer::pointer_to(__r) } -> convertible_to<pointer>;
     118        }
     119  #endif
     120        { return pointer::pointer_to(__r); }
     121      };
     122  
     123    // Do not define pointer_traits<P>::pointer_to if element type is void.
     124    template<typename _Ptr, typename _Elt>
     125      struct __ptr_traits_ptr_to<_Ptr, _Elt, true>
     126      { };
     127  
     128    // Partial specialization defining pointer_traits<T*>::pointer_to(T&).
     129    template<typename _Tp>
     130      struct __ptr_traits_ptr_to<_Tp*, _Tp, false>
     131      {
     132        using pointer = _Tp*;
     133        using element_type = _Tp;
     134  
     135        /**
     136         *  @brief  Obtain a pointer to an object
     137         *  @param  __r  A reference to an object of type `element_type`
     138         *  @return `addressof(__r)`
     139        */
     140        static _GLIBCXX20_CONSTEXPR pointer
     141        pointer_to(element_type& __r) noexcept
     142        { return std::addressof(__r); }
     143      };
     144  
     145    template<typename _Ptr, typename _Elt>
     146      struct __ptr_traits_impl : __ptr_traits_ptr_to<_Ptr, _Elt>
     147      {
     148      private:
     149        template<typename _Tp>
     150  	using __diff_t = typename _Tp::difference_type;
     151  
     152        template<typename _Tp, typename _Up>
     153  	using __rebind = __type_identity<typename _Tp::template rebind<_Up>>;
     154  
     155      public:
     156        /// The pointer type.
     157        using pointer = _Ptr;
     158  
     159        /// The type pointed to.
     160        using element_type = _Elt;
     161  
     162        /// The type used to represent the difference between two pointers.
     163        using difference_type = __detected_or_t<ptrdiff_t, __diff_t, _Ptr>;
     164  
     165        /// A pointer to a different type.
     166        template<typename _Up>
     167  	using rebind = typename __detected_or_t<__replace_first_arg<_Ptr, _Up>,
     168  						__rebind, _Ptr, _Up>::type;
     169      };
     170  
     171    // _GLIBCXX_RESOLVE_LIB_DEFECTS
     172    // 3545. std::pointer_traits should be SFINAE-friendly
     173    template<typename _Ptr>
     174      struct __ptr_traits_impl<_Ptr, __undefined>
     175      { };
     176  
     177    /**
     178     * @brief  Uniform interface to all pointer-like types
     179     * @headerfile memory
     180     * @ingroup pointer_abstractions
     181     * @since C++11
     182    */
     183    template<typename _Ptr>
     184      struct pointer_traits : __ptr_traits_impl<_Ptr, __ptr_traits_elem_t<_Ptr>>
     185      { };
     186  
     187    /**
     188     * @brief  Partial specialization for built-in pointers.
     189     * @headerfile memory
     190     * @ingroup pointer_abstractions
     191     * @since C++11
     192    */
     193    template<typename _Tp>
     194      struct pointer_traits<_Tp*> : __ptr_traits_ptr_to<_Tp*, _Tp>
     195      {
     196        /// The pointer type
     197        typedef _Tp* pointer;
     198        /// The type pointed to
     199        typedef _Tp  element_type;
     200        /// Type used to represent the difference between two pointers
     201        typedef ptrdiff_t difference_type;
     202        /// A pointer to a different type.
     203        template<typename _Up> using rebind = _Up*;
     204      };
     205  
     206    /// Convenience alias for rebinding pointers.
     207    template<typename _Ptr, typename _Tp>
     208      using __ptr_rebind = typename pointer_traits<_Ptr>::template rebind<_Tp>;
     209  
     210    template<typename _Tp>
     211      constexpr _Tp*
     212      __to_address(_Tp* __ptr) noexcept
     213      {
     214        static_assert(!std::is_function<_Tp>::value, "not a function pointer");
     215        return __ptr;
     216      }
     217  
     218  #if __cplusplus <= 201703L
     219    template<typename _Ptr>
     220      constexpr typename std::pointer_traits<_Ptr>::element_type*
     221      __to_address(const _Ptr& __ptr)
     222      { return std::__to_address(__ptr.operator->()); }
     223  #else
     224    template<typename _Ptr>
     225      constexpr auto
     226      __to_address(const _Ptr& __ptr) noexcept
     227      -> decltype(std::pointer_traits<_Ptr>::to_address(__ptr))
     228      { return std::pointer_traits<_Ptr>::to_address(__ptr); }
     229  
     230    template<typename _Ptr, typename... _None>
     231      constexpr auto
     232      __to_address(const _Ptr& __ptr, _None...) noexcept
     233      {
     234        if constexpr (is_base_of_v<__gnu_debug::_Safe_iterator_base, _Ptr>)
     235  	return std::__to_address(__ptr.base().operator->());
     236        else
     237  	return std::__to_address(__ptr.operator->());
     238      }
     239  
     240  #define __cpp_lib_to_address 201711L
     241  
     242    /**
     243     * @brief Obtain address referenced by a pointer to an object
     244     * @param __ptr A pointer to an object
     245     * @return @c __ptr
     246     * @ingroup pointer_abstractions
     247    */
     248    template<typename _Tp>
     249      constexpr _Tp*
     250      to_address(_Tp* __ptr) noexcept
     251      { return std::__to_address(__ptr); }
     252  
     253    /**
     254     * @brief Obtain address referenced by a pointer to an object
     255     * @param __ptr A pointer to an object
     256     * @return @c pointer_traits<_Ptr>::to_address(__ptr) if that expression is
     257               well-formed, otherwise @c to_address(__ptr.operator->())
     258     * @ingroup pointer_abstractions
     259    */
     260    template<typename _Ptr>
     261      constexpr auto
     262      to_address(const _Ptr& __ptr) noexcept
     263      { return std::__to_address(__ptr); }
     264  #endif // C++2a
     265  
     266  _GLIBCXX_END_NAMESPACE_VERSION
     267  } // namespace std
     268  
     269  #endif
     270  
     271  #endif