|
|
|
@ -215,31 +215,45 @@ class NonPolymorphicRefCount { |
|
|
|
|
~NonPolymorphicRefCount() = default; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
// Behavior of RefCounted<> upon ref count reaching 0.
|
|
|
|
|
enum UnrefBehavior { |
|
|
|
|
// Default behavior: Delete the object.
|
|
|
|
|
kUnrefDelete, |
|
|
|
|
// Do not delete the object upon unref. This is useful in cases where all
|
|
|
|
|
// existing objects must be tracked in a registry but the object's entry in
|
|
|
|
|
// the registry cannot be removed from the object's dtor due to
|
|
|
|
|
// synchronization issues. In this case, the registry can be cleaned up
|
|
|
|
|
// later by identifying entries for which RefIfNonZero() returns null.
|
|
|
|
|
kUnrefNoDelete, |
|
|
|
|
// Call the object's dtor but do not delete it. This is useful for cases
|
|
|
|
|
// where the object is stored in memory allocated elsewhere (e.g., the call
|
|
|
|
|
// arena).
|
|
|
|
|
kUnrefCallDtor, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
namespace internal { |
|
|
|
|
template <typename T, bool DoDelete> |
|
|
|
|
template <typename T, UnrefBehavior UnrefBehaviorArg> |
|
|
|
|
class Delete; |
|
|
|
|
template <typename T> |
|
|
|
|
class Delete<T, true> { |
|
|
|
|
class Delete<T, kUnrefDelete> { |
|
|
|
|
public: |
|
|
|
|
explicit Delete(T* t) { delete t; } |
|
|
|
|
}; |
|
|
|
|
template <typename T> |
|
|
|
|
class Delete<T, false> { |
|
|
|
|
class Delete<T, kUnrefNoDelete> { |
|
|
|
|
public: |
|
|
|
|
explicit Delete(T* /*t*/) {} |
|
|
|
|
}; |
|
|
|
|
template <typename T> |
|
|
|
|
class Delete<T, kUnrefCallDtor> { |
|
|
|
|
public: |
|
|
|
|
explicit Delete(T* t) { t->~T(); } |
|
|
|
|
}; |
|
|
|
|
} // namespace internal
|
|
|
|
|
|
|
|
|
|
// A base class for reference-counted objects.
|
|
|
|
|
// New objects should be created via new and start with a refcount of 1.
|
|
|
|
|
// When the refcount reaches 0, the object will be deleted via delete.
|
|
|
|
|
//
|
|
|
|
|
// If DeleteUponUnref is false, deletion will not occur when the ref
|
|
|
|
|
// count reaches 0. This is useful in cases where all existing objects
|
|
|
|
|
// must be tracked in a registry but the object's entry in the registry
|
|
|
|
|
// cannot be removed from the object's dtor due to synchronization issues.
|
|
|
|
|
// In this case, the registry can be cleaned up later by identifying
|
|
|
|
|
// entries for which RefIfNonZero() returns null.
|
|
|
|
|
// When the refcount reaches 0, executes the specified UnrefBehavior.
|
|
|
|
|
//
|
|
|
|
|
// This will commonly be used by CRTP (curiously-recurring template pattern)
|
|
|
|
|
// e.g., class MyClass : public RefCounted<MyClass>
|
|
|
|
@ -264,7 +278,7 @@ class Delete<T, false> { |
|
|
|
|
// ch->Unref();
|
|
|
|
|
//
|
|
|
|
|
template <typename Child, typename Impl = PolymorphicRefCount, |
|
|
|
|
bool DeleteUponUnref = true> |
|
|
|
|
UnrefBehavior UnrefBehaviorArg = kUnrefDelete> |
|
|
|
|
class RefCounted : public Impl { |
|
|
|
|
public: |
|
|
|
|
// Note: Depending on the Impl used, this dtor can be implicitly virtual.
|
|
|
|
@ -287,12 +301,12 @@ class RefCounted : public Impl { |
|
|
|
|
// friend of this class.
|
|
|
|
|
void Unref() { |
|
|
|
|
if (GPR_UNLIKELY(refs_.Unref())) { |
|
|
|
|
internal::Delete<Child, DeleteUponUnref>(static_cast<Child*>(this)); |
|
|
|
|
internal::Delete<Child, UnrefBehaviorArg>(static_cast<Child*>(this)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
void Unref(const DebugLocation& location, const char* reason) { |
|
|
|
|
if (GPR_UNLIKELY(refs_.Unref(location, reason))) { |
|
|
|
|
internal::Delete<Child, DeleteUponUnref>(static_cast<Child*>(this)); |
|
|
|
|
internal::Delete<Child, UnrefBehaviorArg>(static_cast<Child*>(this)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|