1/* 2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2013 Apple Inc. All rights reserved. 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Library General Public 6 * License as published by the Free Software Foundation; either 7 * version 2 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Library General Public License for more details. 13 * 14 * You should have received a copy of the GNU Library General Public License 15 * along with this library; see the file COPYING.LIB. If not, write to 16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 * Boston, MA 02110-1301, USA. 18 * 19 */ 20 21#ifndef RefCounted_h 22#define RefCounted_h 23 24#include <wtf/Assertions.h> 25#include <wtf/FastMalloc.h> 26#include <wtf/Noncopyable.h> 27 28namespace WTF { 29 30#ifdef NDEBUG 31#define CHECK_REF_COUNTED_LIFECYCLE 0 32#else 33#define CHECK_REF_COUNTED_LIFECYCLE 1 34#endif 35 36// This base class holds the non-template methods and attributes. 37// The RefCounted class inherits from it reducing the template bloat 38// generated by the compiler (technique called template hoisting). 39class RefCountedBase { 40public: 41 void ref() 42 { 43#if CHECK_REF_COUNTED_LIFECYCLE 44 ASSERT(!m_deletionHasBegun); 45 ASSERT(!m_adoptionIsRequired); 46#endif 47 ++m_refCount; 48 } 49 50 bool hasOneRef() const 51 { 52#if CHECK_REF_COUNTED_LIFECYCLE 53 ASSERT(!m_deletionHasBegun); 54#endif 55 return m_refCount == 1; 56 } 57 58 unsigned refCount() const 59 { 60 return m_refCount; 61 } 62 63 void relaxAdoptionRequirement() 64 { 65#if CHECK_REF_COUNTED_LIFECYCLE 66 ASSERT(!m_deletionHasBegun); 67 ASSERT(m_adoptionIsRequired); 68 m_adoptionIsRequired = false; 69#endif 70 } 71 72protected: 73 RefCountedBase() 74 : m_refCount(1) 75#if CHECK_REF_COUNTED_LIFECYCLE 76 , m_deletionHasBegun(false) 77 , m_adoptionIsRequired(true) 78#endif 79 { 80 } 81 82 ~RefCountedBase() 83 { 84#if CHECK_REF_COUNTED_LIFECYCLE 85 ASSERT(m_deletionHasBegun); 86 ASSERT(!m_adoptionIsRequired); 87#endif 88 } 89 90 // Returns whether the pointer should be freed or not. 91 bool derefBase() 92 { 93#if CHECK_REF_COUNTED_LIFECYCLE 94 ASSERT(!m_deletionHasBegun); 95 ASSERT(!m_adoptionIsRequired); 96#endif 97 98 ASSERT(m_refCount); 99 unsigned tempRefCount = m_refCount - 1; 100 if (!tempRefCount) { 101#if CHECK_REF_COUNTED_LIFECYCLE 102 m_deletionHasBegun = true; 103#endif 104 return true; 105 } 106 m_refCount = tempRefCount; 107 return false; 108 } 109 110#if CHECK_REF_COUNTED_LIFECYCLE 111 bool deletionHasBegun() const 112 { 113 return m_deletionHasBegun; 114 } 115#endif 116 117private: 118 119#if CHECK_REF_COUNTED_LIFECYCLE 120 friend void adopted(RefCountedBase*); 121#endif 122 123 unsigned m_refCount; 124#if CHECK_REF_COUNTED_LIFECYCLE 125 bool m_deletionHasBegun; 126 bool m_adoptionIsRequired; 127#endif 128}; 129 130#if CHECK_REF_COUNTED_LIFECYCLE 131inline void adopted(RefCountedBase* object) 132{ 133 if (!object) 134 return; 135 ASSERT(!object->m_deletionHasBegun); 136 object->m_adoptionIsRequired = false; 137} 138#endif 139 140template<typename T> class RefCounted : public RefCountedBase { 141 WTF_MAKE_NONCOPYABLE(RefCounted); WTF_MAKE_FAST_ALLOCATED; 142public: 143 void deref() 144 { 145 if (derefBase()) 146 delete static_cast<T*>(this); 147 } 148 149protected: 150 RefCounted() { } 151 ~RefCounted() 152 { 153 } 154}; 155 156} // namespace WTF 157 158using WTF::RefCounted; 159 160#endif // RefCounted_h 161