Viewing file: IntrusiveRefCntPtr.h (9.67 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
//==- llvm/ADT/IntrusiveRefCntPtr.h - Smart Refcounting Pointer --*- C++ -*-==// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// /// /// \file /// This file defines the RefCountedBase, ThreadSafeRefCountedBase, and /// IntrusiveRefCntPtr classes. /// /// 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. /// //===----------------------------------------------------------------------===//
#ifndef LLVM_ADT_INTRUSIVEREFCNTPTR_H #define LLVM_ADT_INTRUSIVEREFCNTPTR_H
#include <atomic> #include <cassert> #include <cstddef> #include <memory>
namespace llvm {
/// 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;
protected: RefCountedBase() = default; RefCountedBase(const RefCountedBase &) {} RefCountedBase &operator=(const RefCountedBase &) = delete;
#ifndef NDEBUG ~RefCountedBase() { assert(RefCount == 0 && "Destruction occurred when there are still references to this."); } #else // Default the destructor in release builds, A trivial destructor may enable // better codegen. ~RefCountedBase() = default; #endif
public: unsigned UseCount() const { return RefCount; }
void Retain() const { ++RefCount; }
void Release() const { assert(RefCount > 0 && "Reference count is already zero."); if (--RefCount == 0) delete static_cast<const Derived *>(this); } };
/// A thread-safe version of \c RefCountedBase. template <class Derived> class ThreadSafeRefCountedBase { mutable std::atomic<int> RefCount{0};
protected: ThreadSafeRefCountedBase() = default; ThreadSafeRefCountedBase(const ThreadSafeRefCountedBase &) {} ThreadSafeRefCountedBase & operator=(const ThreadSafeRefCountedBase &) = delete;
#ifndef NDEBUG ~ThreadSafeRefCountedBase() { assert(RefCount == 0 && "Destruction occurred when there are still references to this."); } #else // Default the destructor in release builds, A trivial destructor may enable // better codegen. ~ThreadSafeRefCountedBase() = default; #endif
public: unsigned UseCount() const { return RefCount.load(std::memory_order_relaxed); }
void Retain() const { RefCount.fetch_add(1, std::memory_order_relaxed); }
void Release() const { 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); } };
/// Class you can specialize to provide custom retain/release functionality for /// a type. /// /// 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 unsigned useCount(const T *obj) { return obj->UseCount(); } static void retain(T *obj) { obj->Retain(); } static void release(T *obj) { obj->Release(); } };
/// 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;
public: using element_type = T;
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 X, std::enable_if_t<std::is_convertible<X *, T *>::value, bool> = true> IntrusiveRefCntPtr(IntrusiveRefCntPtr<X> S) : Obj(S.get()) { S.Obj = nullptr; }
template <class X, std::enable_if_t<std::is_convertible<X *, T *>::value, bool> = true> IntrusiveRefCntPtr(std::unique_ptr<X> S) : Obj(S.release()) { retain(); }
~IntrusiveRefCntPtr() { release(); }
IntrusiveRefCntPtr &operator=(IntrusiveRefCntPtr S) { swap(S); return *this; }
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; }
void resetWithoutRelease() { Obj = nullptr; }
unsigned useCount() const { return Obj ? IntrusiveRefCntPtrInfo<T>::useCount(Obj) : 0; }
private: void retain() { if (Obj) IntrusiveRefCntPtrInfo<T>::retain(Obj); }
void release() { if (Obj) IntrusiveRefCntPtrInfo<T>::release(Obj); }
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, 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>> { using SimpleType = T *;
static SimpleType getSimplifiedValue(IntrusiveRefCntPtr<T> &Val) { return Val.get(); } };
template <class T> struct simplify_type<const IntrusiveRefCntPtr<T>> { using SimpleType = /*const*/ T *;
static SimpleType getSimplifiedValue(const IntrusiveRefCntPtr<T> &Val) { return Val.get(); } };
/// Factory function for creating intrusive ref counted pointers. template <typename T, typename... Args> IntrusiveRefCntPtr<T> makeIntrusiveRefCnt(Args &&...A) { return IntrusiveRefCntPtr<T>(new T(std::forward<Args>(A)...)); }
} // end namespace llvm
#endif // LLVM_ADT_INTRUSIVEREFCNTPTR_H
|