diff options
Diffstat (limited to 'contrib/llvm/include/llvm/ADT/IntrusiveRefCntPtr.h')
-rw-r--r-- | contrib/llvm/include/llvm/ADT/IntrusiveRefCntPtr.h | 426 |
1 files changed, 202 insertions, 224 deletions
diff --git a/contrib/llvm/include/llvm/ADT/IntrusiveRefCntPtr.h b/contrib/llvm/include/llvm/ADT/IntrusiveRefCntPtr.h index 8057ec1..a77cf04 100644 --- a/contrib/llvm/include/llvm/ADT/IntrusiveRefCntPtr.h +++ b/contrib/llvm/include/llvm/ADT/IntrusiveRefCntPtr.h @@ -7,14 +7,49 @@ // //===----------------------------------------------------------------------===// // -// This file defines IntrusiveRefCntPtr, a template class that -// implements a "smart" pointer for objects that maintain their own -// internal reference count, and RefCountedBase/RefCountedBaseVPTR, two -// generic base classes for objects that wish to have their lifetimes -// managed using reference counting. +// This file defines the RefCountedBase, ThreadSafeRefCountedBase, and +// IntrusiveRefCntPtr classes. // -// IntrusiveRefCntPtr is similar to Boost's intrusive_ptr with added -// LLVM-style casting. +// IntrusiveRefCntPtr is a smart pointer to an object which maintains a +// reference count. (ThreadSafe)RefCountedBase is a mixin class that adds a +// refcount member variable and methods for updating the refcount. An object +// that inherits from (ThreadSafe)RefCountedBase deletes itself when its +// refcount hits zero. +// +// For example: +// +// class MyClass : public RefCountedBase<MyClass> {}; +// +// void foo() { +// // Constructing an IntrusiveRefCntPtr increases the pointee's refcount by +// // 1 (from 0 in this case). +// IntrusiveRefCntPtr<MyClass> Ptr1(new MyClass()); +// +// // Copying an IntrusiveRefCntPtr increases the pointee's refcount by 1. +// IntrusiveRefCntPtr<MyClass> Ptr2(Ptr1); +// +// // Constructing an IntrusiveRefCntPtr has no effect on the object's +// // refcount. After a move, the moved-from pointer is null. +// IntrusiveRefCntPtr<MyClass> Ptr3(std::move(Ptr1)); +// assert(Ptr1 == nullptr); +// +// // Clearing an IntrusiveRefCntPtr decreases the pointee's refcount by 1. +// Ptr2.reset(); +// +// // The object deletes itself when we return from the function, because +// // Ptr3's destructor decrements its refcount to 0. +// } +// +// You can use IntrusiveRefCntPtr with isa<T>(), dyn_cast<T>(), etc.: +// +// IntrusiveRefCntPtr<MyClass> Ptr(new MyClass()); +// OtherClass *Other = dyn_cast<OtherClass>(Ptr); // Ptr.get() not required +// +// IntrusiveRefCntPtr works with any class that +// +// - inherits from (ThreadSafe)RefCountedBase, +// - has Retain() and Release() methods, or +// - specializes IntrusiveRefCntPtrInfo. // //===----------------------------------------------------------------------===// @@ -27,261 +62,204 @@ namespace llvm { - template <class T> - class IntrusiveRefCntPtr; - -//===----------------------------------------------------------------------===// -/// RefCountedBase - A generic base class for objects that wish to -/// have their lifetimes managed using reference counts. Classes -/// subclass RefCountedBase to obtain such functionality, and are -/// typically handled with IntrusiveRefCntPtr "smart pointers" (see below) -/// which automatically handle the management of reference counts. -/// Objects that subclass RefCountedBase should not be allocated on -/// the stack, as invoking "delete" (which is called when the -/// reference count hits 0) on such objects is an error. -//===----------------------------------------------------------------------===// - template <class Derived> - class RefCountedBase { - mutable unsigned ref_cnt; - - public: - RefCountedBase() : ref_cnt(0) {} - RefCountedBase(const RefCountedBase &) : ref_cnt(0) {} - - void Retain() const { ++ref_cnt; } - void Release() const { - assert (ref_cnt > 0 && "Reference count is already zero."); - if (--ref_cnt == 0) delete static_cast<const Derived*>(this); - } - }; - -//===----------------------------------------------------------------------===// -/// RefCountedBaseVPTR - A class that has the same function as -/// RefCountedBase, but with a virtual destructor. Should be used -/// instead of RefCountedBase for classes that already have virtual -/// methods to enforce dynamic allocation via 'new'. Classes that -/// inherit from RefCountedBaseVPTR can't be allocated on stack - -/// attempting to do this will produce a compile error. -//===----------------------------------------------------------------------===// - class RefCountedBaseVPTR { - mutable unsigned ref_cnt; - virtual void anchor(); - - protected: - RefCountedBaseVPTR() : ref_cnt(0) {} - RefCountedBaseVPTR(const RefCountedBaseVPTR &) : ref_cnt(0) {} - - virtual ~RefCountedBaseVPTR() {} - - void Retain() const { ++ref_cnt; } - void Release() const { - assert (ref_cnt > 0 && "Reference count is already zero."); - if (--ref_cnt == 0) delete this; - } - - template <typename T> - friend struct IntrusiveRefCntPtrInfo; - }; +/// A CRTP mixin class that adds reference counting to a type. +/// +/// The lifetime of an object which inherits from RefCountedBase is managed by +/// calls to Release() and Retain(), which increment and decrement the object's +/// refcount, respectively. When a Release() call decrements the refcount to 0, +/// the object deletes itself. +template <class Derived> class RefCountedBase { + mutable unsigned RefCount = 0; +public: + RefCountedBase() = default; + RefCountedBase(const RefCountedBase &) : RefCount(0) {} - template <typename T> struct IntrusiveRefCntPtrInfo { - static void retain(T *obj) { obj->Retain(); } - static void release(T *obj) { obj->Release(); } - }; + void Retain() const { ++RefCount; } + void Release() const { + assert(RefCount > 0 && "Reference count is already zero."); + if (--RefCount == 0) + delete static_cast<const Derived *>(this); + } +}; -/// \brief A thread-safe version of \c llvm::RefCountedBase. -/// -/// A generic base class for objects that wish to have their lifetimes managed -/// using reference counts. Classes subclass \c ThreadSafeRefCountedBase to -/// obtain such functionality, and are typically handled with -/// \c IntrusiveRefCntPtr "smart pointers" which automatically handle the -/// management of reference counts. -template <class Derived> -class ThreadSafeRefCountedBase { +/// A thread-safe version of \c RefCountedBase. +template <class Derived> class ThreadSafeRefCountedBase { mutable std::atomic<int> RefCount; protected: ThreadSafeRefCountedBase() : RefCount(0) {} public: - void Retain() const { ++RefCount; } + void Retain() const { RefCount.fetch_add(1, std::memory_order_relaxed); } void Release() const { - int NewRefCount = --RefCount; + int NewRefCount = RefCount.fetch_sub(1, std::memory_order_acq_rel) - 1; assert(NewRefCount >= 0 && "Reference count was already zero."); if (NewRefCount == 0) - delete static_cast<const Derived*>(this); + delete static_cast<const Derived *>(this); } }; -//===----------------------------------------------------------------------===// -/// IntrusiveRefCntPtr - A template class that implements a "smart pointer" -/// that assumes the wrapped object has a reference count associated -/// with it that can be managed via calls to -/// IntrusivePtrAddRef/IntrusivePtrRelease. The smart pointers -/// manage reference counts via the RAII idiom: upon creation of -/// smart pointer the reference count of the wrapped object is -/// incremented and upon destruction of the smart pointer the -/// reference count is decremented. This class also safely handles -/// wrapping NULL pointers. +/// Class you can specialize to provide custom retain/release functionality for +/// a type. /// -/// Reference counting is implemented via calls to -/// Obj->Retain()/Obj->Release(). Release() is required to destroy -/// the object when the reference count reaches zero. Inheriting from -/// RefCountedBase/RefCountedBaseVPTR takes care of this -/// automatically. -//===----------------------------------------------------------------------===// - template <typename T> - class IntrusiveRefCntPtr { - T* Obj; - - public: - typedef T element_type; - - explicit IntrusiveRefCntPtr() : Obj(nullptr) {} - - IntrusiveRefCntPtr(T* obj) : Obj(obj) { - retain(); - } - - IntrusiveRefCntPtr(const IntrusiveRefCntPtr& S) : Obj(S.Obj) { - retain(); - } - - IntrusiveRefCntPtr(IntrusiveRefCntPtr&& S) : Obj(S.Obj) { - S.Obj = nullptr; - } - - template <class X> - IntrusiveRefCntPtr(IntrusiveRefCntPtr<X>&& S) : Obj(S.get()) { - S.Obj = nullptr; - } - - template <class X> - IntrusiveRefCntPtr(const IntrusiveRefCntPtr<X>& S) - : Obj(S.get()) { - retain(); - } - - IntrusiveRefCntPtr& operator=(IntrusiveRefCntPtr S) { - swap(S); - return *this; - } - - ~IntrusiveRefCntPtr() { release(); } - - T& operator*() const { return *Obj; } - - T* operator->() const { return Obj; } - - T* get() const { return Obj; } - - explicit operator bool() const { return Obj; } - - void swap(IntrusiveRefCntPtr& other) { - T* tmp = other.Obj; - other.Obj = Obj; - Obj = tmp; - } - - void reset() { - release(); - Obj = nullptr; - } +/// Usually specializing this class is not necessary, as IntrusiveRefCntPtr +/// works with any type which defines Retain() and Release() functions -- you +/// can define those functions yourself if RefCountedBase doesn't work for you. +/// +/// One case when you might want to specialize this type is if you have +/// - Foo.h defines type Foo and includes Bar.h, and +/// - Bar.h uses IntrusiveRefCntPtr<Foo> in inline functions. +/// +/// Because Foo.h includes Bar.h, Bar.h can't include Foo.h in order to pull in +/// the declaration of Foo. Without the declaration of Foo, normally Bar.h +/// wouldn't be able to use IntrusiveRefCntPtr<Foo>, which wants to call +/// T::Retain and T::Release. +/// +/// To resolve this, Bar.h could include a third header, FooFwd.h, which +/// forward-declares Foo and specializes IntrusiveRefCntPtrInfo<Foo>. Then +/// Bar.h could use IntrusiveRefCntPtr<Foo>, although it still couldn't call any +/// functions on Foo itself, because Foo would be an incomplete type. +template <typename T> struct IntrusiveRefCntPtrInfo { + static void retain(T *obj) { obj->Retain(); } + static void release(T *obj) { obj->Release(); } +}; - void resetWithoutRelease() { - Obj = nullptr; - } +/// A smart pointer to a reference-counted object that inherits from +/// RefCountedBase or ThreadSafeRefCountedBase. +/// +/// This class increments its pointee's reference count when it is created, and +/// decrements its refcount when it's destroyed (or is changed to point to a +/// different object). +template <typename T> class IntrusiveRefCntPtr { + T *Obj = nullptr; - private: - void retain() { if (Obj) IntrusiveRefCntPtrInfo<T>::retain(Obj); } - void release() { if (Obj) IntrusiveRefCntPtrInfo<T>::release(Obj); } +public: + typedef T element_type; - template <typename X> - friend class IntrusiveRefCntPtr; - }; + explicit IntrusiveRefCntPtr() = default; + IntrusiveRefCntPtr(T *obj) : Obj(obj) { retain(); } + IntrusiveRefCntPtr(const IntrusiveRefCntPtr &S) : Obj(S.Obj) { retain(); } + IntrusiveRefCntPtr(IntrusiveRefCntPtr &&S) : Obj(S.Obj) { S.Obj = nullptr; } - template<class T, class U> - inline bool operator==(const IntrusiveRefCntPtr<T>& A, - const IntrusiveRefCntPtr<U>& B) - { - return A.get() == B.get(); + template <class X> + IntrusiveRefCntPtr(IntrusiveRefCntPtr<X> &&S) : Obj(S.get()) { + S.Obj = nullptr; } - template<class T, class U> - inline bool operator!=(const IntrusiveRefCntPtr<T>& A, - const IntrusiveRefCntPtr<U>& B) - { - return A.get() != B.get(); + template <class X> + IntrusiveRefCntPtr(const IntrusiveRefCntPtr<X> &S) : Obj(S.get()) { + retain(); } - template<class T, class U> - inline bool operator==(const IntrusiveRefCntPtr<T>& A, - U* B) - { - return A.get() == B; + IntrusiveRefCntPtr &operator=(IntrusiveRefCntPtr S) { + swap(S); + return *this; } - template<class T, class U> - inline bool operator!=(const IntrusiveRefCntPtr<T>& A, - U* B) - { - return A.get() != B; - } + ~IntrusiveRefCntPtr() { release(); } - template<class T, class U> - inline bool operator==(T* A, - const IntrusiveRefCntPtr<U>& B) - { - return A == B.get(); - } + T &operator*() const { return *Obj; } + T *operator->() const { return Obj; } + T *get() const { return Obj; } + explicit operator bool() const { return Obj; } - template<class T, class U> - inline bool operator!=(T* A, - const IntrusiveRefCntPtr<U>& B) - { - return A != B.get(); + void swap(IntrusiveRefCntPtr &other) { + T *tmp = other.Obj; + other.Obj = Obj; + Obj = tmp; } - template <class T> - bool operator==(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) { - return !B; + void reset() { + release(); + Obj = nullptr; } - template <class T> - bool operator==(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) { - return B == A; - } + void resetWithoutRelease() { Obj = nullptr; } - template <class T> - bool operator!=(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) { - return !(A == B); +private: + void retain() { + if (Obj) + IntrusiveRefCntPtrInfo<T>::retain(Obj); } - - template <class T> - bool operator!=(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) { - return !(A == B); + void release() { + if (Obj) + IntrusiveRefCntPtrInfo<T>::release(Obj); } -//===----------------------------------------------------------------------===// -// LLVM-style downcasting support for IntrusiveRefCntPtr objects -//===----------------------------------------------------------------------===// + template <typename X> friend class IntrusiveRefCntPtr; +}; + +template <class T, class U> +inline bool operator==(const IntrusiveRefCntPtr<T> &A, + const IntrusiveRefCntPtr<U> &B) { + return A.get() == B.get(); +} + +template <class T, class U> +inline bool operator!=(const IntrusiveRefCntPtr<T> &A, + const IntrusiveRefCntPtr<U> &B) { + return A.get() != B.get(); +} + +template <class T, class U> +inline bool operator==(const IntrusiveRefCntPtr<T> &A, U *B) { + return A.get() == B; +} + +template <class T, class U> +inline bool operator!=(const IntrusiveRefCntPtr<T> &A, U *B) { + return A.get() != B; +} + +template <class T, class U> +inline bool operator==(T *A, const IntrusiveRefCntPtr<U> &B) { + return A == B.get(); +} + +template <class T, class U> +inline bool operator!=(T *A, const IntrusiveRefCntPtr<U> &B) { + return A != B.get(); +} + +template <class T> +bool operator==(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) { + return !B; +} + +template <class T> +bool operator==(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) { + return B == A; +} + +template <class T> +bool operator!=(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) { + return !(A == B); +} + +template <class T> +bool operator!=(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) { + return !(A == B); +} + +// Make IntrusiveRefCntPtr work with dyn_cast, isa, and the other idioms from +// Casting.h. +template <typename From> struct simplify_type; + +template <class T> struct simplify_type<IntrusiveRefCntPtr<T>> { + typedef T *SimpleType; + static SimpleType getSimplifiedValue(IntrusiveRefCntPtr<T> &Val) { + return Val.get(); + } +}; - template <typename From> struct simplify_type; - - template<class T> struct simplify_type<IntrusiveRefCntPtr<T> > { - typedef T* SimpleType; - static SimpleType getSimplifiedValue(IntrusiveRefCntPtr<T>& Val) { - return Val.get(); - } - }; - - template<class T> struct simplify_type<const IntrusiveRefCntPtr<T> > { - typedef /*const*/ T* SimpleType; - static SimpleType getSimplifiedValue(const IntrusiveRefCntPtr<T>& Val) { - return Val.get(); - } - }; +template <class T> struct simplify_type<const IntrusiveRefCntPtr<T>> { + typedef /*const*/ T *SimpleType; + static SimpleType getSimplifiedValue(const IntrusiveRefCntPtr<T> &Val) { + return Val.get(); + } +}; } // end namespace llvm |