blob: 2bcdf546c6e4bd2c27d997c9d7e357493ddeec0a [file] [log] [blame]
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01001//===- llvm/ADT/PointerUnion.h - Discriminated Union of 2 Ptrs --*- C++ -*-===//
2//
Andrew Walbran16937d02019-10-22 13:54:20 +01003// 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
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01006//
7//===----------------------------------------------------------------------===//
8//
9// This file defines the PointerUnion class, which is a discriminated union of
10// pointer types.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_ADT_POINTERUNION_H
15#define LLVM_ADT_POINTERUNION_H
16
17#include "llvm/ADT/DenseMapInfo.h"
18#include "llvm/ADT/PointerIntPair.h"
19#include "llvm/Support/PointerLikeTypeTraits.h"
20#include <cassert>
21#include <cstddef>
22#include <cstdint>
23
24namespace llvm {
25
26template <typename T> struct PointerUnionTypeSelectorReturn {
27 using Return = T;
28};
29
30/// Get a type based on whether two types are the same or not.
31///
32/// For:
33///
34/// \code
35/// using Ret = typename PointerUnionTypeSelector<T1, T2, EQ, NE>::Return;
36/// \endcode
37///
38/// Ret will be EQ type if T1 is same as T2 or NE type otherwise.
39template <typename T1, typename T2, typename RET_EQ, typename RET_NE>
40struct PointerUnionTypeSelector {
41 using Return = typename PointerUnionTypeSelectorReturn<RET_NE>::Return;
42};
43
44template <typename T, typename RET_EQ, typename RET_NE>
45struct PointerUnionTypeSelector<T, T, RET_EQ, RET_NE> {
46 using Return = typename PointerUnionTypeSelectorReturn<RET_EQ>::Return;
47};
48
49template <typename T1, typename T2, typename RET_EQ, typename RET_NE>
50struct PointerUnionTypeSelectorReturn<
51 PointerUnionTypeSelector<T1, T2, RET_EQ, RET_NE>> {
52 using Return =
53 typename PointerUnionTypeSelector<T1, T2, RET_EQ, RET_NE>::Return;
54};
55
Andrew Walbran3d2c1972020-04-07 12:24:26 +010056namespace pointer_union_detail {
57 constexpr int constexprMin(int a, int b) { return a < b ? a : b; }
58 /// Determine the number of bits required to store integers with values < n.
59 /// This is ceil(log2(n)).
60 constexpr int bitsRequired(unsigned n) {
61 return n > 1 ? 1 + bitsRequired((n + 1) / 2) : 0;
62 }
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010063
Andrew Walbran3d2c1972020-04-07 12:24:26 +010064 // FIXME: In C++14, replace this with
65 // std::min({PointerLikeTypeTraits<Ts>::NumLowBitsAvailable...})
66 template <typename T> constexpr int lowBitsAvailable() {
67 return PointerLikeTypeTraits<T>::NumLowBitsAvailable;
68 }
69 template <typename T1, typename T2, typename... Ts>
70 constexpr int lowBitsAvailable() {
71 return constexprMin(lowBitsAvailable<T1>(), lowBitsAvailable<T2, Ts...>());
72 }
73
74 /// Find the index of a type in a list of types. TypeIndex<T, Us...>::Index
75 /// is the index of T in Us, or sizeof...(Us) if T does not appear in the
76 /// list.
77 template <typename T, typename ...Us> struct TypeIndex;
78 template <typename T, typename ...Us> struct TypeIndex<T, T, Us...> {
79 static constexpr int Index = 0;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010080 };
Andrew Walbran3d2c1972020-04-07 12:24:26 +010081 template <typename T, typename U, typename... Us>
82 struct TypeIndex<T, U, Us...> {
83 static constexpr int Index = 1 + TypeIndex<T, Us...>::Index;
84 };
85 template <typename T> struct TypeIndex<T> {
86 static constexpr int Index = 0;
87 };
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010088
Andrew Walbran3d2c1972020-04-07 12:24:26 +010089 /// Find the first type in a list of types.
90 template <typename T, typename...> struct GetFirstType {
91 using type = T;
92 };
93
94 /// Provide PointerLikeTypeTraits for void* that is used by PointerUnion
95 /// for the template arguments.
96 template <typename ...PTs> class PointerUnionUIntTraits {
97 public:
98 static inline void *getAsVoidPointer(void *P) { return P; }
99 static inline void *getFromVoidPointer(void *P) { return P; }
100 static constexpr int NumLowBitsAvailable = lowBitsAvailable<PTs...>();
101 };
102
103 /// Implement assigment in terms of construction.
104 template <typename Derived, typename T> struct AssignableFrom {
105 Derived &operator=(T t) {
106 return static_cast<Derived &>(*this) = Derived(t);
107 }
108 };
109
110 template <typename Derived, typename ValTy, int I, typename ...Types>
111 class PointerUnionMembers;
112
113 template <typename Derived, typename ValTy, int I>
114 class PointerUnionMembers<Derived, ValTy, I> {
115 protected:
116 ValTy Val;
117 PointerUnionMembers() = default;
118 PointerUnionMembers(ValTy Val) : Val(Val) {}
119
120 friend struct PointerLikeTypeTraits<Derived>;
121 };
122
123 template <typename Derived, typename ValTy, int I, typename Type,
124 typename ...Types>
125 class PointerUnionMembers<Derived, ValTy, I, Type, Types...>
126 : public PointerUnionMembers<Derived, ValTy, I + 1, Types...> {
127 using Base = PointerUnionMembers<Derived, ValTy, I + 1, Types...>;
128 public:
129 using Base::Base;
130 PointerUnionMembers() = default;
131 PointerUnionMembers(Type V)
132 : Base(ValTy(const_cast<void *>(
133 PointerLikeTypeTraits<Type>::getAsVoidPointer(V)),
134 I)) {}
135
136 using Base::operator=;
137 Derived &operator=(Type V) {
138 this->Val = ValTy(
139 const_cast<void *>(PointerLikeTypeTraits<Type>::getAsVoidPointer(V)),
140 I);
141 return static_cast<Derived &>(*this);
142 };
143 };
144}
145
146/// A discriminated union of two or more pointer types, with the discriminator
147/// in the low bit of the pointer.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100148///
149/// This implementation is extremely efficient in space due to leveraging the
150/// low bits of the pointer, while exposing a natural and type-safe API.
151///
152/// Common use patterns would be something like this:
153/// PointerUnion<int*, float*> P;
154/// P = (int*)0;
155/// printf("%d %d", P.is<int*>(), P.is<float*>()); // prints "1 0"
156/// X = P.get<int*>(); // ok.
157/// Y = P.get<float*>(); // runtime assertion failure.
158/// Z = P.get<double*>(); // compile time failure.
159/// P = (float*)0;
160/// Y = P.get<float*>(); // ok.
161/// X = P.get<int*>(); // runtime assertion failure.
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100162template <typename... PTs>
163class PointerUnion
164 : public pointer_union_detail::PointerUnionMembers<
165 PointerUnion<PTs...>,
166 PointerIntPair<
167 void *, pointer_union_detail::bitsRequired(sizeof...(PTs)), int,
168 pointer_union_detail::PointerUnionUIntTraits<PTs...>>,
169 0, PTs...> {
170 // The first type is special in some ways, but we don't want PointerUnion to
171 // be a 'template <typename First, typename ...Rest>' because it's much more
172 // convenient to have a name for the whole pack. So split off the first type
173 // here.
174 using First = typename pointer_union_detail::GetFirstType<PTs...>::type;
175 using Base = typename PointerUnion::PointerUnionMembers;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100176
177public:
178 PointerUnion() = default;
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100179
180 PointerUnion(std::nullptr_t) : PointerUnion() {}
181 using Base::Base;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100182
183 /// Test if the pointer held in the union is null, regardless of
184 /// which type it is.
185 bool isNull() const {
186 // Convert from the void* to one of the pointer types, to make sure that
187 // we recursively strip off low bits if we have a nested PointerUnion.
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100188 return !PointerLikeTypeTraits<First>::getFromVoidPointer(
189 this->Val.getPointer());
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100190 }
191
192 explicit operator bool() const { return !isNull(); }
193
194 /// Test if the Union currently holds the type matching T.
195 template <typename T> int is() const {
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100196 constexpr int Index = pointer_union_detail::TypeIndex<T, PTs...>::Index;
197 static_assert(Index < sizeof...(PTs),
198 "PointerUnion::is<T> given type not in the union");
199 return this->Val.getInt() == Index;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100200 }
201
202 /// Returns the value of the specified pointer type.
203 ///
204 /// If the specified pointer type is incorrect, assert.
205 template <typename T> T get() const {
206 assert(is<T>() && "Invalid accessor called");
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100207 return PointerLikeTypeTraits<T>::getFromVoidPointer(this->Val.getPointer());
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100208 }
209
210 /// Returns the current pointer if it is of the specified pointer type,
211 /// otherwises returns null.
212 template <typename T> T dyn_cast() const {
213 if (is<T>())
214 return get<T>();
215 return T();
216 }
217
218 /// If the union is set to the first pointer type get an address pointing to
219 /// it.
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100220 First const *getAddrOfPtr1() const {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100221 return const_cast<PointerUnion *>(this)->getAddrOfPtr1();
222 }
223
224 /// If the union is set to the first pointer type get an address pointing to
225 /// it.
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100226 First *getAddrOfPtr1() {
227 assert(is<First>() && "Val is not the first pointer");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100228 assert(
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100229 get<First>() == this->Val.getPointer() &&
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100230 "Can't get the address because PointerLikeTypeTraits changes the ptr");
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100231 return const_cast<First *>(
232 reinterpret_cast<const First *>(this->Val.getAddrOfPointer()));
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100233 }
234
235 /// Assignment from nullptr which just clears the union.
236 const PointerUnion &operator=(std::nullptr_t) {
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100237 this->Val.initWithPointer(nullptr);
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100238 return *this;
239 }
240
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100241 /// Assignment from elements of the union.
242 using Base::operator=;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100243
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100244 void *getOpaqueValue() const { return this->Val.getOpaqueValue(); }
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100245 static inline PointerUnion getFromOpaqueValue(void *VP) {
246 PointerUnion V;
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100247 V.Val = decltype(V.Val)::getFromOpaqueValue(VP);
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100248 return V;
249 }
250};
251
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100252template <typename ...PTs>
253bool operator==(PointerUnion<PTs...> lhs, PointerUnion<PTs...> rhs) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100254 return lhs.getOpaqueValue() == rhs.getOpaqueValue();
255}
256
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100257template <typename ...PTs>
258bool operator!=(PointerUnion<PTs...> lhs, PointerUnion<PTs...> rhs) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100259 return lhs.getOpaqueValue() != rhs.getOpaqueValue();
260}
261
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100262template <typename ...PTs>
263bool operator<(PointerUnion<PTs...> lhs, PointerUnion<PTs...> rhs) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100264 return lhs.getOpaqueValue() < rhs.getOpaqueValue();
265}
266
267// Teach SmallPtrSet that PointerUnion is "basically a pointer", that has
268// # low bits available = min(PT1bits,PT2bits)-1.
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100269template <typename ...PTs>
270struct PointerLikeTypeTraits<PointerUnion<PTs...>> {
271 static inline void *getAsVoidPointer(const PointerUnion<PTs...> &P) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100272 return P.getOpaqueValue();
273 }
274
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100275 static inline PointerUnion<PTs...> getFromVoidPointer(void *P) {
276 return PointerUnion<PTs...>::getFromOpaqueValue(P);
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100277 }
278
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100279 // The number of bits available are the min of the pointer types minus the
280 // bits needed for the discriminator.
281 static constexpr int NumLowBitsAvailable = PointerLikeTypeTraits<decltype(
282 PointerUnion<PTs...>::Val)>::NumLowBitsAvailable;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100283};
284
285/// A pointer union of three pointer types. See documentation for PointerUnion
286/// for usage.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100287template <typename PT1, typename PT2, typename PT3>
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100288using PointerUnion3 = PointerUnion<PT1, PT2, PT3>;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100289
290/// A pointer union of four pointer types. See documentation for PointerUnion
291/// for usage.
292template <typename PT1, typename PT2, typename PT3, typename PT4>
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100293using PointerUnion4 = PointerUnion<PT1, PT2, PT3, PT4>;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100294
295// Teach DenseMap how to use PointerUnions as keys.
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100296template <typename ...PTs> struct DenseMapInfo<PointerUnion<PTs...>> {
297 using Union = PointerUnion<PTs...>;
298 using FirstInfo =
299 DenseMapInfo<typename pointer_union_detail::GetFirstType<PTs...>::type>;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100300
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100301 static inline Union getEmptyKey() { return Union(FirstInfo::getEmptyKey()); }
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100302
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100303 static inline Union getTombstoneKey() {
304 return Union(FirstInfo::getTombstoneKey());
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100305 }
306
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100307 static unsigned getHashValue(const Union &UnionVal) {
308 intptr_t key = (intptr_t)UnionVal.getOpaqueValue();
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100309 return DenseMapInfo<intptr_t>::getHashValue(key);
310 }
311
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100312 static bool isEqual(const Union &LHS, const Union &RHS) {
313 return LHS == RHS;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100314 }
315};
316
317} // end namespace llvm
318
319#endif // LLVM_ADT_POINTERUNION_H