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