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