PointerUnion.h revision 823eb1ca11d684530048f1fe85a727aa1ef622d1
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
20namespace 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).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).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