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#if defined(NDEBUG) && !ENABLE(SECURITY_ASSERTIONS)
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_WITH_SECURITY_IMPLICATION(!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_WITH_SECURITY_IMPLICATION(!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_WITH_SECURITY_IMPLICATION(!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_WITH_SECURITY_IMPLICATION(!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