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
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#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>
571 inline std::basic_ostream<_CharT, _Traits>&
572 operator<<(std::basic_ostream<_CharT, _Traits>& __os,
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
581namespace 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
589 typedef __gnu_cxx::_Pointer_adapter<_Storage_policy> pointer;
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
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
ISO C++ entities toplevel namespace is std.
GNU extensions for public use.
Uniform interface to all pointer-like types.
Definition ptr_traits.h:178
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