30#ifndef _ALLOC_TRAITS_H
31#define _ALLOC_TRAITS_H 1
35#if __cplusplus >= 201103L
46namespace std _GLIBCXX_VISIBILITY(default)
48_GLIBCXX_BEGIN_NAMESPACE_VERSION
50#if __cplusplus >= 201103L
52#pragma GCC diagnostic push
53#pragma GCC diagnostic ignored "-Wc++14-extensions"
54#pragma GCC diagnostic ignored "-Wc++17-extensions"
57 struct __allocator_traits_base
60 template<
typename _Tp,
typename _Up>
62 template<
typename _Tp,
typename _Up,
typename =
void>
64 struct __rebind : __replace_first_arg<_Tp, _Up>
66 static_assert(is_same<
67 typename __replace_first_arg<_Tp, typename _Tp::value_type>::type,
69 "allocator_traits<A>::rebind_alloc<A::value_type> must be A");
72 template<
typename _Tp,
typename _Up>
74 requires requires {
typename _Tp::template rebind<_Up>::other; }
75 struct __rebind<_Tp, _Up>
77 struct __rebind<_Tp, _Up,
78 __void_t<typename _Tp::template rebind<_Up>::other>>
81 using type =
typename _Tp::template rebind<_Up>::other;
83 static_assert(is_same<
84 typename _Tp::template rebind<typename _Tp::value_type>::other,
86 "allocator_traits<A>::rebind_alloc<A::value_type> must be A");
90 template<
typename _Tp>
91 using __pointer =
typename _Tp::pointer;
92 template<
typename _Tp>
93 using __c_pointer =
typename _Tp::const_pointer;
94 template<
typename _Tp>
95 using __v_pointer =
typename _Tp::void_pointer;
96 template<
typename _Tp>
97 using __cv_pointer =
typename _Tp::const_void_pointer;
98 template<
typename _Tp>
99 using __pocca =
typename _Tp::propagate_on_container_copy_assignment;
100 template<
typename _Tp>
101 using __pocma =
typename _Tp::propagate_on_container_move_assignment;
102 template<
typename _Tp>
103 using __pocs =
typename _Tp::propagate_on_container_swap;
104 template<
typename _Tp>
105 using __equal = __type_identity<typename _Tp::is_always_equal>;
109 template<
typename _Alloc,
typename _Sz,
typename _Vp>
110 static constexpr bool __has_allocate_hint
111 =
requires (_Alloc& __a, _Sz __n, _Vp __hint) {
112 __a.allocate(__n, __hint);
115 template<
typename _Alloc,
typename _Sz,
typename _Vp>
116 using __allocate_hint_t
119 template<
typename _Alloc,
typename _Sz,
typename _Vp,
typename =
void>
120 static constexpr bool __has_allocate_hint =
false;
121 template<
typename _Alloc,
typename _Sz,
typename _Vp>
122 static constexpr bool
123 __has_allocate_hint<_Alloc, _Sz, _Vp,
124 __void_t<__allocate_hint_t<_Alloc, _Sz, _Vp>>>
133 template<
typename _Alloc,
typename _Tp,
typename... _Args>
134 static constexpr bool __has_construct
135 =
requires (_Alloc& __a, _Tp* __p, _Args&&... __args) {
138 template<
typename _Tp,
typename... _Args>
139 static constexpr bool __can_construct_at
140 =
requires (_Tp* __p, _Args&&... __args) {
141#if __cpp_constexpr_dynamic_alloc
147 template<
typename _Alloc,
typename _Tp,
typename... _Args>
148 static constexpr bool __can_construct
149 = __has_construct<_Alloc, _Tp, _Args...>
150 || __can_construct_at<_Tp, _Args...>;
152 template<
typename _Alloc,
typename _Tp,
typename... _Args>
156 template<
typename _Alloc,
typename _Tp,
typename,
typename... _Args>
157 static constexpr bool __has_construct_impl =
false;
158 template<
typename _Alloc,
typename _Tp,
typename... _Args>
159 static constexpr bool
160 __has_construct_impl<_Alloc, _Tp,
161 __void_t<__construct_t<_Alloc, _Tp, _Args...>>,
164 template<
typename _Alloc,
typename _Tp,
typename... _Args>
165 static constexpr bool __has_construct
166 = __has_construct_impl<_Alloc, _Tp, void, _Args...>;
167 template<
typename _Tp,
typename... _Args>
170 template<
typename _Tp,
typename,
typename... _Args>
171 static constexpr bool __has_new_expr =
false;
172 template<
typename _Tp,
typename... _Args>
173 static constexpr bool
174 __has_new_expr<_Tp, __void_t<__new_expr_t<_Tp, _Args...>>, _Args...>
176 template<
typename _Alloc,
typename _Tp,
typename... _Args>
177 static constexpr bool __can_construct
178 = __has_construct<_Alloc, _Tp, _Args...>
179 || __has_new_expr<_Tp, void, _Args...>;
184 template<
typename _Alloc,
typename _Tp>
185 static constexpr bool __has_destroy =
requires (_Alloc& __a, _Tp* __p) {
189 template<
typename _Alloc,
typename _Tp>
192 template<
typename _Alloc,
typename _Tp,
typename =
void>
193 static constexpr bool __has_destroy =
false;
194 template<
typename _Alloc,
typename _Tp>
195 static constexpr bool __has_destroy<_Alloc, _Tp,
196 __void_t<__destroy_t<_Alloc, _Tp>>>
202 template<
typename _Alloc>
203 static constexpr bool __has_max_size =
requires (
const _Alloc& __a) {
207 template<
typename _Alloc>
209 template<
typename _Alloc,
typename =
void>
210 static constexpr bool __has_max_size =
false;
211 template<
typename _Alloc>
212 static constexpr bool __has_max_size<_Alloc,
213 __void_t<__max_size_t<_Alloc>>>
220 template<
typename _Alloc>
221 static constexpr bool __has_soccc =
requires (
const _Alloc& __a) {
222 __a.select_on_container_copy_construction();
225 template<
typename _Alloc>
228 .select_on_container_copy_construction());
229 template<
typename _Alloc,
typename =
void>
230 static constexpr bool __has_soccc =
false;
231 template<
typename _Alloc>
232 static constexpr bool __has_soccc<_Alloc, __void_t<__soccc_t<_Alloc>>>
237 template<
typename _Alloc,
typename _Up>
239 =
typename __allocator_traits_base::template __rebind<_Alloc, _Up>::type;
242#if __cplusplus > 202002L
243# define _GLIBCXX_NO_ALLOC_TRAITS_SPECIALIZATIONS _GLIBCXX_NO_SPECIALIZATIONS
245# define _GLIBCXX_NO_ALLOC_TRAITS_SPECIALIZATIONS
254 template<
typename _Alloc>
256 : __allocator_traits_base
268 using pointer = __detected_or_t<value_type*, __pointer, _Alloc>;
272 template<
template<
typename>
class _Func,
typename _Tp,
typename =
void>
278 template<
template<
typename>
class _Func,
typename _Tp>
279 struct _Ptr<_Func, _Tp, __void_t<_Func<_Alloc>>>
281 using type = _Func<_Alloc>;
285 template<
typename _A2,
typename _PtrT,
typename =
void>
287 {
using type =
typename pointer_traits<_PtrT>::difference_type; };
289 template<
typename _A2,
typename _PtrT>
290 struct _Diff<_A2, _PtrT, __void_t<typename _A2::difference_type>>
291 {
using type =
typename _A2::difference_type; };
294 template<
typename _A2,
typename _DiffT,
typename =
void>
295 struct _Size : make_unsigned<_DiffT> { };
297 template<
typename _A2,
typename _DiffT>
298 struct _Size<_A2, _DiffT, __void_t<typename _A2::size_type>>
299 {
using type =
typename _A2::size_type; };
340 using size_type =
typename _Size<_Alloc, difference_type>::type;
349 = __detected_or_t<false_type, __pocca, _Alloc>;
358 = __detected_or_t<false_type, __pocma, _Alloc>;
367 = __detected_or_t<false_type, __pocs, _Alloc>;
376 =
typename __detected_or_t<is_empty<_Alloc>, __equal, _Alloc>::type;
378 template<
typename _Tp>
379 using rebind_alloc = __alloc_rebind<_Alloc, _Tp>;
380 template<
typename _Tp>
390 _GLIBCXX_NODISCARD
static _GLIBCXX20_CONSTEXPR
pointer
392 {
return __a.allocate(__n); }
405 _GLIBCXX_NODISCARD
static _GLIBCXX20_CONSTEXPR
pointer
408 if constexpr (__has_allocate_hint<_Alloc, size_type, const_void_pointer>)
409 return __a.allocate(__n, __hint);
411 return __a.allocate(__n);
414#ifdef __glibcxx_allocate_at_least
427 [[nodiscard]]
static constexpr allocation_result<pointer, size_type>
430 if constexpr (
requires { __a.allocate_at_least(__n); })
431 return __a.allocate_at_least(__n);
433 return { __a.allocate(__n), __n };
445 static _GLIBCXX20_CONSTEXPR
void
447 { __a.deallocate(__p, __n); }
460 template<
typename _Tp,
typename... _Args>
461#if __cpp_concepts && __cpp_constexpr_dynamic_alloc
462 requires __can_construct<_Alloc, _Tp, _Args...>
463 static constexpr void
465 static __enable_if_t<__can_construct<_Alloc, _Tp, _Args...>>
467 construct(_Alloc& __a, _Tp* __p, _Args&&... __args)
468 noexcept(_S_nothrow_construct<_Tp, _Args...>())
470 if constexpr (__has_construct<_Alloc, _Tp, _Args...>)
484 template<
typename _Tp>
485 static _GLIBCXX20_CONSTEXPR
void
487 noexcept(_S_nothrow_destroy<_Tp>())
489 if constexpr (__has_destroy<_Alloc, _Tp>)
504 max_size(
const _Alloc& __a)
noexcept
506 if constexpr (__has_max_size<_Alloc>)
507 return __a.max_size();
511 return __gnu_cxx::__numeric_traits<size_type>::__max
523 static _GLIBCXX20_CONSTEXPR _Alloc
526 if constexpr (__has_soccc<_Alloc>)
527 return __rhs.select_on_container_copy_construction();
533#if __cpp_constexpr >= 201304
534 template<
typename _Tp,
typename... _Args>
535 static constexpr bool
536 _S_nothrow_construct(_Alloc* __a =
nullptr, _Tp* __p =
nullptr)
538 if constexpr (__has_construct<_Alloc, _Tp, _Args...>)
541 return __is_nothrow_new_constructible<_Tp, _Args...>;
544 template<
typename _Tp>
545 static constexpr bool
546 _S_nothrow_destroy(_Alloc* __a =
nullptr, _Tp* __p =
nullptr)
548 if constexpr (__has_destroy<_Alloc, _Tp>)
549 return noexcept(__a->destroy(__p));
551 return is_nothrow_destructible<_Tp>::value;
554 template<
typename _Tp,
typename... _Args>
556 __enable_if_t<__has_construct<_Alloc, _Tp, _Args...>,
bool>
557 _S_nothrow_construct(_Alloc* __a =
nullptr, _Tp* __p =
nullptr)
560 template<
typename _Tp,
typename... _Args>
562 __enable_if_t<!__has_construct<_Alloc, _Tp, _Args...>,
bool>
563 _S_nothrow_construct(_Alloc* =
nullptr, _Tp* __p =
nullptr)
564 {
return __is_nothrow_new_constructible<_Tp, _Args...>; }
566 template<
typename _Tp>
568 __enable_if_t<__has_destroy<_Alloc, _Tp>,
bool>
569 _S_nothrow_destroy(_Alloc* __a =
nullptr, _Tp* __p =
nullptr)
570 {
return noexcept(__a->destroy(__p)); }
572 template<
typename _Tp>
574 __enable_if_t<!__has_destroy<_Alloc, _Tp>,
bool>
575 _S_nothrow_destroy(_Alloc* =
nullptr, _Tp* __p =
nullptr)
576 {
return is_nothrow_destructible<_Tp>::value; }
579#pragma GCC diagnostic pop
581#undef _GLIBCXX_NO_ALLOC_TRAITS_SPECIALIZATIONS
584#pragma GCC diagnostic push
585#pragma GCC diagnostic ignored "-Winvalid-specialization"
594 template<
typename _Tp>
633 template<
typename _Up>
636 template<
typename _Up>
646 [[__nodiscard__,__gnu__::__always_inline__]]
647 static _GLIBCXX20_CONSTEXPR
pointer
649 {
return __a.allocate(__n); }
661 [[__nodiscard__,__gnu__::__always_inline__]]
662 static _GLIBCXX20_CONSTEXPR pointer
666#if __cplusplus <= 201703L
667 return __a.allocate(__n, __hint);
669 return __a.allocate(__n);
673#ifdef __glibcxx_allocate_at_least
683 [[nodiscard,__gnu__::__always_inline__]]
684 static constexpr allocation_result<pointer, size_type>
686 {
return __a.allocate_at_least(__n); }
697 [[__gnu__::__always_inline__]]
698 static _GLIBCXX20_CONSTEXPR
void
700 { __a.deallocate(__p, __n); }
713 template<
typename _Up,
typename... _Args>
714 [[__gnu__::__always_inline__]]
715 static _GLIBCXX20_CONSTEXPR
void
717 _Up* __p, _Args&&... __args)
718#if __cplusplus <= 201703L
721 noexcept(__is_nothrow_new_constructible<_Up, _Args...>)
724#if __cplusplus <= 201703L
726#elif __cpp_constexpr_dynamic_alloc
740 template<
typename _Up>
741 [[__gnu__::__always_inline__]]
742 static _GLIBCXX20_CONSTEXPR
void
746#if __cplusplus <= 201703L
749 std::destroy_at(__p);
758 [[__gnu__::__always_inline__]]
762#if __cplusplus <= 201703L
763 return __a.max_size();
774 [[__gnu__::__always_inline__]]
775 static _GLIBCXX20_CONSTEXPR allocator_type
826 template<
typename _Up>
829 template<
typename _Up>
836#ifdef __glibcxx_allocate_at_least
837 static allocation_result<void*, size_type>
856 template<
typename _Up,
typename... _Args>
857 [[__gnu__::__always_inline__]]
858 static _GLIBCXX20_CONSTEXPR
void
860 noexcept(__is_nothrow_new_constructible<_Up, _Args...>)
870 template<
typename _Up>
871 [[__gnu__::__always_inline__]]
872 static _GLIBCXX20_CONSTEXPR
void
886 [[__gnu__::__always_inline__]]
891#pragma GCC diagnostic pop
895#pragma GCC diagnostic push
896#pragma GCC diagnostic ignored "-Wc++17-extensions"
897 template<
typename _Alloc>
898 [[__gnu__::__always_inline__]]
899 _GLIBCXX14_CONSTEXPR
inline void
900 __alloc_on_copy(_Alloc& __one,
const _Alloc& __two)
902 using __traits = allocator_traits<_Alloc>;
904 typename __traits::propagate_on_container_copy_assignment::type;
905 if constexpr (__pocca::value)
909 template<
typename _Alloc>
910 [[__gnu__::__always_inline__]]
912 __alloc_on_copy(
const _Alloc& __a)
915 return __traits::select_on_container_copy_construction(__a);
918 template<
typename _Alloc>
919 [[__gnu__::__always_inline__]]
920 _GLIBCXX14_CONSTEXPR
inline void
921 __alloc_on_move(_Alloc& __one, _Alloc& __two)
925 =
typename __traits::propagate_on_container_move_assignment::type;
926 if constexpr (__pocma::value)
930 template<
typename _Alloc>
931 [[__gnu__::__always_inline__]]
932 _GLIBCXX14_CONSTEXPR
inline void
933 __alloc_on_swap(_Alloc& __one, _Alloc& __two)
936 using __pocs =
typename __traits::propagate_on_container_swap::type;
937 if constexpr (__pocs::value)
943#pragma GCC diagnostic pop
945 template<
typename _Alloc,
typename _Tp,
946 typename _ValueT = __remove_cvref_t<typename _Alloc::value_type>,
948 struct __is_alloc_insertable_impl
952 template<
typename _Alloc,
typename _Tp,
typename _ValueT>
953 struct __is_alloc_insertable_impl<_Alloc, _Tp, _ValueT,
955 std::declval<_Alloc&>(), std::declval<_ValueT*>(),
956 std::declval<_Tp>()))>>
963 template<
typename _Alloc>
964 struct __is_copy_insertable
965 : __is_alloc_insertable_impl<_Alloc,
966 typename _Alloc::value_type const&>::type
971 template<
typename _Tp>
972 struct __is_copy_insertable<
allocator<_Tp>>
980 template<
typename _Alloc>
981 struct __is_move_insertable
982 : __is_alloc_insertable_impl<_Alloc, typename _Alloc::value_type>::type
987 template<
typename _Tp>
988 struct __is_move_insertable<
allocator<_Tp>>
994 template<
typename _Alloc,
typename =
void>
997 template<
typename _Alloc>
998 struct __is_allocator<_Alloc,
1000 decltype(std::declval<_Alloc&>().allocate(size_t{}))>>
1003 template<
typename _Alloc>
1004 using _RequireAllocator
1007 template<
typename _Alloc>
1008 using _RequireNotAllocator
1011#if __cpp_concepts >= 201907L
1012 template<
typename _Alloc>
1013 concept __allocator_like =
requires (_Alloc& __a) {
1014 typename _Alloc::value_type;
1015 __a.deallocate(__a.allocate(1u), 1u);
1018 template<
typename _Alloc>
1019 concept __not_allocator_like = !__allocator_like<_Alloc>;
1027 template<
typename _Alloc,
bool = __is_empty(_Alloc)>
1029 {
static void _S_do_it(_Alloc&, _Alloc&) _GLIBCXX_NOEXCEPT { } };
1031 template<
typename _Alloc>
1032 struct __alloc_swap<_Alloc, false>
1035 _S_do_it(_Alloc& __one, _Alloc& __two) _GLIBCXX_NOEXCEPT
1043#if __cplusplus >= 201103L
1044 template<
typename _Tp,
bool
1045 = __or_<is_copy_constructible<typename _Tp::value_type>,
1047 struct __shrink_to_fit_aux
1048 {
static bool _S_do_it(_Tp&)
noexcept {
return false; } };
1050 template<
typename _Tp>
1051 struct __shrink_to_fit_aux<_Tp, true>
1053 _GLIBCXX20_CONSTEXPR
1055 _S_do_it(_Tp& __c)
noexcept
1060 _Tp(__make_move_if_noexcept_iterator(__c.begin()),
1061 __make_move_if_noexcept_iterator(__c.end()),
1062 __c.get_allocator()).swap(__c);
1080 template<
typename _ForwardIterator,
typename _Allocator>
1081 _GLIBCXX20_CONSTEXPR
1083 _Destroy(_ForwardIterator __first, _ForwardIterator __last,
1084 _Allocator& __alloc)
1086 for (; __first != __last; ++__first)
1087#
if __cplusplus < 201103L
1096 template<
typename _ForwardIterator,
typename _Tp>
1097 __attribute__((__always_inline__)) _GLIBCXX20_CONSTEXPR
1099 _Destroy(_ForwardIterator __first, _ForwardIterator __last,
1108_GLIBCXX_END_NAMESPACE_VERSION
__bool_constant< true > true_type
The type used as a compile-time boolean with true value.
__bool_constant< false > false_type
The type used as a compile-time boolean with false value.
auto declval() noexcept -> decltype(__declval< _Tp >(0))
constexpr std::remove_reference< _Tp >::type && move(_Tp &&__t) noexcept
Convert a value to an rvalue.
constexpr _Tp * __addressof(_Tp &__r) noexcept
Same as C++11 std::addressof.
constexpr _Tp && forward(typename std::remove_reference< _Tp >::type &__t) noexcept
Forward an lvalue.
ISO C++ entities toplevel namespace is std.
constexpr void _Construct(_Tp *__p, _Args &&... __args)
constexpr void _Destroy(_ForwardIterator __first, _ForwardIterator __last)
Define a member typedef type only if a boolean constant is true.
is_nothrow_move_constructible
Uniform interface to all allocator types.
__detected_or_t< false_type, __pocma, _OuterAlloc > propagate_on_container_move_assignment
typename _Ptr< __v_pointer, void >::type void_pointer
__detected_or_t< value_type *, __pointer, _OuterAlloc > pointer
static constexpr void construct(_OuterAlloc &__a, _Tp *__p, _Args &&... __args) noexcept(_S_nothrow_construct< _Tp, _Args... >())
static constexpr pointer allocate(_OuterAlloc &__a, size_type __n)
typename _Size< _OuterAlloc, difference_type >::type size_type
typename _Ptr< __cv_pointer, const void >::type const_void_pointer
static constexpr allocation_result< pointer, size_type > allocate_at_least(_OuterAlloc &__a, size_type __n)
static constexpr void destroy(_OuterAlloc &__a, _Tp *__p) noexcept(_S_nothrow_destroy< _Tp >())
typename _Diff< _OuterAlloc, pointer >::type difference_type
typename _Ptr< __c_pointer, const value_type >::type const_pointer
_OuterAlloc::value_type value_type
static constexpr void deallocate(_OuterAlloc &__a, pointer __p, size_type __n)
typename __detected_or_t< is_empty< _OuterAlloc >, __equal, _OuterAlloc >::type is_always_equal
static constexpr size_type max_size(const _OuterAlloc &__a) noexcept
__detected_or_t< false_type, __pocca, _OuterAlloc > propagate_on_container_copy_assignment
static constexpr _OuterAlloc select_on_container_copy_construction(const _OuterAlloc &__rhs)
__detected_or_t< false_type, __pocs, _OuterAlloc > propagate_on_container_swap
_OuterAlloc allocator_type
allocator< _Tp > allocator_type
The allocator type.
static constexpr void construct(allocator_type &__a, _Up *__p, _Args &&... __args) noexcept(__is_nothrow_new_constructible< _Up, _Args... >)
Construct an object of type _Up.
void * void_pointer
The allocator's void pointer type.
_Tp * pointer
The allocator's pointer type.
false_type propagate_on_container_swap
How the allocator is propagated on swap.
static constexpr pointer allocate(allocator_type &__a, size_type __n)
Allocate memory.
_Tp value_type
The allocated type.
static constexpr pointer allocate(allocator_type &__a, size_type __n, const_void_pointer __hint)
Allocate memory.
std::ptrdiff_t difference_type
The allocator's difference type.
true_type is_always_equal
Whether all instances of the allocator type compare equal.
const _Tp * const_pointer
The allocator's const pointer type.
static constexpr allocation_result< pointer, size_type > allocate_at_least(allocator_type &__a, size_type __n)
Allocate memory, generously.
const void * const_void_pointer
The allocator's const void pointer type.
true_type propagate_on_container_move_assignment
How the allocator is propagated on move assignment.
static constexpr void deallocate(allocator_type &__a, pointer __p, size_type __n)
Deallocate memory.
static constexpr size_type max_size(const allocator_type &__a) noexcept
The maximum supported allocation size.
static constexpr allocator_type select_on_container_copy_construction(const allocator_type &__rhs)
Obtain an allocator to use when copying a container.
static constexpr void destroy(allocator_type &__a, _Up *__p) noexcept(is_nothrow_destructible< _Up >::value)
Destroy an object of type _Up.
false_type propagate_on_container_copy_assignment
How the allocator is propagated on copy assignment.
std::size_t size_type
The allocator's size type.
false_type propagate_on_container_copy_assignment
How the allocator is propagated on copy assignment.
void * pointer
The allocator's pointer type.
void * void_pointer
The allocator's void pointer type.
static void deallocate(allocator_type &, void *, size_type)=delete
deallocate is ill-formed for allocator<void>
allocator< void > allocator_type
The allocator type.
true_type is_always_equal
Whether all instances of the allocator type compare equal.
void value_type
The allocated type.
static size_type max_size(const allocator_type &)=delete
max_size is ill-formed for allocator<void>
std::size_t size_type
The allocator's size type.
true_type propagate_on_container_move_assignment
How the allocator is propagated on move assignment.
const void * const_pointer
The allocator's const pointer type.
std::ptrdiff_t difference_type
The allocator's difference type.
static void * allocate(allocator_type &, size_type, const void *=nullptr)=delete
allocate is ill-formed for allocator<void>
static constexpr allocator_type select_on_container_copy_construction(const allocator_type &__rhs)
Obtain an allocator to use when copying a container.
static constexpr void construct(allocator_type &, _Up *__p, _Args &&... __args) noexcept(__is_nothrow_new_constructible< _Up, _Args... >)
Construct an object of type _Up.
const void * const_void_pointer
The allocator's const void pointer type.
static constexpr void destroy(allocator_type &, _Up *__p) noexcept(is_nothrow_destructible< _Up >::value)
Destroy an object of type _Up.
false_type propagate_on_container_swap
How the allocator is propagated on swap.
The standard allocator, as per C++03 [20.4.1].
Uniform interface to all pointer-like types.