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