PointerUnion.h revision f54229192c22559389b0ef47e731fd628db963c5
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  /// getPointerUnionTypeNum - If the argument has type PT1* or PT2* return
23  /// false or true respectively.
24  template <typename PT1, typename PT2>
25  static inline int getPointerUnionTypeNum(PT1 *P) { return 0; }
26  template <typename PT1, typename PT2>
27  static inline int getPointerUnionTypeNum(PT2 *P) { return 1; }
28  template <typename PT1, typename PT2>
29  static inline int getPointerUnionTypeNum(...) { return -1; }
30
31
32  /// Provide PointerLikeTypeTraits for void* that is used by PointerUnion
33  /// for the two template arguments.
34  template <typename PT1, typename PT2>
35  class PointerUnionUIntTraits {
36  public:
37    static inline void *getAsVoidPointer(void *P) { return P; }
38    static inline void *getFromVoidPointer(void *P) { return P; }
39    enum {
40      PT1BitsAv = PointerLikeTypeTraits<PT1>::NumLowBitsAvailable,
41      PT2BitsAv = PointerLikeTypeTraits<PT2>::NumLowBitsAvailable,
42      NumLowBitsAvailable = PT1BitsAv < PT2BitsAv ? PT1BitsAv : PT2BitsAv
43    };
44  };
45
46  /// PointerUnion - This implements a discriminated union of two pointer types,
47  /// and keeps the discriminator bit-mangled into the low bits of the pointer.
48  /// This allows the implementation to be extremely efficient in space, but
49  /// permits a very natural and type-safe API.
50  ///
51  /// Common use patterns would be something like this:
52  ///    PointerUnion<int*, float*> P;
53  ///    P = (int*)0;
54  ///    printf("%d %d", P.is<int*>(), P.is<float*>());  // prints "1 0"
55  ///    X = P.get<int*>();     // ok.
56  ///    Y = P.get<float*>();   // runtime assertion failure.
57  ///    Z = P.get<double*>();  // runtime assertion failure (regardless of tag)
58  ///    P = (float*)0;
59  ///    Y = P.get<float*>();   // ok.
60  ///    X = P.get<int*>();     // runtime assertion failure.
61  template <typename PT1, typename PT2>
62  class PointerUnion {
63  public:
64    typedef PointerIntPair<void*, 1, bool,
65                           PointerUnionUIntTraits<PT1,PT2> > ValTy;
66  private:
67    ValTy Val;
68  public:
69    PointerUnion() {}
70
71    PointerUnion(PT1 V) {
72      Val.setPointer(PointerLikeTypeTraits<PT1>::getAsVoidPointer(V));
73      Val.setInt(0);
74    }
75    PointerUnion(PT2 V) {
76      Val.setPointer(PointerLikeTypeTraits<PT2>::getAsVoidPointer(V));
77      Val.setInt(1);
78    }
79
80    /// isNull - Return true if the pointer help in the union is null,
81    /// regardless of which type it is.
82    bool isNull() const { return Val.getPointer() == 0; }
83    operator bool() const { return !isNull(); }
84
85    /// is<T>() return true if the Union currently holds the type matching T.
86    template<typename T>
87    int is() const {
88      int TyNo = ::llvm::getPointerUnionTypeNum<PT1, PT2>((T*)0);
89      assert(TyNo != -1 && "Type query could never succeed on PointerUnion!");
90      return Val.getInt() == TyNo;
91    }
92
93    /// get<T>() - Return the value of the specified pointer type. If the
94    /// specified pointer type is incorrect, assert.
95    template<typename T>
96    T get() const {
97      assert(is<T>() && "Invalid accessor called");
98      return PointerLikeTypeTraits<T>::getFromVoidPointer(Val.getPointer());
99    }
100
101    /// dyn_cast<T>() - If the current value is of the specified pointer type,
102    /// return it, otherwise return null.
103    template<typename T>
104    T dyn_cast() const {
105      if (is<T>()) return get<T>();
106      return T();
107    }
108
109    /// Assignment operators - Allow assigning into this union from either
110    /// pointer type, setting the discriminator to remember what it came from.
111    const PointerUnion &operator=(const PT1 &RHS) {
112      Val.setPointer(PointerLikeTypeTraits<PT1>::getAsVoidPointer(RHS));
113      Val.setInt(0);
114      return *this;
115    }
116    const PointerUnion &operator=(const PT2 &RHS) {
117      Val.setPointer(PointerLikeTypeTraits<PT2>::getAsVoidPointer(RHS));
118      Val.setInt(1);
119      return *this;
120    }
121
122    void *getOpaqueValue() const { return Val.getOpaqueValue(); }
123    static PointerUnion getFromOpaqueValue(void *VP) {
124      PointerUnion V;
125      V.Val = ValTy::getFromOpaqueValue(VP);
126      return V;
127    }
128  };
129
130  // Teach SmallPtrSet that PointerUnion is "basically a pointer", that has
131  // # low bits available = min(PT1bits,PT2bits)-1.
132  template<typename PT1, typename PT2>
133  class PointerLikeTypeTraits<PointerUnion<PT1, PT2> > {
134  public:
135    static inline void *
136    getAsVoidPointer(const PointerUnion<PT1, PT2> &P) {
137      return P.getOpaqueValue();
138    }
139    static inline PointerUnion<PT1, PT2>
140    getFromVoidPointer(void *P) {
141      return PointerUnion<PT1, PT2>::getFromOpaqueValue(P);
142    }
143
144    // The number of bits available are the min of the two pointer types.
145    enum {
146      NumLowBitsAvailable =
147        PointerLikeTypeTraits<typename PointerUnion<PT1,PT2>::ValTy>
148          ::NumLowBitsAvailable
149    };
150  };
151
152
153  /// PointerUnion3 - This is a pointer union of three pointer types.  See
154  /// documentation for PointerUnion for usage.
155  template <typename PT1, typename PT2, typename PT3>
156  class PointerUnion3 {
157  public:
158    typedef PointerUnion<PT1, PT2> InnerUnion;
159    typedef PointerUnion<InnerUnion, PT3> ValTy;
160  private:
161    ValTy Val;
162  public:
163    PointerUnion3() {}
164
165    PointerUnion3(PT1 V) {
166      Val = InnerUnion(V);
167    }
168    PointerUnion3(PT2 V) {
169      Val = InnerUnion(V);
170    }
171    PointerUnion3(PT3 V) {
172      Val = V;
173    }
174
175    /// isNull - Return true if the pointer help in the union is null,
176    /// regardless of which type it is.
177    bool isNull() const { return Val.isNull(); }
178    operator bool() const { return !isNull(); }
179
180    /// is<T>() return true if the Union currently holds the type matching T.
181    template<typename T>
182    int is() const {
183      // Is it PT1/PT2?
184      if (::llvm::getPointerUnionTypeNum<PT1, PT2>((T*)0) != -1)
185        return Val.get<InnerUnion>().is<T>();
186      // Must be PT3 or statically invalid.
187      assert(Val.is<T>());
188      return true;
189    }
190
191    /// get<T>() - Return the value of the specified pointer type. If the
192    /// specified pointer type is incorrect, assert.
193    template<typename T>
194    T get() const {
195      assert(is<T>() && "Invalid accessor called");
196      if (Val.is<T>())
197        return Val.get<T>();
198      return Val.get<InnerUnion>().get<T>();
199    }
200
201    /// dyn_cast<T>() - If the current value is of the specified pointer type,
202    /// return it, otherwise return null.
203    template<typename T>
204    T dyn_cast() const {
205      if (is<T>()) return get<T>();
206      return T();
207    }
208
209    /// Assignment operators - Allow assigning into this union from either
210    /// pointer type, setting the discriminator to remember what it came from.
211    const PointerUnion3 &operator=(const PT1 &RHS) {
212      Val = InnerUnion(RHS);
213      return *this;
214    }
215    const PointerUnion3 &operator=(const PT2 &RHS) {
216      Val = InnerUnion(RHS);
217      return *this;
218    }
219    const PointerUnion3 &operator=(const PT3 &RHS) {
220      Val = RHS;
221      return *this;
222    }
223
224    void *getOpaqueValue() const { return Val.getOpaqueValue(); }
225    static PointerUnion3 getFromOpaqueValue(void *VP) {
226      PointerUnion3 V;
227      V.Val = ValTy::getFromOpaqueValue(VP);
228      return V;
229    }
230  };
231
232  // Teach SmallPtrSet that PointerUnion3 is "basically a pointer", that has
233  // # low bits available = min(PT1bits,PT2bits,PT2bits)-2.
234  template<typename PT1, typename PT2, typename PT3>
235  class PointerLikeTypeTraits<PointerUnion3<PT1, PT2, PT3> > {
236  public:
237    static inline void *
238    getAsVoidPointer(const PointerUnion3<PT1, PT2, PT3> &P) {
239      return P.getOpaqueValue();
240    }
241    static inline PointerUnion3<PT1, PT2, PT3>
242    getFromVoidPointer(void *P) {
243      return PointerUnion3<PT1, PT2, PT3>::getFromOpaqueValue(P);
244    }
245
246    // The number of bits available are the min of the two pointer types.
247    enum {
248      NumLowBitsAvailable =
249        PointerLikeTypeTraits<typename PointerUnion3<PT1, PT2, PT3>::ValTy>
250          ::NumLowBitsAvailable
251    };
252  };
253}
254
255#endif
256