1193323Sed//== llvm/ADT/IntrusiveRefCntPtr.h - Smart Refcounting Pointer ---*- 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 IntrusiveRefCntPtr, a template class that
11193323Sed// implements a "smart" pointer for objects that maintain their own
12193323Sed// internal reference count, and RefCountedBase/RefCountedBaseVPTR, two
13193323Sed// generic base classes for objects that wish to have their lifetimes
14193323Sed// managed using reference counting.
15193323Sed//
16193323Sed// IntrusiveRefCntPtr is similar to Boost's intrusive_ptr with added
17193323Sed// LLVM-style casting.
18193323Sed//
19193323Sed//===----------------------------------------------------------------------===//
20193323Sed
21249423Sdim#ifndef LLVM_ADT_INTRUSIVEREFCNTPTR_H
22249423Sdim#define LLVM_ADT_INTRUSIVEREFCNTPTR_H
23193323Sed
24193323Sed#include "llvm/Support/Casting.h"
25239462Sdim#include "llvm/Support/Compiler.h"
26239462Sdim#include <memory>
27193323Sed
28193323Sednamespace llvm {
29193323Sed
30193323Sed  template <class T>
31193323Sed  class IntrusiveRefCntPtr;
32193323Sed
33193323Sed//===----------------------------------------------------------------------===//
34193323Sed/// RefCountedBase - A generic base class for objects that wish to
35193323Sed///  have their lifetimes managed using reference counts. Classes
36193323Sed///  subclass RefCountedBase to obtain such functionality, and are
37239462Sdim///  typically handled with IntrusiveRefCntPtr "smart pointers" (see below)
38193323Sed///  which automatically handle the management of reference counts.
39193323Sed///  Objects that subclass RefCountedBase should not be allocated on
40193323Sed///  the stack, as invoking "delete" (which is called when the
41193323Sed///  reference count hits 0) on such objects is an error.
42193323Sed//===----------------------------------------------------------------------===//
43193323Sed  template <class Derived>
44193323Sed  class RefCountedBase {
45221345Sdim    mutable unsigned ref_cnt;
46193323Sed
47221345Sdim  public:
48193323Sed    RefCountedBase() : ref_cnt(0) {}
49234353Sdim    RefCountedBase(const RefCountedBase &) : ref_cnt(0) {}
50193323Sed
51221345Sdim    void Retain() const { ++ref_cnt; }
52221345Sdim    void Release() const {
53193323Sed      assert (ref_cnt > 0 && "Reference count is already zero.");
54221345Sdim      if (--ref_cnt == 0) delete static_cast<const Derived*>(this);
55193323Sed    }
56193323Sed  };
57193323Sed
58193323Sed//===----------------------------------------------------------------------===//
59193323Sed/// RefCountedBaseVPTR - A class that has the same function as
60193323Sed///  RefCountedBase, but with a virtual destructor. Should be used
61193323Sed///  instead of RefCountedBase for classes that already have virtual
62193323Sed///  methods to enforce dynamic allocation via 'new'. Classes that
63193323Sed///  inherit from RefCountedBaseVPTR can't be allocated on stack -
64193323Sed///  attempting to do this will produce a compile error.
65193323Sed//===----------------------------------------------------------------------===//
66193323Sed  class RefCountedBaseVPTR {
67221345Sdim    mutable unsigned ref_cnt;
68234353Sdim    virtual void anchor();
69193323Sed
70193323Sed  protected:
71193323Sed    RefCountedBaseVPTR() : ref_cnt(0) {}
72234353Sdim    RefCountedBaseVPTR(const RefCountedBaseVPTR &) : ref_cnt(0) {}
73234353Sdim
74193323Sed    virtual ~RefCountedBaseVPTR() {}
75193323Sed
76221345Sdim    void Retain() const { ++ref_cnt; }
77221345Sdim    void Release() const {
78193323Sed      assert (ref_cnt > 0 && "Reference count is already zero.");
79193323Sed      if (--ref_cnt == 0) delete this;
80193323Sed    }
81193323Sed
82221345Sdim    template <typename T>
83234353Sdim    friend struct IntrusiveRefCntPtrInfo;
84193323Sed  };
85193323Sed
86234353Sdim
87234353Sdim  template <typename T> struct IntrusiveRefCntPtrInfo {
88234353Sdim    static void retain(T *obj) { obj->Retain(); }
89234353Sdim    static void release(T *obj) { obj->Release(); }
90234353Sdim  };
91234353Sdim
92193323Sed//===----------------------------------------------------------------------===//
93193323Sed/// IntrusiveRefCntPtr - A template class that implements a "smart pointer"
94193323Sed///  that assumes the wrapped object has a reference count associated
95193323Sed///  with it that can be managed via calls to
96193323Sed///  IntrusivePtrAddRef/IntrusivePtrRelease.  The smart pointers
97193323Sed///  manage reference counts via the RAII idiom: upon creation of
98193323Sed///  smart pointer the reference count of the wrapped object is
99193323Sed///  incremented and upon destruction of the smart pointer the
100193323Sed///  reference count is decremented.  This class also safely handles
101193323Sed///  wrapping NULL pointers.
102193323Sed///
103193323Sed/// Reference counting is implemented via calls to
104193323Sed///  Obj->Retain()/Obj->Release(). Release() is required to destroy
105193323Sed///  the object when the reference count reaches zero. Inheriting from
106193323Sed///  RefCountedBase/RefCountedBaseVPTR takes care of this
107193323Sed///  automatically.
108193323Sed//===----------------------------------------------------------------------===//
109193323Sed  template <typename T>
110193323Sed  class IntrusiveRefCntPtr {
111193323Sed    T* Obj;
112193323Sed    typedef IntrusiveRefCntPtr this_type;
113193323Sed  public:
114193323Sed    typedef T element_type;
115193323Sed
116193323Sed    explicit IntrusiveRefCntPtr() : Obj(0) {}
117193323Sed
118234353Sdim    IntrusiveRefCntPtr(T* obj) : Obj(obj) {
119193323Sed      retain();
120193323Sed    }
121193323Sed
122193323Sed    IntrusiveRefCntPtr(const IntrusiveRefCntPtr& S) : Obj(S.Obj) {
123193323Sed      retain();
124193323Sed    }
125193323Sed
126249423Sdim#if LLVM_HAS_RVALUE_REFERENCES
127239462Sdim    IntrusiveRefCntPtr(IntrusiveRefCntPtr&& S) : Obj(S.Obj) {
128239462Sdim      S.Obj = 0;
129193323Sed    }
130193323Sed
131239462Sdim    template <class X>
132239462Sdim    IntrusiveRefCntPtr(IntrusiveRefCntPtr<X>&& S) : Obj(S.getPtr()) {
133239462Sdim      S.Obj = 0;
134193323Sed    }
135239462Sdim#endif
136193323Sed
137193323Sed    template <class X>
138239462Sdim    IntrusiveRefCntPtr(const IntrusiveRefCntPtr<X>& S)
139239462Sdim      : Obj(S.getPtr()) {
140239462Sdim      retain();
141193323Sed    }
142193323Sed
143239462Sdim    IntrusiveRefCntPtr& operator=(IntrusiveRefCntPtr S) {
144239462Sdim      swap(S);
145193323Sed      return *this;
146193323Sed    }
147193323Sed
148193323Sed    ~IntrusiveRefCntPtr() { release(); }
149193323Sed
150193323Sed    T& operator*() const { return *Obj; }
151193323Sed
152193323Sed    T* operator->() const { return Obj; }
153193323Sed
154193323Sed    T* getPtr() const { return Obj; }
155193323Sed
156193323Sed    typedef T* (IntrusiveRefCntPtr::*unspecified_bool_type) () const;
157193323Sed    operator unspecified_bool_type() const {
158193323Sed      return Obj == 0 ? 0 : &IntrusiveRefCntPtr::getPtr;
159193323Sed    }
160193323Sed
161193323Sed    void swap(IntrusiveRefCntPtr& other) {
162193323Sed      T* tmp = other.Obj;
163193323Sed      other.Obj = Obj;
164193323Sed      Obj = tmp;
165193323Sed    }
166234353Sdim
167234353Sdim    void reset() {
168234353Sdim      release();
169234353Sdim      Obj = 0;
170234353Sdim    }
171234353Sdim
172221345Sdim    void resetWithoutRelease() {
173221345Sdim      Obj = 0;
174221345Sdim    }
175193323Sed
176193323Sed  private:
177234353Sdim    void retain() { if (Obj) IntrusiveRefCntPtrInfo<T>::retain(Obj); }
178234353Sdim    void release() { if (Obj) IntrusiveRefCntPtrInfo<T>::release(Obj); }
179193323Sed  };
180193323Sed
181193323Sed  template<class T, class U>
182193323Sed  inline bool operator==(const IntrusiveRefCntPtr<T>& A,
183193323Sed                         const IntrusiveRefCntPtr<U>& B)
184193323Sed  {
185193323Sed    return A.getPtr() == B.getPtr();
186193323Sed  }
187193323Sed
188193323Sed  template<class T, class U>
189193323Sed  inline bool operator!=(const IntrusiveRefCntPtr<T>& A,
190193323Sed                         const IntrusiveRefCntPtr<U>& B)
191193323Sed  {
192193323Sed    return A.getPtr() != B.getPtr();
193193323Sed  }
194193323Sed
195193323Sed  template<class T, class U>
196193323Sed  inline bool operator==(const IntrusiveRefCntPtr<T>& A,
197193323Sed                         U* B)
198193323Sed  {
199193323Sed    return A.getPtr() == B;
200193323Sed  }
201193323Sed
202193323Sed  template<class T, class U>
203193323Sed  inline bool operator!=(const IntrusiveRefCntPtr<T>& A,
204193323Sed                         U* B)
205193323Sed  {
206193323Sed    return A.getPtr() != B;
207193323Sed  }
208193323Sed
209193323Sed  template<class T, class U>
210193323Sed  inline bool operator==(T* A,
211193323Sed                         const IntrusiveRefCntPtr<U>& B)
212193323Sed  {
213193323Sed    return A == B.getPtr();
214193323Sed  }
215193323Sed
216193323Sed  template<class T, class U>
217193323Sed  inline bool operator!=(T* A,
218193323Sed                         const IntrusiveRefCntPtr<U>& B)
219193323Sed  {
220193323Sed    return A != B.getPtr();
221193323Sed  }
222193323Sed
223193323Sed//===----------------------------------------------------------------------===//
224193323Sed// LLVM-style downcasting support for IntrusiveRefCntPtr objects
225193323Sed//===----------------------------------------------------------------------===//
226193323Sed
227193323Sed  template<class T> struct simplify_type<IntrusiveRefCntPtr<T> > {
228193323Sed    typedef T* SimpleType;
229249423Sdim    static SimpleType getSimplifiedValue(IntrusiveRefCntPtr<T>& Val) {
230193323Sed      return Val.getPtr();
231193323Sed    }
232193323Sed  };
233193323Sed
234193323Sed  template<class T> struct simplify_type<const IntrusiveRefCntPtr<T> > {
235249423Sdim    typedef /*const*/ T* SimpleType;
236193323Sed    static SimpleType getSimplifiedValue(const IntrusiveRefCntPtr<T>& Val) {
237193323Sed      return Val.getPtr();
238193323Sed    }
239193323Sed  };
240193323Sed
241193323Sed} // end namespace llvm
242193323Sed
243249423Sdim#endif // LLVM_ADT_INTRUSIVEREFCNTPTR_H
244