1/*
2 * Copyright (C) 2006, 2007, 2009, 2010 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 TreeShared_h
22#define TreeShared_h
23
24#include <wtf/Assertions.h>
25#include <wtf/Noncopyable.h>
26#include <wtf/Threading.h>
27
28namespace WebCore {
29
30#ifndef NDEBUG
31template<typename T> class TreeShared;
32template<typename T> void adopted(TreeShared<T>*);
33#endif
34
35template<typename T> class TreeShared {
36    WTF_MAKE_NONCOPYABLE(TreeShared);
37public:
38    TreeShared()
39        : m_refCount(1)
40        , m_parent(0)
41#ifndef NDEBUG
42        , m_adoptionIsRequired(true)
43#endif
44    {
45        ASSERT(isMainThread());
46#ifndef NDEBUG
47        m_deletionHasBegun = false;
48        m_inRemovedLastRefFunction = false;
49#endif
50    }
51    virtual ~TreeShared()
52    {
53        ASSERT(isMainThread());
54        ASSERT(!m_refCount);
55        ASSERT(m_deletionHasBegun);
56        ASSERT(!m_adoptionIsRequired);
57    }
58
59    void ref()
60    {
61        ASSERT(isMainThread());
62        ASSERT(!m_deletionHasBegun);
63        ASSERT(!m_inRemovedLastRefFunction);
64        ASSERT(!m_adoptionIsRequired);
65        ++m_refCount;
66    }
67
68    void deref()
69    {
70        ASSERT(isMainThread());
71        ASSERT(m_refCount >= 0);
72        ASSERT(!m_deletionHasBegun);
73        ASSERT(!m_inRemovedLastRefFunction);
74        ASSERT(!m_adoptionIsRequired);
75        if (--m_refCount <= 0 && !m_parent) {
76#ifndef NDEBUG
77            m_inRemovedLastRefFunction = true;
78#endif
79            removedLastRef();
80        }
81    }
82
83    bool hasOneRef() const
84    {
85        ASSERT(!m_deletionHasBegun);
86        ASSERT(!m_inRemovedLastRefFunction);
87        return m_refCount == 1;
88    }
89
90    int refCount() const
91    {
92        return m_refCount;
93    }
94
95    void setParent(T* parent)
96    {
97        ASSERT(isMainThread());
98        m_parent = parent;
99    }
100
101    T* parent() const
102    {
103        ASSERT(isMainThread());
104        return m_parent;
105    }
106
107#ifndef NDEBUG
108    bool m_deletionHasBegun;
109    bool m_inRemovedLastRefFunction;
110#endif
111
112protected:
113    virtual void removedLastRef()
114    {
115#ifndef NDEBUG
116        m_deletionHasBegun = true;
117#endif
118        delete this;
119    }
120
121private:
122#ifndef NDEBUG
123    friend void adopted<>(TreeShared<T>*);
124#endif
125
126    int m_refCount;
127    T* m_parent;
128#ifndef NDEBUG
129    bool m_adoptionIsRequired;
130#endif
131};
132
133#ifndef NDEBUG
134
135template<typename T> inline void adopted(TreeShared<T>* object)
136{
137    if (!object)
138        return;
139    ASSERT(!object->m_deletionHasBegun);
140    ASSERT(!object->m_inRemovedLastRefFunction);
141    object->m_adoptionIsRequired = false;
142}
143
144#endif
145
146}
147
148#endif // TreeShared.h
149