libstdc++
pointer.h
Go to the documentation of this file.
1// Custom pointer adapter and sample storage policies
2
3// Copyright (C) 2008-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/**
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
57namespace __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
282 typedef std::random_access_iterator_tag iterator_category;
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>
308 _Pointer_adapter(const _Pointer_adapter<_Up>& __arg)
309 { _Storage_policy::set(__arg.get()); }
310
311 // Destructor
312 ~_Pointer_adapter() { }
313
314 // Assignment operator
315 _Pointer_adapter&
316 operator=(const _Pointer_adapter& __arg)
317 {
318 _Storage_policy::set(__arg.get());
319 return *this;
320 }
321
322 template<typename _Up>
323 _Pointer_adapter&
324 operator=(const _Pointer_adapter<_Up>& __arg)
325 {
326 _Storage_policy::set(__arg.get());
327 return *this;
328 }
329
330 template<typename _Up>
331 _Pointer_adapter&
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 _CXX_POINTER_ARITH_OPERATOR_SET(long long);
441 _CXX_POINTER_ARITH_OPERATOR_SET(unsigned long long);
442#endif
443
444 // Mathematical Manipulators
445 inline _Pointer_adapter&
446 operator++()
447 {
448 _Storage_policy::set(_Storage_policy::get() + 1);
449 return *this;
450 }
451
452 inline _Pointer_adapter
453 operator++(int)
454 {
455 _Pointer_adapter __tmp(*this);
456 _Storage_policy::set(_Storage_policy::get() + 1);
457 return __tmp;
458 }
459
460 inline _Pointer_adapter&
461 operator--()
462 {
463 _Storage_policy::set(_Storage_policy::get() - 1);
464 return *this;
465 }
466
467 inline _Pointer_adapter
468 operator--(int)
469 {
470 _Pointer_adapter __tmp(*this);
471 _Storage_policy::set(_Storage_policy::get() - 1);
472 return __tmp;
473 }
474
475#if __cpp_lib_three_way_comparison
476 friend std::strong_ordering
477 operator<=>(const _Pointer_adapter& __lhs, const _Pointer_adapter& __rhs)
478 noexcept
479 { return __lhs.get() <=> __rhs.get(); }
480#endif
481 }; // class _Pointer_adapter
482
483
484#define _GCC_CXX_POINTER_COMPARISON_OPERATION_SET(OPERATOR) \
485 template<typename _Tp1, typename _Tp2> \
486 inline bool \
487 operator OPERATOR(const _Pointer_adapter<_Tp1>& __lhs, _Tp2 __rhs) \
488 { return __lhs.get() OPERATOR __rhs; } \
489\
490 template<typename _Tp1, typename _Tp2> \
491 inline bool \
492 operator OPERATOR(_Tp1 __lhs, const _Pointer_adapter<_Tp2>& __rhs) \
493 { return __lhs OPERATOR __rhs.get(); } \
494\
495 template<typename _Tp1, typename _Tp2> \
496 inline bool \
497 operator OPERATOR(const _Pointer_adapter<_Tp1>& __lhs, \
498 const _Pointer_adapter<_Tp2>& __rhs) \
499 { return __lhs.get() OPERATOR __rhs.get(); } \
500\
501// End GCC_CXX_POINTER_COMPARISON_OPERATION_SET Macro
502
503 // Expand into the various comparison operators needed.
504 _GCC_CXX_POINTER_COMPARISON_OPERATION_SET(==)
505 _GCC_CXX_POINTER_COMPARISON_OPERATION_SET(!=)
506 _GCC_CXX_POINTER_COMPARISON_OPERATION_SET(<)
507 _GCC_CXX_POINTER_COMPARISON_OPERATION_SET(<=)
508 _GCC_CXX_POINTER_COMPARISON_OPERATION_SET(>)
509 _GCC_CXX_POINTER_COMPARISON_OPERATION_SET(>=)
510
511 // These are here for expressions like "ptr == 0", "ptr != 0"
512 template<typename _Tp>
513 inline bool
514 operator==(const _Pointer_adapter<_Tp>& __lhs, int __rhs)
515 { return __lhs.get() == reinterpret_cast<void*>(__rhs); }
516
517 template<typename _Tp>
518 inline bool
519 operator==(int __lhs, const _Pointer_adapter<_Tp>& __rhs)
520 { return __rhs.get() == reinterpret_cast<void*>(__lhs); }
521
522 template<typename _Tp>
523 inline bool
524 operator!=(const _Pointer_adapter<_Tp>& __lhs, int __rhs)
525 { return __lhs.get() != reinterpret_cast<void*>(__rhs); }
526
527 template<typename _Tp>
528 inline bool
529 operator!=(int __lhs, const _Pointer_adapter<_Tp>& __rhs)
530 { return __rhs.get() != reinterpret_cast<void*>(__lhs); }
531
532 /**
533 * Comparison operators for _Pointer_adapter defer to the base class'
534 * comparison operators, when possible.
535 */
536 template<typename _Tp>
537 inline bool
538 operator==(const _Pointer_adapter<_Tp>& __lhs,
539 const _Pointer_adapter<_Tp>& __rhs)
540 { return __lhs._Tp::operator==(__rhs); }
541
542 template<typename _Tp>
543 inline bool
544 operator<=(const _Pointer_adapter<_Tp>& __lhs,
545 const _Pointer_adapter<_Tp>& __rhs)
546 { return __lhs._Tp::operator<(__rhs) || __lhs._Tp::operator==(__rhs); }
547
548 template<typename _Tp>
549 inline bool
550 operator!=(const _Pointer_adapter<_Tp>& __lhs,
551 const _Pointer_adapter<_Tp>& __rhs)
552 { return !(__lhs._Tp::operator==(__rhs)); }
553
554 template<typename _Tp>
555 inline bool
556 operator>(const _Pointer_adapter<_Tp>& __lhs,
557 const _Pointer_adapter<_Tp>& __rhs)
558 { return !(__lhs._Tp::operator<(__rhs) || __lhs._Tp::operator==(__rhs)); }
559
560 template<typename _Tp>
561 inline bool
562 operator>=(const _Pointer_adapter<_Tp>& __lhs,
563 const _Pointer_adapter<_Tp>& __rhs)
564 { return !(__lhs._Tp::operator<(__rhs)); }
565
566#if _GLIBCXX_HOSTED
567 template<typename _CharT, typename _Traits, typename _StoreT>
568 inline std::basic_ostream<_CharT, _Traits>&
569 operator<<(std::basic_ostream<_CharT, _Traits>& __os,
570 const _Pointer_adapter<_StoreT>& __p)
571 { return (__os << __p.get()); }
572#endif // HOSTED
573
574_GLIBCXX_END_NAMESPACE_VERSION
575} // namespace
576
577#if __cplusplus >= 201103L
578namespace std _GLIBCXX_VISIBILITY(default)
579{
580_GLIBCXX_BEGIN_NAMESPACE_VERSION
581
582 template<typename _Storage_policy>
583 struct pointer_traits<__gnu_cxx::_Pointer_adapter<_Storage_policy>>
584 {
585 /// The pointer type
586 typedef __gnu_cxx::_Pointer_adapter<_Storage_policy> pointer;
587 /// The type pointed to
588 typedef typename pointer::element_type element_type;
589 /// Type used to represent the difference between two pointers
590 typedef typename pointer::difference_type difference_type;
591
592 template<typename _Up>
593 using rebind = typename __gnu_cxx::_Pointer_adapter<
594 typename pointer_traits<_Storage_policy>::template rebind<_Up>>;
595
596 static pointer pointer_to(typename pointer::reference __r) noexcept
597 { return pointer(std::addressof(__r)); }
598 };
599
600#if __cpp_lib_concepts
601 template<typename _Policy>
602 struct indirectly_readable_traits<__gnu_cxx::_Pointer_adapter<_Policy>>
603 {
604 using value_type
605 = typename __gnu_cxx::_Pointer_adapter<_Policy>::value_type;
606 };
607#endif
608_GLIBCXX_END_NAMESPACE_VERSION
609} // namespace
610#endif
611
612#endif // _POINTER_H
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:138
ISO C++ entities toplevel namespace is std.
GNU extensions for public use.
Uniform interface to all pointer-like types.
Definition ptr_traits.h:185
Random-access iterators support a superset of bidirectional iterator operations.
A storage policy for use with _Pointer_adapter<> which yields a standard pointer.
Definition pointer.h:74
A storage policy for use with _Pointer_adapter<> which stores the pointer's address as an offset valu...
Definition pointer.h:117