michael@0: /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: // This header provides virtual, non-templated alternatives to MFBT's RefCounted. michael@0: // It intentionally uses MFBT coding style with the intention of moving there michael@0: // should there be other use cases for it. michael@0: michael@0: #ifndef MOZILLA_GENERICREFCOUNTED_H_ michael@0: #define MOZILLA_GENERICREFCOUNTED_H_ michael@0: michael@0: #include "mozilla/RefPtr.h" michael@0: michael@0: namespace mozilla { michael@0: michael@0: /** michael@0: * Common base class for GenericRefCounted and GenericAtomicRefCounted. michael@0: * michael@0: * Having this shared base class, common to both the atomic and non-atomic michael@0: * cases, allows to have RefPtr's that don't care about whether the michael@0: * objects they're managing have atomic refcounts or not. michael@0: */ michael@0: class GenericRefCountedBase michael@0: { michael@0: protected: michael@0: virtual ~GenericRefCountedBase() {}; michael@0: michael@0: public: michael@0: // AddRef() and Release() method names are for compatibility with nsRefPtr. michael@0: virtual void AddRef() = 0; michael@0: michael@0: virtual void Release() = 0; michael@0: michael@0: // ref() and deref() method names are for compatibility with wtf::RefPtr. michael@0: // No virtual keywords here: if a subclass wants to override the refcounting michael@0: // mechanism, it is welcome to do so by overriding AddRef() and Release(). michael@0: void ref() { AddRef(); } michael@0: void deref() { Release(); } michael@0: michael@0: #ifdef MOZ_REFCOUNTED_LEAK_CHECKING michael@0: virtual const char* typeName() const = 0; michael@0: virtual size_t typeSize() const = 0; michael@0: #endif michael@0: }; michael@0: michael@0: namespace detail { michael@0: michael@0: template michael@0: class GenericRefCounted : public GenericRefCountedBase michael@0: { michael@0: protected: michael@0: GenericRefCounted() : refCnt(0) { } michael@0: michael@0: virtual ~GenericRefCounted() { michael@0: MOZ_ASSERT(refCnt == detail::DEAD); michael@0: } michael@0: michael@0: public: michael@0: virtual void AddRef() { michael@0: // Note: this method must be thread safe for GenericAtomicRefCounted. michael@0: MOZ_ASSERT(int32_t(refCnt) >= 0); michael@0: #ifndef MOZ_REFCOUNTED_LEAK_CHECKING michael@0: ++refCnt; michael@0: #else michael@0: const char* type = typeName(); michael@0: uint32_t size = typeSize(); michael@0: const void* ptr = this; michael@0: MozRefCountType cnt = ++refCnt; michael@0: detail::RefCountLogger::logAddRef(ptr, cnt, type, size); michael@0: #endif michael@0: } michael@0: michael@0: virtual void Release() { michael@0: // Note: this method must be thread safe for GenericAtomicRefCounted. michael@0: MOZ_ASSERT(int32_t(refCnt) > 0); michael@0: #ifndef MOZ_REFCOUNTED_LEAK_CHECKING michael@0: MozRefCountType cnt = --refCnt; michael@0: #else michael@0: const char* type = typeName(); michael@0: const void* ptr = this; michael@0: MozRefCountType cnt = --refCnt; michael@0: // Note: it's not safe to touch |this| after decrementing the refcount, michael@0: // except for below. michael@0: detail::RefCountLogger::logRelease(ptr, cnt, type); michael@0: #endif michael@0: if (0 == cnt) { michael@0: // Because we have atomically decremented the refcount above, only michael@0: // one thread can get a 0 count here, so as long as we can assume that michael@0: // everything else in the system is accessing this object through michael@0: // RefPtrs, it's safe to access |this| here. michael@0: #ifdef DEBUG michael@0: refCnt = detail::DEAD; michael@0: #endif michael@0: delete this; michael@0: } michael@0: } michael@0: michael@0: MozRefCountType refCount() const { return refCnt; } michael@0: bool hasOneRef() const { michael@0: MOZ_ASSERT(refCnt > 0); michael@0: return refCnt == 1; michael@0: } michael@0: michael@0: private: michael@0: typename Conditional, MozRefCountType>::Type refCnt; michael@0: }; michael@0: michael@0: } // namespace detail michael@0: michael@0: /** michael@0: * This reference-counting base class is virtual instead of michael@0: * being templated, which is useful in cases where one needs michael@0: * genericity at binary code level, but comes at the cost michael@0: * of a moderate performance and size overhead, like anything virtual. michael@0: */ michael@0: class GenericRefCounted : public detail::GenericRefCounted michael@0: { michael@0: }; michael@0: michael@0: /** michael@0: * GenericAtomicRefCounted is like GenericRefCounted, with an atomically updated michael@0: * reference counter. michael@0: */ michael@0: class GenericAtomicRefCounted : public detail::GenericRefCounted michael@0: { michael@0: }; michael@0: michael@0: } // namespace mozilla michael@0: michael@0: #endif