1 //===- llvm/Support/PointerLikeTypeTraits.h - Pointer Traits ----*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This file defines the PointerLikeTypeTraits class. This allows data
10 // structures to reason about pointers and other things that are pointer sized.
12 //===----------------------------------------------------------------------===//
14 #ifndef LLVM_SUPPORT_POINTERLIKETYPETRAITS_H
15 #define LLVM_SUPPORT_POINTERLIKETYPETRAITS_H
17 #include "llvm/Support/DataTypes.h"
19 #include <type_traits>
23 /// A traits type that is used to handle pointer types and things that are just
24 /// wrappers for pointers as a uniform entity.
25 template <typename T
> struct PointerLikeTypeTraits
;
28 /// A tiny meta function to compute the log2 of a compile time constant.
31 : std::integral_constant
<size_t, ConstantLog2
<N
/ 2>::value
+ 1> {};
32 template <> struct ConstantLog2
<1> : std::integral_constant
<size_t, 0> {};
34 // Provide a trait to check if T is pointer-like.
35 template <typename T
, typename U
= void> struct HasPointerLikeTypeTraits
{
36 static const bool value
= false;
39 // sizeof(T) is valid only for a complete T.
40 template <typename T
> struct HasPointerLikeTypeTraits
<
41 T
, decltype((sizeof(PointerLikeTypeTraits
<T
>) + sizeof(T
)), void())> {
42 static const bool value
= true;
45 template <typename T
> struct IsPointerLike
{
46 static const bool value
= HasPointerLikeTypeTraits
<T
>::value
;
49 template <typename T
> struct IsPointerLike
<T
*> {
50 static const bool value
= true;
54 // Provide PointerLikeTypeTraits for non-cvr pointers.
55 template <typename T
> struct PointerLikeTypeTraits
<T
*> {
56 static inline void *getAsVoidPointer(T
*P
) { return P
; }
57 static inline T
*getFromVoidPointer(void *P
) { return static_cast<T
*>(P
); }
59 enum { NumLowBitsAvailable
= detail::ConstantLog2
<alignof(T
)>::value
};
62 template <> struct PointerLikeTypeTraits
<void *> {
63 static inline void *getAsVoidPointer(void *P
) { return P
; }
64 static inline void *getFromVoidPointer(void *P
) { return P
; }
66 /// Note, we assume here that void* is related to raw malloc'ed memory and
67 /// that malloc returns objects at least 4-byte aligned. However, this may be
68 /// wrong, or pointers may be from something other than malloc. In this case,
69 /// you should specify a real typed pointer or avoid this template.
71 /// All clients should use assertions to do a run-time check to ensure that
72 /// this is actually true.
73 enum { NumLowBitsAvailable
= 2 };
76 // Provide PointerLikeTypeTraits for const things.
77 template <typename T
> struct PointerLikeTypeTraits
<const T
> {
78 typedef PointerLikeTypeTraits
<T
> NonConst
;
80 static inline const void *getAsVoidPointer(const T P
) {
81 return NonConst::getAsVoidPointer(P
);
83 static inline const T
getFromVoidPointer(const void *P
) {
84 return NonConst::getFromVoidPointer(const_cast<void *>(P
));
86 enum { NumLowBitsAvailable
= NonConst::NumLowBitsAvailable
};
89 // Provide PointerLikeTypeTraits for const pointers.
90 template <typename T
> struct PointerLikeTypeTraits
<const T
*> {
91 typedef PointerLikeTypeTraits
<T
*> NonConst
;
93 static inline const void *getAsVoidPointer(const T
*P
) {
94 return NonConst::getAsVoidPointer(const_cast<T
*>(P
));
96 static inline const T
*getFromVoidPointer(const void *P
) {
97 return NonConst::getFromVoidPointer(const_cast<void *>(P
));
99 enum { NumLowBitsAvailable
= NonConst::NumLowBitsAvailable
};
102 // Provide PointerLikeTypeTraits for uintptr_t.
103 template <> struct PointerLikeTypeTraits
<uintptr_t> {
104 static inline void *getAsVoidPointer(uintptr_t P
) {
105 return reinterpret_cast<void *>(P
);
107 static inline uintptr_t getFromVoidPointer(void *P
) {
108 return reinterpret_cast<uintptr_t>(P
);
110 // No bits are available!
111 enum { NumLowBitsAvailable
= 0 };
114 /// Provide suitable custom traits struct for function pointers.
116 /// Function pointers can't be directly given these traits as functions can't
117 /// have their alignment computed with `alignof` and we need different casting.
119 /// To rely on higher alignment for a specialized use, you can provide a
120 /// customized form of this template explicitly with higher alignment, and
121 /// potentially use alignment attributes on functions to satisfy that.
122 template <int Alignment
, typename FunctionPointerT
>
123 struct FunctionPointerLikeTypeTraits
{
124 enum { NumLowBitsAvailable
= detail::ConstantLog2
<Alignment
>::value
};
125 static inline void *getAsVoidPointer(FunctionPointerT P
) {
126 assert((reinterpret_cast<uintptr_t>(P
) &
127 ~((uintptr_t)-1 << NumLowBitsAvailable
)) == 0 &&
128 "Alignment not satisfied for an actual function pointer!");
129 return reinterpret_cast<void *>(P
);
131 static inline FunctionPointerT
getFromVoidPointer(void *P
) {
132 return reinterpret_cast<FunctionPointerT
>(P
);
136 /// Provide a default specialization for function pointers that assumes 4-byte
139 /// We assume here that functions used with this are always at least 4-byte
140 /// aligned. This means that, for example, thumb functions won't work or systems
141 /// with weird unaligned function pointers won't work. But all practical systems
142 /// we support satisfy this requirement.
143 template <typename ReturnT
, typename
... ParamTs
>
144 struct PointerLikeTypeTraits
<ReturnT (*)(ParamTs
...)>
145 : FunctionPointerLikeTypeTraits
<4, ReturnT (*)(ParamTs
...)> {};
147 } // end namespace llvm