• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- llvm/ADT/PointerUnion.h - Discriminated Union of 2 Ptrs --*- 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 PointerUnion class, which is a discriminated union of
11 // pointer types.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #ifndef LLVM_ADT_POINTERUNION_H
16 #define LLVM_ADT_POINTERUNION_H
17 
18 #include "llvm/ADT/PointerIntPair.h"
19 
20 namespace llvm {
21 
22   template <typename T>
23   struct PointerUnionTypeSelectorReturn {
24     typedef T Return;
25   };
26 
27   /// \brief Get a type based on whether two types are the same or not. For:
28   /// @code
29   /// typedef typename PointerUnionTypeSelector<T1, T2, EQ, NE>::Return Ret;
30   /// @endcode
31   /// Ret will be EQ type if T1 is same as T2 or NE type otherwise.
32   template <typename T1, typename T2, typename RET_EQ, typename RET_NE>
33   struct PointerUnionTypeSelector {
34     typedef typename PointerUnionTypeSelectorReturn<RET_NE>::Return Return;
35   };
36 
37   template <typename T, typename RET_EQ, typename RET_NE>
38   struct PointerUnionTypeSelector<T, T, RET_EQ, RET_NE> {
39     typedef typename PointerUnionTypeSelectorReturn<RET_EQ>::Return Return;
40   };
41 
42   template <typename T1, typename T2, typename RET_EQ, typename RET_NE>
43   struct PointerUnionTypeSelectorReturn<
44                             PointerUnionTypeSelector<T1, T2, RET_EQ, RET_NE> > {
45     typedef typename PointerUnionTypeSelector<T1, T2, RET_EQ, RET_NE>::Return
46         Return;
47   };
48 
49   /// Provide PointerLikeTypeTraits for void* that is used by PointerUnion
50   /// for the two template arguments.
51   template <typename PT1, typename PT2>
52   class PointerUnionUIntTraits {
53   public:
54     static inline void *getAsVoidPointer(void *P) { return P; }
55     static inline void *getFromVoidPointer(void *P) { return P; }
56     enum {
57       PT1BitsAv = PointerLikeTypeTraits<PT1>::NumLowBitsAvailable,
58       PT2BitsAv = PointerLikeTypeTraits<PT2>::NumLowBitsAvailable,
59       NumLowBitsAvailable = PT1BitsAv < PT2BitsAv ? PT1BitsAv : PT2BitsAv
60     };
61   };
62 
63   /// PointerUnion - This implements a discriminated union of two pointer types,
64   /// and keeps the discriminator bit-mangled into the low bits of the pointer.
65   /// This allows the implementation to be extremely efficient in space, but
66   /// permits a very natural and type-safe API.
67   ///
68   /// Common use patterns would be something like this:
69   ///    PointerUnion<int*, float*> P;
70   ///    P = (int*)0;
71   ///    printf("%d %d", P.is<int*>(), P.is<float*>());  // prints "1 0"
72   ///    X = P.get<int*>();     // ok.
73   ///    Y = P.get<float*>();   // runtime assertion failure.
74   ///    Z = P.get<double*>();  // runtime assertion failure (regardless of tag)
75   ///    P = (float*)0;
76   ///    Y = P.get<float*>();   // ok.
77   ///    X = P.get<int*>();     // runtime assertion failure.
78   template <typename PT1, typename PT2>
79   class PointerUnion {
80   public:
81     typedef PointerIntPair<void*, 1, bool,
82                            PointerUnionUIntTraits<PT1,PT2> > ValTy;
83   private:
84     ValTy Val;
85 
86     struct IsPT1 {
87       static const int Num = 0;
88     };
89     struct IsPT2 {
90       static const int Num = 1;
91     };
92     template <typename T>
93     struct UNION_DOESNT_CONTAIN_TYPE { };
94 
95   public:
96     PointerUnion() {}
97 
98     PointerUnion(PT1 V) {
99       Val.setPointer(
100          const_cast<void *>(PointerLikeTypeTraits<PT1>::getAsVoidPointer(V)));
101       Val.setInt(0);
102     }
103     PointerUnion(PT2 V) {
104       Val.setPointer(
105          const_cast<void *>(PointerLikeTypeTraits<PT2>::getAsVoidPointer(V)));
106       Val.setInt(1);
107     }
108 
109     /// isNull - Return true if the pointer held in the union is null,
110     /// regardless of which type it is.
111     bool isNull() const {
112       // Convert from the void* to one of the pointer types, to make sure that
113       // we recursively strip off low bits if we have a nested PointerUnion.
114       return !PointerLikeTypeTraits<PT1>::getFromVoidPointer(Val.getPointer());
115     }
116     operator bool() const { return !isNull(); }
117 
118     /// is<T>() return true if the Union currently holds the type matching T.
119     template<typename T>
120     int is() const {
121       typedef typename
122         ::llvm::PointerUnionTypeSelector<PT1, T, IsPT1,
123           ::llvm::PointerUnionTypeSelector<PT2, T, IsPT2,
124                                     UNION_DOESNT_CONTAIN_TYPE<T> > >::Return Ty;
125       int TyNo = Ty::Num;
126       return static_cast<int>(Val.getInt()) == TyNo;
127     }
128 
129     /// get<T>() - Return the value of the specified pointer type. If the
130     /// specified pointer type is incorrect, assert.
131     template<typename T>
132     T get() const {
133       assert(is<T>() && "Invalid accessor called");
134       return PointerLikeTypeTraits<T>::getFromVoidPointer(Val.getPointer());
135     }
136 
137     /// dyn_cast<T>() - If the current value is of the specified pointer type,
138     /// return it, otherwise return null.
139     template<typename T>
140     T dyn_cast() const {
141       if (is<T>()) return get<T>();
142       return T();
143     }
144 
145     /// \brief If the union is set to the first pointer type we can get an
146     /// address pointing to it.
147     template <typename T>
148     PT1 const *getAddrOf() const {
149       assert(is<PT1>() && "Val is not the first pointer");
150       assert(get<PT1>() == Val.getPointer() &&
151          "Can't get the address because PointerLikeTypeTraits changes the ptr");
152       T const *can_only_get_address_of_first_pointer_type
153                         = reinterpret_cast<PT1 const *>(Val.getAddrOfPointer());
154       return can_only_get_address_of_first_pointer_type;
155     }
156 
157     /// Assignment operators - Allow assigning into this union from either
158     /// pointer type, setting the discriminator to remember what it came from.
159     const PointerUnion &operator=(const PT1 &RHS) {
160       Val.setPointer(
161          const_cast<void *>(PointerLikeTypeTraits<PT1>::getAsVoidPointer(RHS)));
162       Val.setInt(0);
163       return *this;
164     }
165     const PointerUnion &operator=(const PT2 &RHS) {
166       Val.setPointer(
167         const_cast<void *>(PointerLikeTypeTraits<PT2>::getAsVoidPointer(RHS)));
168       Val.setInt(1);
169       return *this;
170     }
171 
172     void *getOpaqueValue() const { return Val.getOpaqueValue(); }
173     static inline PointerUnion getFromOpaqueValue(void *VP) {
174       PointerUnion V;
175       V.Val = ValTy::getFromOpaqueValue(VP);
176       return V;
177     }
178   };
179 
180   // Teach SmallPtrSet that PointerUnion is "basically a pointer", that has
181   // # low bits available = min(PT1bits,PT2bits)-1.
182   template<typename PT1, typename PT2>
183   class PointerLikeTypeTraits<PointerUnion<PT1, PT2> > {
184   public:
185     static inline void *
186     getAsVoidPointer(const PointerUnion<PT1, PT2> &P) {
187       return P.getOpaqueValue();
188     }
189     static inline PointerUnion<PT1, PT2>
190     getFromVoidPointer(void *P) {
191       return PointerUnion<PT1, PT2>::getFromOpaqueValue(P);
192     }
193 
194     // The number of bits available are the min of the two pointer types.
195     enum {
196       NumLowBitsAvailable =
197         PointerLikeTypeTraits<typename PointerUnion<PT1,PT2>::ValTy>
198           ::NumLowBitsAvailable
199     };
200   };
201 
202 
203   /// PointerUnion3 - This is a pointer union of three pointer types.  See
204   /// documentation for PointerUnion for usage.
205   template <typename PT1, typename PT2, typename PT3>
206   class PointerUnion3 {
207   public:
208     typedef PointerUnion<PT1, PT2> InnerUnion;
209     typedef PointerUnion<InnerUnion, PT3> ValTy;
210   private:
211     ValTy Val;
212 
213     struct IsInnerUnion {
214       ValTy Val;
215       IsInnerUnion(ValTy val) : Val(val) { }
216       template<typename T>
217       int is() const {
218         return Val.template is<InnerUnion>() &&
219                Val.template get<InnerUnion>().template is<T>();
220       }
221       template<typename T>
222       T get() const {
223         return Val.template get<InnerUnion>().template get<T>();
224       }
225     };
226 
227     struct IsPT3 {
228       ValTy Val;
229       IsPT3(ValTy val) : Val(val) { }
230       template<typename T>
231       int is() const {
232         return Val.template is<T>();
233       }
234       template<typename T>
235       T get() const {
236         return Val.template get<T>();
237       }
238     };
239 
240   public:
241     PointerUnion3() {}
242 
243     PointerUnion3(PT1 V) {
244       Val = InnerUnion(V);
245     }
246     PointerUnion3(PT2 V) {
247       Val = InnerUnion(V);
248     }
249     PointerUnion3(PT3 V) {
250       Val = V;
251     }
252 
253     /// isNull - Return true if the pointer held in the union is null,
254     /// regardless of which type it is.
255     bool isNull() const { return Val.isNull(); }
256     operator bool() const { return !isNull(); }
257 
258     /// is<T>() return true if the Union currently holds the type matching T.
259     template<typename T>
260     int is() const {
261       // If T is PT1/PT2 choose IsInnerUnion otherwise choose IsPT3.
262       typedef typename
263         ::llvm::PointerUnionTypeSelector<PT1, T, IsInnerUnion,
264           ::llvm::PointerUnionTypeSelector<PT2, T, IsInnerUnion, IsPT3 >
265                                                                    >::Return Ty;
266       return Ty(Val).template is<T>();
267     }
268 
269     /// get<T>() - Return the value of the specified pointer type. If the
270     /// specified pointer type is incorrect, assert.
271     template<typename T>
272     T get() const {
273       assert(is<T>() && "Invalid accessor called");
274       // If T is PT1/PT2 choose IsInnerUnion otherwise choose IsPT3.
275       typedef typename
276         ::llvm::PointerUnionTypeSelector<PT1, T, IsInnerUnion,
277           ::llvm::PointerUnionTypeSelector<PT2, T, IsInnerUnion, IsPT3 >
278                                                                    >::Return Ty;
279       return Ty(Val).template get<T>();
280     }
281 
282     /// dyn_cast<T>() - If the current value is of the specified pointer type,
283     /// return it, otherwise return null.
284     template<typename T>
285     T dyn_cast() const {
286       if (is<T>()) return get<T>();
287       return T();
288     }
289 
290     /// Assignment operators - Allow assigning into this union from either
291     /// pointer type, setting the discriminator to remember what it came from.
292     const PointerUnion3 &operator=(const PT1 &RHS) {
293       Val = InnerUnion(RHS);
294       return *this;
295     }
296     const PointerUnion3 &operator=(const PT2 &RHS) {
297       Val = InnerUnion(RHS);
298       return *this;
299     }
300     const PointerUnion3 &operator=(const PT3 &RHS) {
301       Val = RHS;
302       return *this;
303     }
304 
305     void *getOpaqueValue() const { return Val.getOpaqueValue(); }
306     static inline PointerUnion3 getFromOpaqueValue(void *VP) {
307       PointerUnion3 V;
308       V.Val = ValTy::getFromOpaqueValue(VP);
309       return V;
310     }
311   };
312 
313   // Teach SmallPtrSet that PointerUnion3 is "basically a pointer", that has
314   // # low bits available = min(PT1bits,PT2bits,PT2bits)-2.
315   template<typename PT1, typename PT2, typename PT3>
316   class PointerLikeTypeTraits<PointerUnion3<PT1, PT2, PT3> > {
317   public:
318     static inline void *
319     getAsVoidPointer(const PointerUnion3<PT1, PT2, PT3> &P) {
320       return P.getOpaqueValue();
321     }
322     static inline PointerUnion3<PT1, PT2, PT3>
323     getFromVoidPointer(void *P) {
324       return PointerUnion3<PT1, PT2, PT3>::getFromOpaqueValue(P);
325     }
326 
327     // The number of bits available are the min of the two pointer types.
328     enum {
329       NumLowBitsAvailable =
330         PointerLikeTypeTraits<typename PointerUnion3<PT1, PT2, PT3>::ValTy>
331           ::NumLowBitsAvailable
332     };
333   };
334 
335   /// PointerUnion4 - This is a pointer union of four pointer types.  See
336   /// documentation for PointerUnion for usage.
337   template <typename PT1, typename PT2, typename PT3, typename PT4>
338   class PointerUnion4 {
339   public:
340     typedef PointerUnion<PT1, PT2> InnerUnion1;
341     typedef PointerUnion<PT3, PT4> InnerUnion2;
342     typedef PointerUnion<InnerUnion1, InnerUnion2> ValTy;
343   private:
344     ValTy Val;
345   public:
346     PointerUnion4() {}
347 
348     PointerUnion4(PT1 V) {
349       Val = InnerUnion1(V);
350     }
351     PointerUnion4(PT2 V) {
352       Val = InnerUnion1(V);
353     }
354     PointerUnion4(PT3 V) {
355       Val = InnerUnion2(V);
356     }
357     PointerUnion4(PT4 V) {
358       Val = InnerUnion2(V);
359     }
360 
361     /// isNull - Return true if the pointer held in the union is null,
362     /// regardless of which type it is.
363     bool isNull() const { return Val.isNull(); }
364     operator bool() const { return !isNull(); }
365 
366     /// is<T>() return true if the Union currently holds the type matching T.
367     template<typename T>
368     int is() const {
369       // If T is PT1/PT2 choose InnerUnion1 otherwise choose InnerUnion2.
370       typedef typename
371         ::llvm::PointerUnionTypeSelector<PT1, T, InnerUnion1,
372           ::llvm::PointerUnionTypeSelector<PT2, T, InnerUnion1, InnerUnion2 >
373                                                                    >::Return Ty;
374       return Val.template is<Ty>() &&
375              Val.template get<Ty>().template is<T>();
376     }
377 
378     /// get<T>() - Return the value of the specified pointer type. If the
379     /// specified pointer type is incorrect, assert.
380     template<typename T>
381     T get() const {
382       assert(is<T>() && "Invalid accessor called");
383       // If T is PT1/PT2 choose InnerUnion1 otherwise choose InnerUnion2.
384       typedef typename
385         ::llvm::PointerUnionTypeSelector<PT1, T, InnerUnion1,
386           ::llvm::PointerUnionTypeSelector<PT2, T, InnerUnion1, InnerUnion2 >
387                                                                    >::Return Ty;
388       return Val.template get<Ty>().template get<T>();
389     }
390 
391     /// dyn_cast<T>() - If the current value is of the specified pointer type,
392     /// return it, otherwise return null.
393     template<typename T>
394     T dyn_cast() const {
395       if (is<T>()) return get<T>();
396       return T();
397     }
398 
399     /// Assignment operators - Allow assigning into this union from either
400     /// pointer type, setting the discriminator to remember what it came from.
401     const PointerUnion4 &operator=(const PT1 &RHS) {
402       Val = InnerUnion1(RHS);
403       return *this;
404     }
405     const PointerUnion4 &operator=(const PT2 &RHS) {
406       Val = InnerUnion1(RHS);
407       return *this;
408     }
409     const PointerUnion4 &operator=(const PT3 &RHS) {
410       Val = InnerUnion2(RHS);
411       return *this;
412     }
413     const PointerUnion4 &operator=(const PT4 &RHS) {
414       Val = InnerUnion2(RHS);
415       return *this;
416     }
417 
418     void *getOpaqueValue() const { return Val.getOpaqueValue(); }
419     static inline PointerUnion4 getFromOpaqueValue(void *VP) {
420       PointerUnion4 V;
421       V.Val = ValTy::getFromOpaqueValue(VP);
422       return V;
423     }
424   };
425 
426   // Teach SmallPtrSet that PointerUnion4 is "basically a pointer", that has
427   // # low bits available = min(PT1bits,PT2bits,PT2bits)-2.
428   template<typename PT1, typename PT2, typename PT3, typename PT4>
429   class PointerLikeTypeTraits<PointerUnion4<PT1, PT2, PT3, PT4> > {
430   public:
431     static inline void *
432     getAsVoidPointer(const PointerUnion4<PT1, PT2, PT3, PT4> &P) {
433       return P.getOpaqueValue();
434     }
435     static inline PointerUnion4<PT1, PT2, PT3, PT4>
436     getFromVoidPointer(void *P) {
437       return PointerUnion4<PT1, PT2, PT3, PT4>::getFromOpaqueValue(P);
438     }
439 
440     // The number of bits available are the min of the two pointer types.
441     enum {
442       NumLowBitsAvailable =
443         PointerLikeTypeTraits<typename PointerUnion4<PT1, PT2, PT3, PT4>::ValTy>
444           ::NumLowBitsAvailable
445     };
446   };
447 }
448 
449 #endif
450