Line data Source code
1 : //===- llvm/Support/PointerLikeTypeTraits.h - Pointer Traits ----*- C++ -*-===//
2 : //
3 : // The LLVM Compiler Infrastructure
4 : //
5 : // This file is distributed under the University of Illinois Open Source
6 : // License. See LICENSE.TXT for details.
7 : //
8 : //===----------------------------------------------------------------------===//
9 : //
10 : // This file defines the PointerLikeTypeTraits class. This allows data
11 : // structures to reason about pointers and other things that are pointer sized.
12 : //
13 : //===----------------------------------------------------------------------===//
14 :
15 : #ifndef LLVM_SUPPORT_POINTERLIKETYPETRAITS_H
16 : #define LLVM_SUPPORT_POINTERLIKETYPETRAITS_H
17 :
18 : #include "llvm/Support/DataTypes.h"
19 : #include <assert.h>
20 : #include <type_traits>
21 :
22 : namespace llvm {
23 :
24 : /// A traits type that is used to handle pointer types and things that are just
25 : /// wrappers for pointers as a uniform entity.
26 : template <typename T> struct PointerLikeTypeTraits;
27 :
28 : namespace detail {
29 : /// A tiny meta function to compute the log2 of a compile time constant.
30 : template <size_t N>
31 : struct ConstantLog2
32 : : std::integral_constant<size_t, ConstantLog2<N / 2>::value + 1> {};
33 : template <> struct ConstantLog2<1> : std::integral_constant<size_t, 0> {};
34 :
35 : // Provide a trait to check if T is pointer-like.
36 : template <typename T, typename U = void> struct HasPointerLikeTypeTraits {
37 : static const bool value = false;
38 : };
39 :
40 : // sizeof(T) is valid only for a complete T.
41 : template <typename T> struct HasPointerLikeTypeTraits<
42 : T, decltype((sizeof(PointerLikeTypeTraits<T>) + sizeof(T)), void())> {
43 : static const bool value = true;
44 : };
45 :
46 : template <typename T> struct IsPointerLike {
47 : static const bool value = HasPointerLikeTypeTraits<T>::value;
48 : };
49 :
50 : template <typename T> struct IsPointerLike<T *> {
51 : static const bool value = true;
52 : };
53 : } // namespace detail
54 :
55 : // Provide PointerLikeTypeTraits for non-cvr pointers.
56 : template <typename T> struct PointerLikeTypeTraits<T *> {
57 : static inline void *getAsVoidPointer(T *P) { return P; }
58 : static inline T *getFromVoidPointer(void *P) { return static_cast<T *>(P); }
59 :
60 : enum { NumLowBitsAvailable = detail::ConstantLog2<alignof(T)>::value };
61 : };
62 :
63 : template <> struct PointerLikeTypeTraits<void *> {
64 : static inline void *getAsVoidPointer(void *P) { return P; }
65 : static inline void *getFromVoidPointer(void *P) { return P; }
66 :
67 : /// Note, we assume here that void* is related to raw malloc'ed memory and
68 : /// that malloc returns objects at least 4-byte aligned. However, this may be
69 : /// wrong, or pointers may be from something other than malloc. In this case,
70 : /// you should specify a real typed pointer or avoid this template.
71 : ///
72 : /// All clients should use assertions to do a run-time check to ensure that
73 : /// this is actually true.
74 : enum { NumLowBitsAvailable = 2 };
75 : };
76 :
77 : // Provide PointerLikeTypeTraits for const things.
78 : template <typename T> struct PointerLikeTypeTraits<const T> {
79 : typedef PointerLikeTypeTraits<T> NonConst;
80 :
81 : static inline const void *getAsVoidPointer(const T P) {
82 : return NonConst::getAsVoidPointer(P);
83 : }
84 : static inline const T getFromVoidPointer(const void *P) {
85 : return NonConst::getFromVoidPointer(const_cast<void *>(P));
86 : }
87 : enum { NumLowBitsAvailable = NonConst::NumLowBitsAvailable };
88 : };
89 :
90 : // Provide PointerLikeTypeTraits for const pointers.
91 : template <typename T> struct PointerLikeTypeTraits<const T *> {
92 : typedef PointerLikeTypeTraits<T *> NonConst;
93 :
94 : static inline const void *getAsVoidPointer(const T *P) {
95 : return NonConst::getAsVoidPointer(const_cast<T *>(P));
96 : }
97 : static inline const T *getFromVoidPointer(const void *P) {
98 : return NonConst::getFromVoidPointer(const_cast<void *>(P));
99 : }
100 : enum { NumLowBitsAvailable = NonConst::NumLowBitsAvailable };
101 : };
102 :
103 : // Provide PointerLikeTypeTraits for uintptr_t.
104 : template <> struct PointerLikeTypeTraits<uintptr_t> {
105 : static inline void *getAsVoidPointer(uintptr_t P) {
106 : return reinterpret_cast<void *>(P);
107 : }
108 : static inline uintptr_t getFromVoidPointer(void *P) {
109 : return reinterpret_cast<uintptr_t>(P);
110 : }
111 : // No bits are available!
112 : enum { NumLowBitsAvailable = 0 };
113 : };
114 :
115 : /// Provide suitable custom traits struct for function pointers.
116 : ///
117 : /// Function pointers can't be directly given these traits as functions can't
118 : /// have their alignment computed with `alignof` and we need different casting.
119 : ///
120 : /// To rely on higher alignment for a specialized use, you can provide a
121 : /// customized form of this template explicitly with higher alignment, and
122 : /// potentially use alignment attributes on functions to satisfy that.
123 : template <int Alignment, typename FunctionPointerT>
124 : struct FunctionPointerLikeTypeTraits {
125 : enum { NumLowBitsAvailable = detail::ConstantLog2<Alignment>::value };
126 : static inline void *getAsVoidPointer(FunctionPointerT P) {
127 : assert((reinterpret_cast<uintptr_t>(P) &
128 : ~((uintptr_t)-1 << NumLowBitsAvailable)) == 0 &&
129 : "Alignment not satisfied for an actual function pointer!");
130 : return reinterpret_cast<void *>(P);
131 : }
132 : static inline FunctionPointerT getFromVoidPointer(void *P) {
133 76 : return reinterpret_cast<FunctionPointerT>(P);
134 : }
135 : };
136 :
137 : /// Provide a default specialization for function pointers that assumes 4-byte
138 : /// alignment.
139 : ///
140 : /// We assume here that functions used with this are always at least 4-byte
141 : /// aligned. This means that, for example, thumb functions won't work or systems
142 : /// with weird unaligned function pointers won't work. But all practical systems
143 : /// we support satisfy this requirement.
144 : template <typename ReturnT, typename... ParamTs>
145 : struct PointerLikeTypeTraits<ReturnT (*)(ParamTs...)>
146 : : FunctionPointerLikeTypeTraits<4, ReturnT (*)(ParamTs...)> {};
147 :
148 : } // end namespace llvm
149 :
150 : #endif
|