libstdc++
pointer.h
Go to the documentation of this file.
1 // Custom pointer adapter and sample storage policies
2 
3 // Copyright (C) 2008-2024 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 /**
26  * @file ext/pointer.h
27  * This file is a GNU extension to the Standard C++ Library.
28  *
29  * @author Bob Walters
30  *
31  * Provides reusable _Pointer_adapter for assisting in the development of
32  * custom pointer types that can be used with the standard containers via
33  * the allocator::pointer and allocator::const_pointer typedefs.
34  */
35 
36 #ifndef _POINTER_H
37 #define _POINTER_H 1
38 
39 #pragma GCC system_header
40 
41 #include <bits/c++config.h>
42 #if _GLIBCXX_HOSTED
43 # include <iosfwd>
44 #endif
45 
47 #include <ext/cast.h>
48 #include <ext/type_traits.h>
49 #if __cplusplus >= 201103L
50 # include <bits/move.h>
51 # include <bits/ptr_traits.h>
52 #endif
53 #if __cplusplus > 201703L
54 # include <iterator> // for indirectly_readable_traits
55 #endif
56 
57 namespace __gnu_cxx _GLIBCXX_VISIBILITY(default)
58 {
59 _GLIBCXX_BEGIN_NAMESPACE_VERSION
60 
61  /**
62  * @brief A storage policy for use with _Pointer_adapter<> which yields a
63  * standard pointer.
64  *
65  * A _Storage_policy is required to provide 4 things:
66  * 1) A get() API for returning the stored pointer value.
67  * 2) An set() API for storing a pointer value.
68  * 3) An element_type typedef to define the type this points to.
69  * 4) An operator<() to support pointer comparison.
70  * 5) An operator==() to support pointer comparison.
71  */
72  template<typename _Tp>
74  {
75  public:
76  // the type this pointer points to.
77  typedef _Tp element_type;
78 
79  // A method to fetch the pointer value as a standard T* value;
80  inline _Tp*
81  get() const
82  { return _M_value; }
83 
84  // A method to set the pointer value, from a standard T* value;
85  inline void
86  set(element_type* __arg)
87  { _M_value = __arg; }
88 
89  // Comparison of pointers
90  inline bool
91  operator<(const _Std_pointer_impl& __rarg) const
92  { return (_M_value < __rarg._M_value); }
93 
94  inline bool
95  operator==(const _Std_pointer_impl& __rarg) const
96  { return (_M_value == __rarg._M_value); }
97 
98  private:
99  element_type* _M_value;
100  };
101 
102  /**
103  * @brief A storage policy for use with _Pointer_adapter<> which stores
104  * the pointer's address as an offset value which is relative to
105  * its own address.
106  *
107  * This is intended for pointers within shared memory regions which
108  * might be mapped at different addresses by different processes.
109  * For null pointers, a value of 1 is used. (0 is legitimate
110  * sometimes for nodes in circularly linked lists) This value was
111  * chosen as the least likely to generate an incorrect null, As
112  * there is no reason why any normal pointer would point 1 byte into
113  * its own pointer address.
114  */
115  template<typename _Tp>
117  {
118  public:
119  typedef _Tp element_type;
120 
121  _Tp*
122  get() const
123  {
124  if (_M_diff == 1)
125  return 0;
126  else
127  return reinterpret_cast<_Tp*>(reinterpret_cast<uintptr_t>(this)
128  + _M_diff);
129  }
130 
131  void
132  set(_Tp* __arg)
133  {
134  if (!__arg)
135  _M_diff = 1;
136  else
137  _M_diff = reinterpret_cast<uintptr_t>(__arg)
138  - reinterpret_cast<uintptr_t>(this);
139  }
140 
141  // Comparison of pointers
142  inline bool
143  operator<(const _Relative_pointer_impl& __rarg) const
144  { return (reinterpret_cast<uintptr_t>(this->get())
145  < reinterpret_cast<uintptr_t>(__rarg.get())); }
146 
147  inline bool
148  operator==(const _Relative_pointer_impl& __rarg) const
149  { return (reinterpret_cast<uintptr_t>(this->get())
150  == reinterpret_cast<uintptr_t>(__rarg.get())); }
151 
152  private:
153  typedef __UINTPTR_TYPE__ uintptr_t;
154  uintptr_t _M_diff;
155  };
156 
157  /**
158  * Relative_pointer_impl needs a specialization for const T because of
159  * the casting done during pointer arithmetic.
160  */
161  template<typename _Tp>
162  class _Relative_pointer_impl<const _Tp>
163  {
164  public:
165  typedef const _Tp element_type;
166 
167  const _Tp*
168  get() const
169  {
170  if (_M_diff == 1)
171  return 0;
172  else
173  return reinterpret_cast<const _Tp*>
174  (reinterpret_cast<uintptr_t>(this) + _M_diff);
175  }
176 
177  void
178  set(const _Tp* __arg)
179  {
180  if (!__arg)
181  _M_diff = 1;
182  else
183  _M_diff = reinterpret_cast<uintptr_t>(__arg)
184  - reinterpret_cast<uintptr_t>(this);
185  }
186 
187  // Comparison of pointers
188  inline bool
189  operator<(const _Relative_pointer_impl& __rarg) const
190  { return (reinterpret_cast<uintptr_t>(this->get())
191  < reinterpret_cast<uintptr_t>(__rarg.get())); }
192 
193  inline bool
194  operator==(const _Relative_pointer_impl& __rarg) const
195  { return (reinterpret_cast<uintptr_t>(this->get())
196  == reinterpret_cast<uintptr_t>(__rarg.get())); }
197 
198  private:
199  typedef __UINTPTR_TYPE__ uintptr_t;
200  uintptr_t _M_diff;
201  };
202 
203  /**
204  * The specialization on this type helps resolve the problem of
205  * reference to void, and eliminates the need to specialize
206  * _Pointer_adapter for cases of void*, const void*, and so on.
207  */
208  struct _Invalid_type { };
209 
210  template<typename _Tp>
211  struct _Reference_type
212  { typedef _Tp& reference; };
213 
214  template<>
215  struct _Reference_type<void>
216  { typedef _Invalid_type& reference; };
217 
218  template<>
219  struct _Reference_type<const void>
220  { typedef const _Invalid_type& reference; };
221 
222  template<>
223  struct _Reference_type<volatile void>
224  { typedef volatile _Invalid_type& reference; };
225 
226  template<>
227  struct _Reference_type<volatile const void>
228  { typedef const volatile _Invalid_type& reference; };
229 
230  /**
231  * This structure accommodates the way in which
232  * std::iterator_traits<> is normally specialized for const T*, so
233  * that value_type is still T.
234  */
235  template<typename _Tp>
237  { typedef _Tp type; };
238 
239  template<typename _Tp>
240  struct _Unqualified_type<const _Tp>
241  { typedef _Tp type; };
242 
243  /**
244  * The following provides an 'alternative pointer' that works with
245  * the containers when specified as the pointer typedef of the
246  * allocator.
247  *
248  * The pointer type used with the containers doesn't have to be this
249  * class, but it must support the implicit conversions, pointer
250  * arithmetic, comparison operators, etc. that are supported by this
251  * class, and avoid raising compile-time ambiguities. Because
252  * creating a working pointer can be challenging, this pointer
253  * template was designed to wrapper an easier storage policy type,
254  * so that it becomes reusable for creating other pointer types.
255  *
256  * A key point of this class is also that it allows container
257  * writers to 'assume' Allocator::pointer is a typedef for a normal
258  * pointer. This class supports most of the conventions of a true
259  * pointer, and can, for instance handle implicit conversion to
260  * const and base class pointer types. The only impositions on
261  * container writers to support extended pointers are: 1) use the
262  * Allocator::pointer typedef appropriately for pointer types. 2)
263  * if you need pointer casting, use the __pointer_cast<> functions
264  * from ext/cast.h. This allows pointer cast operations to be
265  * overloaded as necessary by custom pointers.
266  *
267  * Note: The const qualifier works with this pointer adapter as
268  * follows:
269  *
270  * _Tp* == _Pointer_adapter<_Std_pointer_impl<_Tp> >;
271  * const _Tp* == _Pointer_adapter<_Std_pointer_impl<const _Tp> >;
272  * _Tp* const == const _Pointer_adapter<_Std_pointer_impl<_Tp> >;
273  * const _Tp* const == const _Pointer_adapter<_Std_pointer_impl<const _Tp> >;
274  */
275  template<typename _Storage_policy>
276  class _Pointer_adapter : public _Storage_policy
277  {
278  public:
279  typedef typename _Storage_policy::element_type element_type;
280 
281  // These are needed for iterator_traits
283  typedef typename _Unqualified_type<element_type>::type value_type;
284  typedef std::ptrdiff_t difference_type;
285  typedef _Pointer_adapter pointer;
286  typedef typename _Reference_type<element_type>::reference reference;
287 
288  // Reminder: 'const' methods mean that the method is valid when the
289  // pointer is immutable, and has nothing to do with whether the
290  // 'pointee' is const.
291 
292  // Default Constructor (Convert from element_type*)
293  _Pointer_adapter(element_type* __arg = 0)
294  { _Storage_policy::set(__arg); }
295 
296  // Copy constructor from _Pointer_adapter of same type.
297  _Pointer_adapter(const _Pointer_adapter& __arg)
298  { _Storage_policy::set(__arg.get()); }
299 
300  // Convert from _Up* if conversion to element_type* is valid.
301  template<typename _Up>
302  _Pointer_adapter(_Up* __arg)
303  { _Storage_policy::set(__arg); }
304 
305  // Conversion from another _Pointer_adapter if _Up if static cast is
306  // valid.
307  template<typename _Up>
309  { _Storage_policy::set(__arg.get()); }
310 
311  // Destructor
312  ~_Pointer_adapter() { }
313 
314  // Assignment operator
316  operator=(const _Pointer_adapter& __arg)
317  {
318  _Storage_policy::set(__arg.get());
319  return *this;
320  }
321 
322  template<typename _Up>
324  operator=(const _Pointer_adapter<_Up>& __arg)
325  {
326  _Storage_policy::set(__arg.get());
327  return *this;
328  }
329 
330  template<typename _Up>
332  operator=(_Up* __arg)
333  {
334  _Storage_policy::set(__arg);
335  return *this;
336  }
337 
338  // Operator*, returns element_type&
339  inline reference
340  operator*() const
341  { return *(_Storage_policy::get()); }
342 
343  // Operator->, returns element_type*
344  inline element_type*
345  operator->() const
346  { return _Storage_policy::get(); }
347 
348  // Operator[], returns a element_type& to the item at that loc.
349  inline reference
350  operator[](std::ptrdiff_t __index) const
351  { return _Storage_policy::get()[__index]; }
352 
353  // To allow implicit conversion to "bool", for "if (ptr)..."
354 #if __cplusplus >= 201103L
355  explicit operator bool() const { return _Storage_policy::get() != 0; }
356 #else
357  private:
358  typedef element_type*(_Pointer_adapter::*__unspecified_bool_type)() const;
359 
360  public:
361  operator __unspecified_bool_type() const
362  {
363  return _Storage_policy::get() == 0 ? 0 :
364  &_Pointer_adapter::operator->;
365  }
366 
367  // ! operator (for: if (!ptr)...)
368  inline bool
369  operator!() const
370  { return (_Storage_policy::get() == 0); }
371 #endif
372 
373  // Pointer differences
374  inline friend std::ptrdiff_t
375  operator-(const _Pointer_adapter& __lhs, element_type* __rhs)
376  { return (__lhs.get() - __rhs); }
377 
378  inline friend std::ptrdiff_t
379  operator-(element_type* __lhs, const _Pointer_adapter& __rhs)
380  { return (__lhs - __rhs.get()); }
381 
382  template<typename _Up>
383  inline friend std::ptrdiff_t
384  operator-(const _Pointer_adapter& __lhs, _Up* __rhs)
385  { return (__lhs.get() - __rhs); }
386 
387  template<typename _Up>
388  inline friend std::ptrdiff_t
389  operator-(_Up* __lhs, const _Pointer_adapter& __rhs)
390  { return (__lhs - __rhs.get()); }
391 
392  template<typename _Up>
393  inline std::ptrdiff_t
394  operator-(const _Pointer_adapter<_Up>& __rhs) const
395  { return (_Storage_policy::get() - __rhs.get()); }
396 
397  // Pointer math
398  // Note: There is a reason for all this overloading based on different
399  // integer types. In some libstdc++-v3 test cases, a templated
400  // operator+ is declared which can match any types. This operator
401  // tends to "steal" the recognition of _Pointer_adapter's own operator+
402  // unless the integer type matches perfectly.
403 
404 #define _CXX_POINTER_ARITH_OPERATOR_SET(INT_TYPE) \
405  inline friend _Pointer_adapter \
406  operator+(const _Pointer_adapter& __lhs, INT_TYPE __offset) \
407  { return _Pointer_adapter(__lhs.get() + __offset); } \
408 \
409  inline friend _Pointer_adapter \
410  operator+(INT_TYPE __offset, const _Pointer_adapter& __rhs) \
411  { return _Pointer_adapter(__rhs.get() + __offset); } \
412 \
413  inline friend _Pointer_adapter \
414  operator-(const _Pointer_adapter& __lhs, INT_TYPE __offset) \
415  { return _Pointer_adapter(__lhs.get() - __offset); } \
416 \
417  inline _Pointer_adapter& \
418  operator+=(INT_TYPE __offset) \
419  { \
420  _Storage_policy::set(_Storage_policy::get() + __offset); \
421  return *this; \
422  } \
423 \
424  inline _Pointer_adapter& \
425  operator-=(INT_TYPE __offset) \
426  { \
427  _Storage_policy::set(_Storage_policy::get() - __offset); \
428  return *this; \
429  } \
430 // END of _CXX_POINTER_ARITH_OPERATOR_SET macro
431 
432  // Expand into the various pointer arithmetic operators needed.
433  _CXX_POINTER_ARITH_OPERATOR_SET(short);
434  _CXX_POINTER_ARITH_OPERATOR_SET(unsigned short);
435  _CXX_POINTER_ARITH_OPERATOR_SET(int);
436  _CXX_POINTER_ARITH_OPERATOR_SET(unsigned int);
437  _CXX_POINTER_ARITH_OPERATOR_SET(long);
438  _CXX_POINTER_ARITH_OPERATOR_SET(unsigned long);
439 #ifdef _GLIBCXX_USE_LONG_LONG
440 #pragma GCC diagnostic push
441 #pragma GCC diagnostic ignored "-Wlong-long"
442  _CXX_POINTER_ARITH_OPERATOR_SET(long long);
443  _CXX_POINTER_ARITH_OPERATOR_SET(unsigned long long);
444 #pragma GCC diagnostic pop
445 #endif
446 
447  // Mathematical Manipulators
448  inline _Pointer_adapter&
449  operator++()
450  {
451  _Storage_policy::set(_Storage_policy::get() + 1);
452  return *this;
453  }
454 
455  inline _Pointer_adapter
456  operator++(int)
457  {
458  _Pointer_adapter __tmp(*this);
459  _Storage_policy::set(_Storage_policy::get() + 1);
460  return __tmp;
461  }
462 
463  inline _Pointer_adapter&
464  operator--()
465  {
466  _Storage_policy::set(_Storage_policy::get() - 1);
467  return *this;
468  }
469 
470  inline _Pointer_adapter
471  operator--(int)
472  {
473  _Pointer_adapter __tmp(*this);
474  _Storage_policy::set(_Storage_policy::get() - 1);
475  return __tmp;
476  }
477 
478 #if __cpp_lib_three_way_comparison
479  friend std::strong_ordering
480  operator<=>(const _Pointer_adapter& __lhs, const _Pointer_adapter& __rhs)
481  noexcept
482  { return __lhs.get() <=> __rhs.get(); }
483 #endif
484  }; // class _Pointer_adapter
485 
486 
487 #define _GCC_CXX_POINTER_COMPARISON_OPERATION_SET(OPERATOR) \
488  template<typename _Tp1, typename _Tp2> \
489  inline bool \
490  operator OPERATOR(const _Pointer_adapter<_Tp1>& __lhs, _Tp2 __rhs) \
491  { return __lhs.get() OPERATOR __rhs; } \
492 \
493  template<typename _Tp1, typename _Tp2> \
494  inline bool \
495  operator OPERATOR(_Tp1 __lhs, const _Pointer_adapter<_Tp2>& __rhs) \
496  { return __lhs OPERATOR __rhs.get(); } \
497 \
498  template<typename _Tp1, typename _Tp2> \
499  inline bool \
500  operator OPERATOR(const _Pointer_adapter<_Tp1>& __lhs, \
501  const _Pointer_adapter<_Tp2>& __rhs) \
502  { return __lhs.get() OPERATOR __rhs.get(); } \
503 \
504 // End GCC_CXX_POINTER_COMPARISON_OPERATION_SET Macro
505 
506  // Expand into the various comparison operators needed.
507  _GCC_CXX_POINTER_COMPARISON_OPERATION_SET(==)
508  _GCC_CXX_POINTER_COMPARISON_OPERATION_SET(!=)
509  _GCC_CXX_POINTER_COMPARISON_OPERATION_SET(<)
510  _GCC_CXX_POINTER_COMPARISON_OPERATION_SET(<=)
511  _GCC_CXX_POINTER_COMPARISON_OPERATION_SET(>)
512  _GCC_CXX_POINTER_COMPARISON_OPERATION_SET(>=)
513 
514  // These are here for expressions like "ptr == 0", "ptr != 0"
515  template<typename _Tp>
516  inline bool
517  operator==(const _Pointer_adapter<_Tp>& __lhs, int __rhs)
518  { return __lhs.get() == reinterpret_cast<void*>(__rhs); }
519 
520  template<typename _Tp>
521  inline bool
522  operator==(int __lhs, const _Pointer_adapter<_Tp>& __rhs)
523  { return __rhs.get() == reinterpret_cast<void*>(__lhs); }
524 
525  template<typename _Tp>
526  inline bool
527  operator!=(const _Pointer_adapter<_Tp>& __lhs, int __rhs)
528  { return __lhs.get() != reinterpret_cast<void*>(__rhs); }
529 
530  template<typename _Tp>
531  inline bool
532  operator!=(int __lhs, const _Pointer_adapter<_Tp>& __rhs)
533  { return __rhs.get() != reinterpret_cast<void*>(__lhs); }
534 
535  /**
536  * Comparison operators for _Pointer_adapter defer to the base class'
537  * comparison operators, when possible.
538  */
539  template<typename _Tp>
540  inline bool
541  operator==(const _Pointer_adapter<_Tp>& __lhs,
542  const _Pointer_adapter<_Tp>& __rhs)
543  { return __lhs._Tp::operator==(__rhs); }
544 
545  template<typename _Tp>
546  inline bool
547  operator<=(const _Pointer_adapter<_Tp>& __lhs,
548  const _Pointer_adapter<_Tp>& __rhs)
549  { return __lhs._Tp::operator<(__rhs) || __lhs._Tp::operator==(__rhs); }
550 
551  template<typename _Tp>
552  inline bool
553  operator!=(const _Pointer_adapter<_Tp>& __lhs,
554  const _Pointer_adapter<_Tp>& __rhs)
555  { return !(__lhs._Tp::operator==(__rhs)); }
556 
557  template<typename _Tp>
558  inline bool
559  operator>(const _Pointer_adapter<_Tp>& __lhs,
560  const _Pointer_adapter<_Tp>& __rhs)
561  { return !(__lhs._Tp::operator<(__rhs) || __lhs._Tp::operator==(__rhs)); }
562 
563  template<typename _Tp>
564  inline bool
565  operator>=(const _Pointer_adapter<_Tp>& __lhs,
566  const _Pointer_adapter<_Tp>& __rhs)
567  { return !(__lhs._Tp::operator<(__rhs)); }
568 
569 #if _GLIBCXX_HOSTED
570  template<typename _CharT, typename _Traits, typename _StoreT>
573  const _Pointer_adapter<_StoreT>& __p)
574  { return (__os << __p.get()); }
575 #endif // HOSTED
576 
577 _GLIBCXX_END_NAMESPACE_VERSION
578 } // namespace
579 
580 #if __cplusplus >= 201103L
581 namespace std _GLIBCXX_VISIBILITY(default)
582 {
583 _GLIBCXX_BEGIN_NAMESPACE_VERSION
584 
585  template<typename _Storage_policy>
586  struct pointer_traits<__gnu_cxx::_Pointer_adapter<_Storage_policy>>
587  {
588  /// The pointer type
590  /// The type pointed to
591  typedef typename pointer::element_type element_type;
592  /// Type used to represent the difference between two pointers
593  typedef typename pointer::difference_type difference_type;
594 
595  template<typename _Up>
596  using rebind = typename __gnu_cxx::_Pointer_adapter<
597  typename pointer_traits<_Storage_policy>::template rebind<_Up>>;
598 
599  static pointer pointer_to(typename pointer::reference __r) noexcept
600  { return pointer(std::addressof(__r)); }
601  };
602 
603 #if __cpp_lib_concepts
604  template<typename _Policy>
605  struct indirectly_readable_traits<__gnu_cxx::_Pointer_adapter<_Policy>>
606  {
607  using value_type
608  = typename __gnu_cxx::_Pointer_adapter<_Policy>::value_type;
609  };
610 #endif
611 _GLIBCXX_END_NAMESPACE_VERSION
612 } // namespace
613 #endif
614 
615 #endif // _POINTER_H
__gnu_cxx::_Relative_pointer_impl
A storage policy for use with _Pointer_adapter<> which stores the pointer's address as an offset valu...
Definition: pointer.h:116
ptr_traits.h
std
ISO C++ entities toplevel namespace is std.
stl_iterator_base_types.h
__gnu_cxx
GNU extensions for public use.
std::basic_ostream
Template class basic_ostream.
Definition: iosfwd:88
__gnu_cxx::_Invalid_type
Definition: pointer.h:208
__gnu_cxx::_Std_pointer_impl
A storage policy for use with _Pointer_adapter<> which yields a standard pointer.
Definition: pointer.h:73
type_traits.h
std::addressof
constexpr _Tp * addressof(_Tp &__r) noexcept
Returns the actual address of the object or function referenced by r, even in the presence of an over...
Definition: move.h:175
__gnu_cxx::_Pointer_adapter
Definition: pointer.h:276
iterator
move.h
iosfwd
std::operator<<
std::basic_ostream< _CharT, _Traits > & operator<<(std::basic_ostream< _CharT, _Traits > &__os, const bitset< _Nb > &__x)
Global I/O operators for bitsets.
Definition: bitset:1687
cast.h
std::random_access_iterator_tag
Random-access iterators support a superset of bidirectional iterator operations.
Definition: stl_iterator_base_types.h:107
c++config.h
__gnu_cxx::_Unqualified_type
Definition: pointer.h:236