1193323Sed//===- llvm/ADT/PointerUnion.h - Discriminated Union of 2 Ptrs --*- C++ -*-===//
2193323Sed//
3193323Sed//                     The LLVM Compiler Infrastructure
4193323Sed//
5193323Sed// This file is distributed under the University of Illinois Open Source
6193323Sed// License. See LICENSE.TXT for details.
7193323Sed//
8193323Sed//===----------------------------------------------------------------------===//
9193323Sed//
10193323Sed// This file defines the PointerUnion class, which is a discriminated union of
11193323Sed// pointer types.
12193323Sed//
13193323Sed//===----------------------------------------------------------------------===//
14193323Sed
15193323Sed#ifndef LLVM_ADT_POINTERUNION_H
16193323Sed#define LLVM_ADT_POINTERUNION_H
17193323Sed
18263508Sdim#include "llvm/Support/Compiler.h"
19193323Sed#include "llvm/ADT/PointerIntPair.h"
20193323Sed
21193323Sednamespace llvm {
22193323Sed
23221345Sdim  template <typename T>
24221345Sdim  struct PointerUnionTypeSelectorReturn {
25221345Sdim    typedef T Return;
26221345Sdim  };
27221345Sdim
28221345Sdim  /// \brief Get a type based on whether two types are the same or not. For:
29221345Sdim  /// @code
30221345Sdim  /// typedef typename PointerUnionTypeSelector<T1, T2, EQ, NE>::Return Ret;
31221345Sdim  /// @endcode
32221345Sdim  /// Ret will be EQ type if T1 is same as T2 or NE type otherwise.
33221345Sdim  template <typename T1, typename T2, typename RET_EQ, typename RET_NE>
34221345Sdim  struct PointerUnionTypeSelector {
35221345Sdim    typedef typename PointerUnionTypeSelectorReturn<RET_NE>::Return Return;
36221345Sdim  };
37221345Sdim
38221345Sdim  template <typename T, typename RET_EQ, typename RET_NE>
39221345Sdim  struct PointerUnionTypeSelector<T, T, RET_EQ, RET_NE> {
40221345Sdim    typedef typename PointerUnionTypeSelectorReturn<RET_EQ>::Return Return;
41221345Sdim  };
42221345Sdim
43221345Sdim  template <typename T1, typename T2, typename RET_EQ, typename RET_NE>
44221345Sdim  struct PointerUnionTypeSelectorReturn<
45221345Sdim                            PointerUnionTypeSelector<T1, T2, RET_EQ, RET_NE> > {
46221345Sdim    typedef typename PointerUnionTypeSelector<T1, T2, RET_EQ, RET_NE>::Return
47221345Sdim        Return;
48221345Sdim  };
49221345Sdim
50193323Sed  /// Provide PointerLikeTypeTraits for void* that is used by PointerUnion
51193323Sed  /// for the two template arguments.
52193323Sed  template <typename PT1, typename PT2>
53193323Sed  class PointerUnionUIntTraits {
54193323Sed  public:
55193323Sed    static inline void *getAsVoidPointer(void *P) { return P; }
56193323Sed    static inline void *getFromVoidPointer(void *P) { return P; }
57193323Sed    enum {
58239462Sdim      PT1BitsAv = (int)(PointerLikeTypeTraits<PT1>::NumLowBitsAvailable),
59239462Sdim      PT2BitsAv = (int)(PointerLikeTypeTraits<PT2>::NumLowBitsAvailable),
60193323Sed      NumLowBitsAvailable = PT1BitsAv < PT2BitsAv ? PT1BitsAv : PT2BitsAv
61193323Sed    };
62193323Sed  };
63193323Sed
64193323Sed  /// PointerUnion - This implements a discriminated union of two pointer types,
65193323Sed  /// and keeps the discriminator bit-mangled into the low bits of the pointer.
66193323Sed  /// This allows the implementation to be extremely efficient in space, but
67193323Sed  /// permits a very natural and type-safe API.
68193323Sed  ///
69193323Sed  /// Common use patterns would be something like this:
70193323Sed  ///    PointerUnion<int*, float*> P;
71193323Sed  ///    P = (int*)0;
72193323Sed  ///    printf("%d %d", P.is<int*>(), P.is<float*>());  // prints "1 0"
73193323Sed  ///    X = P.get<int*>();     // ok.
74193323Sed  ///    Y = P.get<float*>();   // runtime assertion failure.
75263508Sdim  ///    Z = P.get<double*>();  // compile time failure.
76193323Sed  ///    P = (float*)0;
77193323Sed  ///    Y = P.get<float*>();   // ok.
78193323Sed  ///    X = P.get<int*>();     // runtime assertion failure.
79193323Sed  template <typename PT1, typename PT2>
80193323Sed  class PointerUnion {
81193323Sed  public:
82193323Sed    typedef PointerIntPair<void*, 1, bool,
83193323Sed                           PointerUnionUIntTraits<PT1,PT2> > ValTy;
84193323Sed  private:
85193323Sed    ValTy Val;
86221345Sdim
87221345Sdim    struct IsPT1 {
88221345Sdim      static const int Num = 0;
89221345Sdim    };
90221345Sdim    struct IsPT2 {
91221345Sdim      static const int Num = 1;
92221345Sdim    };
93221345Sdim    template <typename T>
94221345Sdim    struct UNION_DOESNT_CONTAIN_TYPE { };
95221345Sdim
96193323Sed  public:
97193323Sed    PointerUnion() {}
98193323Sed
99249423Sdim    PointerUnion(PT1 V) : Val(
100249423Sdim      const_cast<void *>(PointerLikeTypeTraits<PT1>::getAsVoidPointer(V))) {
101193323Sed    }
102249423Sdim    PointerUnion(PT2 V) : Val(
103249423Sdim      const_cast<void *>(PointerLikeTypeTraits<PT2>::getAsVoidPointer(V)), 1) {
104193323Sed    }
105193323Sed
106198090Srdivacky    /// isNull - Return true if the pointer held in the union is null,
107193323Sed    /// regardless of which type it is.
108226633Sdim    bool isNull() const {
109226633Sdim      // Convert from the void* to one of the pointer types, to make sure that
110226633Sdim      // we recursively strip off low bits if we have a nested PointerUnion.
111226633Sdim      return !PointerLikeTypeTraits<PT1>::getFromVoidPointer(Val.getPointer());
112226633Sdim    }
113263508Sdim    LLVM_EXPLICIT operator bool() const { return !isNull(); }
114193323Sed
115193323Sed    /// is<T>() return true if the Union currently holds the type matching T.
116193323Sed    template<typename T>
117193323Sed    int is() const {
118221345Sdim      typedef typename
119221345Sdim        ::llvm::PointerUnionTypeSelector<PT1, T, IsPT1,
120221345Sdim          ::llvm::PointerUnionTypeSelector<PT2, T, IsPT2,
121221345Sdim                                    UNION_DOESNT_CONTAIN_TYPE<T> > >::Return Ty;
122221345Sdim      int TyNo = Ty::Num;
123195340Sed      return static_cast<int>(Val.getInt()) == TyNo;
124193323Sed    }
125193323Sed
126193323Sed    /// get<T>() - Return the value of the specified pointer type. If the
127193323Sed    /// specified pointer type is incorrect, assert.
128193323Sed    template<typename T>
129193323Sed    T get() const {
130193323Sed      assert(is<T>() && "Invalid accessor called");
131193323Sed      return PointerLikeTypeTraits<T>::getFromVoidPointer(Val.getPointer());
132193323Sed    }
133193323Sed
134193323Sed    /// dyn_cast<T>() - If the current value is of the specified pointer type,
135193323Sed    /// return it, otherwise return null.
136193323Sed    template<typename T>
137193323Sed    T dyn_cast() const {
138193323Sed      if (is<T>()) return get<T>();
139193323Sed      return T();
140193323Sed    }
141218893Sdim
142234353Sdim    /// \brief If the union is set to the first pointer type get an address
143234353Sdim    /// pointing to it.
144234353Sdim    PT1 const *getAddrOfPtr1() const {
145234353Sdim      return const_cast<PointerUnion *>(this)->getAddrOfPtr1();
146234353Sdim    }
147234353Sdim
148234353Sdim    /// \brief If the union is set to the first pointer type get an address
149234353Sdim    /// pointing to it.
150234353Sdim    PT1 *getAddrOfPtr1() {
151218893Sdim      assert(is<PT1>() && "Val is not the first pointer");
152218893Sdim      assert(get<PT1>() == Val.getPointer() &&
153218893Sdim         "Can't get the address because PointerLikeTypeTraits changes the ptr");
154234353Sdim      return (PT1 *)Val.getAddrOfPointer();
155218893Sdim    }
156193323Sed
157193323Sed    /// Assignment operators - Allow assigning into this union from either
158193323Sed    /// pointer type, setting the discriminator to remember what it came from.
159193323Sed    const PointerUnion &operator=(const PT1 &RHS) {
160249423Sdim      Val.initWithPointer(
161193323Sed         const_cast<void *>(PointerLikeTypeTraits<PT1>::getAsVoidPointer(RHS)));
162193323Sed      return *this;
163193323Sed    }
164193323Sed    const PointerUnion &operator=(const PT2 &RHS) {
165249423Sdim      Val.setPointerAndInt(
166249423Sdim        const_cast<void *>(PointerLikeTypeTraits<PT2>::getAsVoidPointer(RHS)),
167249423Sdim        1);
168193323Sed      return *this;
169193323Sed    }
170193323Sed
171193323Sed    void *getOpaqueValue() const { return Val.getOpaqueValue(); }
172206083Srdivacky    static inline PointerUnion getFromOpaqueValue(void *VP) {
173193323Sed      PointerUnion V;
174193323Sed      V.Val = ValTy::getFromOpaqueValue(VP);
175193323Sed      return V;
176193323Sed    }
177193323Sed  };
178263508Sdim
179263508Sdim  template<typename PT1, typename PT2>
180263508Sdim  static bool operator==(PointerUnion<PT1, PT2> lhs,
181263508Sdim                         PointerUnion<PT1, PT2> rhs) {
182263508Sdim    return lhs.getOpaqueValue() == rhs.getOpaqueValue();
183263508Sdim  }
184263508Sdim
185263508Sdim  template<typename PT1, typename PT2>
186263508Sdim  static bool operator!=(PointerUnion<PT1, PT2> lhs,
187263508Sdim                         PointerUnion<PT1, PT2> rhs) {
188263508Sdim    return lhs.getOpaqueValue() != rhs.getOpaqueValue();
189263508Sdim  }
190263508Sdim
191193323Sed  // Teach SmallPtrSet that PointerUnion is "basically a pointer", that has
192193323Sed  // # low bits available = min(PT1bits,PT2bits)-1.
193193323Sed  template<typename PT1, typename PT2>
194193323Sed  class PointerLikeTypeTraits<PointerUnion<PT1, PT2> > {
195193323Sed  public:
196193323Sed    static inline void *
197193323Sed    getAsVoidPointer(const PointerUnion<PT1, PT2> &P) {
198193323Sed      return P.getOpaqueValue();
199193323Sed    }
200193323Sed    static inline PointerUnion<PT1, PT2>
201193323Sed    getFromVoidPointer(void *P) {
202193323Sed      return PointerUnion<PT1, PT2>::getFromOpaqueValue(P);
203193323Sed    }
204193323Sed
205193323Sed    // The number of bits available are the min of the two pointer types.
206193323Sed    enum {
207193323Sed      NumLowBitsAvailable =
208193323Sed        PointerLikeTypeTraits<typename PointerUnion<PT1,PT2>::ValTy>
209193323Sed          ::NumLowBitsAvailable
210193323Sed    };
211193323Sed  };
212193323Sed
213193323Sed
214193323Sed  /// PointerUnion3 - This is a pointer union of three pointer types.  See
215193323Sed  /// documentation for PointerUnion for usage.
216193323Sed  template <typename PT1, typename PT2, typename PT3>
217193323Sed  class PointerUnion3 {
218193323Sed  public:
219193323Sed    typedef PointerUnion<PT1, PT2> InnerUnion;
220193323Sed    typedef PointerUnion<InnerUnion, PT3> ValTy;
221193323Sed  private:
222193323Sed    ValTy Val;
223221345Sdim
224221345Sdim    struct IsInnerUnion {
225221345Sdim      ValTy Val;
226221345Sdim      IsInnerUnion(ValTy val) : Val(val) { }
227221345Sdim      template<typename T>
228221345Sdim      int is() const {
229221345Sdim        return Val.template is<InnerUnion>() &&
230221345Sdim               Val.template get<InnerUnion>().template is<T>();
231221345Sdim      }
232221345Sdim      template<typename T>
233221345Sdim      T get() const {
234221345Sdim        return Val.template get<InnerUnion>().template get<T>();
235221345Sdim      }
236221345Sdim    };
237221345Sdim
238221345Sdim    struct IsPT3 {
239221345Sdim      ValTy Val;
240221345Sdim      IsPT3(ValTy val) : Val(val) { }
241221345Sdim      template<typename T>
242221345Sdim      int is() const {
243221345Sdim        return Val.template is<T>();
244221345Sdim      }
245221345Sdim      template<typename T>
246221345Sdim      T get() const {
247221345Sdim        return Val.template get<T>();
248221345Sdim      }
249221345Sdim    };
250221345Sdim
251193323Sed  public:
252193323Sed    PointerUnion3() {}
253193323Sed
254193323Sed    PointerUnion3(PT1 V) {
255193323Sed      Val = InnerUnion(V);
256193323Sed    }
257193323Sed    PointerUnion3(PT2 V) {
258193323Sed      Val = InnerUnion(V);
259193323Sed    }
260193323Sed    PointerUnion3(PT3 V) {
261193323Sed      Val = V;
262193323Sed    }
263193323Sed
264198090Srdivacky    /// isNull - Return true if the pointer held in the union is null,
265193323Sed    /// regardless of which type it is.
266193323Sed    bool isNull() const { return Val.isNull(); }
267263508Sdim    LLVM_EXPLICIT operator bool() const { return !isNull(); }
268193323Sed
269193323Sed    /// is<T>() return true if the Union currently holds the type matching T.
270193323Sed    template<typename T>
271193323Sed    int is() const {
272221345Sdim      // If T is PT1/PT2 choose IsInnerUnion otherwise choose IsPT3.
273221345Sdim      typedef typename
274221345Sdim        ::llvm::PointerUnionTypeSelector<PT1, T, IsInnerUnion,
275221345Sdim          ::llvm::PointerUnionTypeSelector<PT2, T, IsInnerUnion, IsPT3 >
276221345Sdim                                                                   >::Return Ty;
277234353Sdim      return Ty(Val).template is<T>();
278193323Sed    }
279193323Sed
280193323Sed    /// get<T>() - Return the value of the specified pointer type. If the
281193323Sed    /// specified pointer type is incorrect, assert.
282193323Sed    template<typename T>
283193323Sed    T get() const {
284193323Sed      assert(is<T>() && "Invalid accessor called");
285221345Sdim      // If T is PT1/PT2 choose IsInnerUnion otherwise choose IsPT3.
286221345Sdim      typedef typename
287221345Sdim        ::llvm::PointerUnionTypeSelector<PT1, T, IsInnerUnion,
288221345Sdim          ::llvm::PointerUnionTypeSelector<PT2, T, IsInnerUnion, IsPT3 >
289221345Sdim                                                                   >::Return Ty;
290234353Sdim      return Ty(Val).template get<T>();
291193323Sed    }
292193323Sed
293193323Sed    /// dyn_cast<T>() - If the current value is of the specified pointer type,
294193323Sed    /// return it, otherwise return null.
295193323Sed    template<typename T>
296193323Sed    T dyn_cast() const {
297193323Sed      if (is<T>()) return get<T>();
298193323Sed      return T();
299193323Sed    }
300193323Sed
301193323Sed    /// Assignment operators - Allow assigning into this union from either
302193323Sed    /// pointer type, setting the discriminator to remember what it came from.
303193323Sed    const PointerUnion3 &operator=(const PT1 &RHS) {
304193323Sed      Val = InnerUnion(RHS);
305193323Sed      return *this;
306193323Sed    }
307193323Sed    const PointerUnion3 &operator=(const PT2 &RHS) {
308193323Sed      Val = InnerUnion(RHS);
309193323Sed      return *this;
310193323Sed    }
311193323Sed    const PointerUnion3 &operator=(const PT3 &RHS) {
312193323Sed      Val = RHS;
313193323Sed      return *this;
314193323Sed    }
315193323Sed
316193323Sed    void *getOpaqueValue() const { return Val.getOpaqueValue(); }
317206083Srdivacky    static inline PointerUnion3 getFromOpaqueValue(void *VP) {
318193323Sed      PointerUnion3 V;
319193323Sed      V.Val = ValTy::getFromOpaqueValue(VP);
320193323Sed      return V;
321193323Sed    }
322193323Sed  };
323193323Sed
324193323Sed  // Teach SmallPtrSet that PointerUnion3 is "basically a pointer", that has
325193323Sed  // # low bits available = min(PT1bits,PT2bits,PT2bits)-2.
326193323Sed  template<typename PT1, typename PT2, typename PT3>
327193323Sed  class PointerLikeTypeTraits<PointerUnion3<PT1, PT2, PT3> > {
328193323Sed  public:
329193323Sed    static inline void *
330193323Sed    getAsVoidPointer(const PointerUnion3<PT1, PT2, PT3> &P) {
331193323Sed      return P.getOpaqueValue();
332193323Sed    }
333193323Sed    static inline PointerUnion3<PT1, PT2, PT3>
334193323Sed    getFromVoidPointer(void *P) {
335193323Sed      return PointerUnion3<PT1, PT2, PT3>::getFromOpaqueValue(P);
336193323Sed    }
337193323Sed
338193323Sed    // The number of bits available are the min of the two pointer types.
339193323Sed    enum {
340193323Sed      NumLowBitsAvailable =
341193323Sed        PointerLikeTypeTraits<typename PointerUnion3<PT1, PT2, PT3>::ValTy>
342193323Sed          ::NumLowBitsAvailable
343193323Sed    };
344193323Sed  };
345198090Srdivacky
346198090Srdivacky  /// PointerUnion4 - This is a pointer union of four pointer types.  See
347198090Srdivacky  /// documentation for PointerUnion for usage.
348198090Srdivacky  template <typename PT1, typename PT2, typename PT3, typename PT4>
349198090Srdivacky  class PointerUnion4 {
350198090Srdivacky  public:
351198090Srdivacky    typedef PointerUnion<PT1, PT2> InnerUnion1;
352198090Srdivacky    typedef PointerUnion<PT3, PT4> InnerUnion2;
353198090Srdivacky    typedef PointerUnion<InnerUnion1, InnerUnion2> ValTy;
354198090Srdivacky  private:
355198090Srdivacky    ValTy Val;
356198090Srdivacky  public:
357198090Srdivacky    PointerUnion4() {}
358198090Srdivacky
359198090Srdivacky    PointerUnion4(PT1 V) {
360198090Srdivacky      Val = InnerUnion1(V);
361198090Srdivacky    }
362198090Srdivacky    PointerUnion4(PT2 V) {
363198090Srdivacky      Val = InnerUnion1(V);
364198090Srdivacky    }
365198090Srdivacky    PointerUnion4(PT3 V) {
366198090Srdivacky      Val = InnerUnion2(V);
367198090Srdivacky    }
368198090Srdivacky    PointerUnion4(PT4 V) {
369198090Srdivacky      Val = InnerUnion2(V);
370198090Srdivacky    }
371198090Srdivacky
372198090Srdivacky    /// isNull - Return true if the pointer held in the union is null,
373198090Srdivacky    /// regardless of which type it is.
374198090Srdivacky    bool isNull() const { return Val.isNull(); }
375263508Sdim    LLVM_EXPLICIT operator bool() const { return !isNull(); }
376198090Srdivacky
377198090Srdivacky    /// is<T>() return true if the Union currently holds the type matching T.
378198090Srdivacky    template<typename T>
379198090Srdivacky    int is() const {
380221345Sdim      // If T is PT1/PT2 choose InnerUnion1 otherwise choose InnerUnion2.
381221345Sdim      typedef typename
382221345Sdim        ::llvm::PointerUnionTypeSelector<PT1, T, InnerUnion1,
383221345Sdim          ::llvm::PointerUnionTypeSelector<PT2, T, InnerUnion1, InnerUnion2 >
384221345Sdim                                                                   >::Return Ty;
385221345Sdim      return Val.template is<Ty>() &&
386221345Sdim             Val.template get<Ty>().template is<T>();
387198090Srdivacky    }
388198090Srdivacky
389198090Srdivacky    /// get<T>() - Return the value of the specified pointer type. If the
390198090Srdivacky    /// specified pointer type is incorrect, assert.
391198090Srdivacky    template<typename T>
392198090Srdivacky    T get() const {
393198090Srdivacky      assert(is<T>() && "Invalid accessor called");
394221345Sdim      // If T is PT1/PT2 choose InnerUnion1 otherwise choose InnerUnion2.
395221345Sdim      typedef typename
396221345Sdim        ::llvm::PointerUnionTypeSelector<PT1, T, InnerUnion1,
397221345Sdim          ::llvm::PointerUnionTypeSelector<PT2, T, InnerUnion1, InnerUnion2 >
398221345Sdim                                                                   >::Return Ty;
399221345Sdim      return Val.template get<Ty>().template get<T>();
400198090Srdivacky    }
401198090Srdivacky
402198090Srdivacky    /// dyn_cast<T>() - If the current value is of the specified pointer type,
403198090Srdivacky    /// return it, otherwise return null.
404198090Srdivacky    template<typename T>
405198090Srdivacky    T dyn_cast() const {
406198090Srdivacky      if (is<T>()) return get<T>();
407198090Srdivacky      return T();
408198090Srdivacky    }
409198090Srdivacky
410198090Srdivacky    /// Assignment operators - Allow assigning into this union from either
411198090Srdivacky    /// pointer type, setting the discriminator to remember what it came from.
412198090Srdivacky    const PointerUnion4 &operator=(const PT1 &RHS) {
413198090Srdivacky      Val = InnerUnion1(RHS);
414198090Srdivacky      return *this;
415198090Srdivacky    }
416198090Srdivacky    const PointerUnion4 &operator=(const PT2 &RHS) {
417198090Srdivacky      Val = InnerUnion1(RHS);
418198090Srdivacky      return *this;
419198090Srdivacky    }
420198090Srdivacky    const PointerUnion4 &operator=(const PT3 &RHS) {
421198090Srdivacky      Val = InnerUnion2(RHS);
422198090Srdivacky      return *this;
423198090Srdivacky    }
424198090Srdivacky    const PointerUnion4 &operator=(const PT4 &RHS) {
425198090Srdivacky      Val = InnerUnion2(RHS);
426198090Srdivacky      return *this;
427198090Srdivacky    }
428198090Srdivacky
429198090Srdivacky    void *getOpaqueValue() const { return Val.getOpaqueValue(); }
430206083Srdivacky    static inline PointerUnion4 getFromOpaqueValue(void *VP) {
431198090Srdivacky      PointerUnion4 V;
432198090Srdivacky      V.Val = ValTy::getFromOpaqueValue(VP);
433198090Srdivacky      return V;
434198090Srdivacky    }
435198090Srdivacky  };
436198090Srdivacky
437198090Srdivacky  // Teach SmallPtrSet that PointerUnion4 is "basically a pointer", that has
438198090Srdivacky  // # low bits available = min(PT1bits,PT2bits,PT2bits)-2.
439198090Srdivacky  template<typename PT1, typename PT2, typename PT3, typename PT4>
440198090Srdivacky  class PointerLikeTypeTraits<PointerUnion4<PT1, PT2, PT3, PT4> > {
441198090Srdivacky  public:
442198090Srdivacky    static inline void *
443198090Srdivacky    getAsVoidPointer(const PointerUnion4<PT1, PT2, PT3, PT4> &P) {
444198090Srdivacky      return P.getOpaqueValue();
445198090Srdivacky    }
446198090Srdivacky    static inline PointerUnion4<PT1, PT2, PT3, PT4>
447198090Srdivacky    getFromVoidPointer(void *P) {
448198090Srdivacky      return PointerUnion4<PT1, PT2, PT3, PT4>::getFromOpaqueValue(P);
449198090Srdivacky    }
450198090Srdivacky
451198090Srdivacky    // The number of bits available are the min of the two pointer types.
452198090Srdivacky    enum {
453198090Srdivacky      NumLowBitsAvailable =
454198090Srdivacky        PointerLikeTypeTraits<typename PointerUnion4<PT1, PT2, PT3, PT4>::ValTy>
455198090Srdivacky          ::NumLowBitsAvailable
456198090Srdivacky    };
457198090Srdivacky  };
458193323Sed}
459193323Sed
460193323Sed#endif
461