1 //===- llvm/ADT/PointerUnion.h - Discriminated Union of 2 Ptrs --*- 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 PointerUnion class, which is a discriminated union of
12 //===----------------------------------------------------------------------===//
14 #ifndef LLVM_ADT_POINTERUNION_H
15 #define LLVM_ADT_POINTERUNION_H
17 #include "llvm/ADT/DenseMapInfo.h"
18 #include "llvm/ADT/PointerIntPair.h"
19 #include "llvm/Support/PointerLikeTypeTraits.h"
26 template <typename T
> struct PointerUnionTypeSelectorReturn
{
30 /// Get a type based on whether two types are the same or not.
35 /// using Ret = typename PointerUnionTypeSelector<T1, T2, EQ, NE>::Return;
38 /// Ret will be EQ type if T1 is same as T2 or NE type otherwise.
39 template <typename T1
, typename T2
, typename RET_EQ
, typename RET_NE
>
40 struct PointerUnionTypeSelector
{
41 using Return
= typename PointerUnionTypeSelectorReturn
<RET_NE
>::Return
;
44 template <typename T
, typename RET_EQ
, typename RET_NE
>
45 struct PointerUnionTypeSelector
<T
, T
, RET_EQ
, RET_NE
> {
46 using Return
= typename PointerUnionTypeSelectorReturn
<RET_EQ
>::Return
;
49 template <typename T1
, typename T2
, typename RET_EQ
, typename RET_NE
>
50 struct PointerUnionTypeSelectorReturn
<
51 PointerUnionTypeSelector
<T1
, T2
, RET_EQ
, RET_NE
>> {
53 typename PointerUnionTypeSelector
<T1
, T2
, RET_EQ
, RET_NE
>::Return
;
56 /// Provide PointerLikeTypeTraits for void* that is used by PointerUnion
57 /// for the two template arguments.
58 template <typename PT1
, typename PT2
> class PointerUnionUIntTraits
{
60 static inline void *getAsVoidPointer(void *P
) { return P
; }
61 static inline void *getFromVoidPointer(void *P
) { return P
; }
64 PT1BitsAv
= (int)(PointerLikeTypeTraits
<PT1
>::NumLowBitsAvailable
),
65 PT2BitsAv
= (int)(PointerLikeTypeTraits
<PT2
>::NumLowBitsAvailable
),
66 NumLowBitsAvailable
= PT1BitsAv
< PT2BitsAv
? PT1BitsAv
: PT2BitsAv
70 /// A discriminated union of two pointer types, with the discriminator in the
71 /// low bit of the pointer.
73 /// This implementation is extremely efficient in space due to leveraging the
74 /// low bits of the pointer, while exposing a natural and type-safe API.
76 /// Common use patterns would be something like this:
77 /// PointerUnion<int*, float*> P;
79 /// printf("%d %d", P.is<int*>(), P.is<float*>()); // prints "1 0"
80 /// X = P.get<int*>(); // ok.
81 /// Y = P.get<float*>(); // runtime assertion failure.
82 /// Z = P.get<double*>(); // compile time failure.
84 /// Y = P.get<float*>(); // ok.
85 /// X = P.get<int*>(); // runtime assertion failure.
86 template <typename PT1
, typename PT2
> class PointerUnion
{
89 PointerIntPair
<void *, 1, bool, PointerUnionUIntTraits
<PT1
, PT2
>>;
95 static const int Num
= 0;
98 static const int Num
= 1;
100 template <typename T
> struct UNION_DOESNT_CONTAIN_TYPE
{};
103 PointerUnion() = default;
105 : Val(const_cast<void *>(
106 PointerLikeTypeTraits
<PT1
>::getAsVoidPointer(V
))) {}
108 : Val(const_cast<void *>(PointerLikeTypeTraits
<PT2
>::getAsVoidPointer(V
)),
111 /// Test if the pointer held in the union is null, regardless of
112 /// which type it is.
113 bool isNull() const {
114 // Convert from the void* to one of the pointer types, to make sure that
115 // we recursively strip off low bits if we have a nested PointerUnion.
116 return !PointerLikeTypeTraits
<PT1
>::getFromVoidPointer(Val
.getPointer());
119 explicit operator bool() const { return !isNull(); }
121 /// Test if the Union currently holds the type matching T.
122 template <typename T
> int is() const {
123 using Ty
= typename ::llvm::PointerUnionTypeSelector
<
125 ::llvm::PointerUnionTypeSelector
<PT2
, T
, IsPT2
,
126 UNION_DOESNT_CONTAIN_TYPE
<T
>>>::Return
;
128 return static_cast<int>(Val
.getInt()) == TyNo
;
131 /// Returns the value of the specified pointer type.
133 /// If the specified pointer type is incorrect, assert.
134 template <typename T
> T
get() const {
135 assert(is
<T
>() && "Invalid accessor called");
136 return PointerLikeTypeTraits
<T
>::getFromVoidPointer(Val
.getPointer());
139 /// Returns the current pointer if it is of the specified pointer type,
140 /// otherwises returns null.
141 template <typename T
> T
dyn_cast() const {
147 /// If the union is set to the first pointer type get an address pointing to
149 PT1
const *getAddrOfPtr1() const {
150 return const_cast<PointerUnion
*>(this)->getAddrOfPtr1();
153 /// If the union is set to the first pointer type get an address pointing to
155 PT1
*getAddrOfPtr1() {
156 assert(is
<PT1
>() && "Val is not the first pointer");
158 get
<PT1
>() == Val
.getPointer() &&
159 "Can't get the address because PointerLikeTypeTraits changes the ptr");
160 return const_cast<PT1
*>(
161 reinterpret_cast<const PT1
*>(Val
.getAddrOfPointer()));
164 /// Assignment from nullptr which just clears the union.
165 const PointerUnion
&operator=(std::nullptr_t
) {
166 Val
.initWithPointer(nullptr);
170 /// Assignment operators - Allow assigning into this union from either
171 /// pointer type, setting the discriminator to remember what it came from.
172 const PointerUnion
&operator=(const PT1
&RHS
) {
174 const_cast<void *>(PointerLikeTypeTraits
<PT1
>::getAsVoidPointer(RHS
)));
177 const PointerUnion
&operator=(const PT2
&RHS
) {
178 Val
.setPointerAndInt(
179 const_cast<void *>(PointerLikeTypeTraits
<PT2
>::getAsVoidPointer(RHS
)),
184 void *getOpaqueValue() const { return Val
.getOpaqueValue(); }
185 static inline PointerUnion
getFromOpaqueValue(void *VP
) {
187 V
.Val
= ValTy::getFromOpaqueValue(VP
);
192 template <typename PT1
, typename PT2
>
193 bool operator==(PointerUnion
<PT1
, PT2
> lhs
, PointerUnion
<PT1
, PT2
> rhs
) {
194 return lhs
.getOpaqueValue() == rhs
.getOpaqueValue();
197 template <typename PT1
, typename PT2
>
198 bool operator!=(PointerUnion
<PT1
, PT2
> lhs
, PointerUnion
<PT1
, PT2
> rhs
) {
199 return lhs
.getOpaqueValue() != rhs
.getOpaqueValue();
202 template <typename PT1
, typename PT2
>
203 bool operator<(PointerUnion
<PT1
, PT2
> lhs
, PointerUnion
<PT1
, PT2
> rhs
) {
204 return lhs
.getOpaqueValue() < rhs
.getOpaqueValue();
207 // Teach SmallPtrSet that PointerUnion is "basically a pointer", that has
208 // # low bits available = min(PT1bits,PT2bits)-1.
209 template <typename PT1
, typename PT2
>
210 struct PointerLikeTypeTraits
<PointerUnion
<PT1
, PT2
>> {
211 static inline void *getAsVoidPointer(const PointerUnion
<PT1
, PT2
> &P
) {
212 return P
.getOpaqueValue();
215 static inline PointerUnion
<PT1
, PT2
> getFromVoidPointer(void *P
) {
216 return PointerUnion
<PT1
, PT2
>::getFromOpaqueValue(P
);
219 // The number of bits available are the min of the two pointer types.
221 NumLowBitsAvailable
= PointerLikeTypeTraits
<
222 typename PointerUnion
<PT1
, PT2
>::ValTy
>::NumLowBitsAvailable
226 /// A pointer union of three pointer types. See documentation for PointerUnion
228 template <typename PT1
, typename PT2
, typename PT3
> class PointerUnion3
{
230 using InnerUnion
= PointerUnion
<PT1
, PT2
>;
231 using ValTy
= PointerUnion
<InnerUnion
, PT3
>;
236 struct IsInnerUnion
{
239 IsInnerUnion(ValTy val
) : Val(val
) {}
241 template <typename T
> int is() const {
242 return Val
.template is
<InnerUnion
>() &&
243 Val
.template get
<InnerUnion
>().template is
<T
>();
246 template <typename T
> T
get() const {
247 return Val
.template get
<InnerUnion
>().template get
<T
>();
254 IsPT3(ValTy val
) : Val(val
) {}
256 template <typename T
> int is() const { return Val
.template is
<T
>(); }
257 template <typename T
> T
get() const { return Val
.template get
<T
>(); }
261 PointerUnion3() = default;
262 PointerUnion3(PT1 V
) { Val
= InnerUnion(V
); }
263 PointerUnion3(PT2 V
) { Val
= InnerUnion(V
); }
264 PointerUnion3(PT3 V
) { Val
= V
; }
266 /// Test if the pointer held in the union is null, regardless of
267 /// which type it is.
268 bool isNull() const { return Val
.isNull(); }
269 explicit operator bool() const { return !isNull(); }
271 /// Test if the Union currently holds the type matching T.
272 template <typename T
> int is() const {
273 // If T is PT1/PT2 choose IsInnerUnion otherwise choose IsPT3.
274 using Ty
= typename ::llvm::PointerUnionTypeSelector
<
275 PT1
, T
, IsInnerUnion
,
276 ::llvm::PointerUnionTypeSelector
<PT2
, T
, IsInnerUnion
, IsPT3
>>::Return
;
277 return Ty(Val
).template is
<T
>();
280 /// Returns the value of the specified pointer type.
282 /// If the specified pointer type is incorrect, assert.
283 template <typename T
> T
get() const {
284 assert(is
<T
>() && "Invalid accessor called");
285 // If T is PT1/PT2 choose IsInnerUnion otherwise choose IsPT3.
286 using Ty
= typename ::llvm::PointerUnionTypeSelector
<
287 PT1
, T
, IsInnerUnion
,
288 ::llvm::PointerUnionTypeSelector
<PT2
, T
, IsInnerUnion
, IsPT3
>>::Return
;
289 return Ty(Val
).template get
<T
>();
292 /// Returns the current pointer if it is of the specified pointer type,
293 /// otherwises returns null.
294 template <typename T
> T
dyn_cast() const {
300 /// Assignment from nullptr which just clears the union.
301 const PointerUnion3
&operator=(std::nullptr_t
) {
306 /// Assignment operators - Allow assigning into this union from either
307 /// pointer type, setting the discriminator to remember what it came from.
308 const PointerUnion3
&operator=(const PT1
&RHS
) {
309 Val
= InnerUnion(RHS
);
312 const PointerUnion3
&operator=(const PT2
&RHS
) {
313 Val
= InnerUnion(RHS
);
316 const PointerUnion3
&operator=(const PT3
&RHS
) {
321 void *getOpaqueValue() const { return Val
.getOpaqueValue(); }
322 static inline PointerUnion3
getFromOpaqueValue(void *VP
) {
324 V
.Val
= ValTy::getFromOpaqueValue(VP
);
329 // Teach SmallPtrSet that PointerUnion3 is "basically a pointer", that has
330 // # low bits available = min(PT1bits,PT2bits,PT2bits)-2.
331 template <typename PT1
, typename PT2
, typename PT3
>
332 struct PointerLikeTypeTraits
<PointerUnion3
<PT1
, PT2
, PT3
>> {
333 static inline void *getAsVoidPointer(const PointerUnion3
<PT1
, PT2
, PT3
> &P
) {
334 return P
.getOpaqueValue();
337 static inline PointerUnion3
<PT1
, PT2
, PT3
> getFromVoidPointer(void *P
) {
338 return PointerUnion3
<PT1
, PT2
, PT3
>::getFromOpaqueValue(P
);
341 // The number of bits available are the min of the two pointer types.
343 NumLowBitsAvailable
= PointerLikeTypeTraits
<
344 typename PointerUnion3
<PT1
, PT2
, PT3
>::ValTy
>::NumLowBitsAvailable
348 template <typename PT1
, typename PT2
, typename PT3
>
349 bool operator<(PointerUnion3
<PT1
, PT2
, PT3
> lhs
,
350 PointerUnion3
<PT1
, PT2
, PT3
> rhs
) {
351 return lhs
.getOpaqueValue() < rhs
.getOpaqueValue();
354 /// A pointer union of four pointer types. See documentation for PointerUnion
356 template <typename PT1
, typename PT2
, typename PT3
, typename PT4
>
357 class PointerUnion4
{
359 using InnerUnion1
= PointerUnion
<PT1
, PT2
>;
360 using InnerUnion2
= PointerUnion
<PT3
, PT4
>;
361 using ValTy
= PointerUnion
<InnerUnion1
, InnerUnion2
>;
367 PointerUnion4() = default;
368 PointerUnion4(PT1 V
) { Val
= InnerUnion1(V
); }
369 PointerUnion4(PT2 V
) { Val
= InnerUnion1(V
); }
370 PointerUnion4(PT3 V
) { Val
= InnerUnion2(V
); }
371 PointerUnion4(PT4 V
) { Val
= InnerUnion2(V
); }
373 /// Test if the pointer held in the union is null, regardless of
374 /// which type it is.
375 bool isNull() const { return Val
.isNull(); }
376 explicit operator bool() const { return !isNull(); }
378 /// Test if the Union currently holds the type matching T.
379 template <typename T
> int is() const {
380 // If T is PT1/PT2 choose InnerUnion1 otherwise choose InnerUnion2.
381 using Ty
= typename ::llvm::PointerUnionTypeSelector
<
383 ::llvm::PointerUnionTypeSelector
<PT2
, T
, InnerUnion1
,
384 InnerUnion2
>>::Return
;
385 return Val
.template is
<Ty
>() && Val
.template get
<Ty
>().template is
<T
>();
388 /// Returns the value of the specified pointer type.
390 /// If the specified pointer type is incorrect, assert.
391 template <typename T
> T
get() const {
392 assert(is
<T
>() && "Invalid accessor called");
393 // If T is PT1/PT2 choose InnerUnion1 otherwise choose InnerUnion2.
394 using Ty
= typename ::llvm::PointerUnionTypeSelector
<
396 ::llvm::PointerUnionTypeSelector
<PT2
, T
, InnerUnion1
,
397 InnerUnion2
>>::Return
;
398 return Val
.template get
<Ty
>().template get
<T
>();
401 /// Returns the current pointer if it is of the specified pointer type,
402 /// otherwises returns null.
403 template <typename T
> T
dyn_cast() const {
409 /// Assignment from nullptr which just clears the union.
410 const PointerUnion4
&operator=(std::nullptr_t
) {
415 /// Assignment operators - Allow assigning into this union from either
416 /// pointer type, setting the discriminator to remember what it came from.
417 const PointerUnion4
&operator=(const PT1
&RHS
) {
418 Val
= InnerUnion1(RHS
);
421 const PointerUnion4
&operator=(const PT2
&RHS
) {
422 Val
= InnerUnion1(RHS
);
425 const PointerUnion4
&operator=(const PT3
&RHS
) {
426 Val
= InnerUnion2(RHS
);
429 const PointerUnion4
&operator=(const PT4
&RHS
) {
430 Val
= InnerUnion2(RHS
);
434 void *getOpaqueValue() const { return Val
.getOpaqueValue(); }
435 static inline PointerUnion4
getFromOpaqueValue(void *VP
) {
437 V
.Val
= ValTy::getFromOpaqueValue(VP
);
442 // Teach SmallPtrSet that PointerUnion4 is "basically a pointer", that has
443 // # low bits available = min(PT1bits,PT2bits,PT2bits)-2.
444 template <typename PT1
, typename PT2
, typename PT3
, typename PT4
>
445 struct PointerLikeTypeTraits
<PointerUnion4
<PT1
, PT2
, PT3
, PT4
>> {
447 getAsVoidPointer(const PointerUnion4
<PT1
, PT2
, PT3
, PT4
> &P
) {
448 return P
.getOpaqueValue();
451 static inline PointerUnion4
<PT1
, PT2
, PT3
, PT4
> getFromVoidPointer(void *P
) {
452 return PointerUnion4
<PT1
, PT2
, PT3
, PT4
>::getFromOpaqueValue(P
);
455 // The number of bits available are the min of the two pointer types.
457 NumLowBitsAvailable
= PointerLikeTypeTraits
<
458 typename PointerUnion4
<PT1
, PT2
, PT3
, PT4
>::ValTy
>::NumLowBitsAvailable
462 // Teach DenseMap how to use PointerUnions as keys.
463 template <typename T
, typename U
> struct DenseMapInfo
<PointerUnion
<T
, U
>> {
464 using Pair
= PointerUnion
<T
, U
>;
465 using FirstInfo
= DenseMapInfo
<T
>;
466 using SecondInfo
= DenseMapInfo
<U
>;
468 static inline Pair
getEmptyKey() { return Pair(FirstInfo::getEmptyKey()); }
470 static inline Pair
getTombstoneKey() {
471 return Pair(FirstInfo::getTombstoneKey());
474 static unsigned getHashValue(const Pair
&PairVal
) {
475 intptr_t key
= (intptr_t)PairVal
.getOpaqueValue();
476 return DenseMapInfo
<intptr_t>::getHashValue(key
);
479 static bool isEqual(const Pair
&LHS
, const Pair
&RHS
) {
480 return LHS
.template is
<T
>() == RHS
.template is
<T
>() &&
481 (LHS
.template is
<T
>() ? FirstInfo::isEqual(LHS
.template get
<T
>(),
482 RHS
.template get
<T
>())
483 : SecondInfo::isEqual(LHS
.template get
<U
>(),
484 RHS
.template get
<U
>()));
488 } // end namespace llvm
490 #endif // LLVM_ADT_POINTERUNION_H