1/*
2 *  Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
3 *  Copyright (C) 2008 Collabora Ltd.
4 *  Copyright (C) 2009 Martin Robinson
5 *
6 *  This library is free software; you can redistribute it and/or
7 *  modify it under the terms of the GNU Library General Public
8 *  License as published by the Free Software Foundation; either
9 *  version 2 of the License, or (at your option) any later version.
10 *
11 *  This library is distributed in the hope that it will be useful,
12 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 *  Library General Public License for more details.
15 *
16 *  You should have received a copy of the GNU Library General Public License
17 *  along with this library; see the file COPYING.LIB.  If not, write to
18 *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 *  Boston, MA 02110-1301, USA.
20 *
21 */
22
23#ifndef WTF_GRefPtr_h
24#define WTF_GRefPtr_h
25
26#if ENABLE(GLIB_SUPPORT)
27
28#include "AlwaysInline.h"
29#include "GRefPtr.h"
30#include "RefPtr.h"
31#include <algorithm>
32
33extern "C" void g_object_unref(gpointer);
34extern "C" gpointer g_object_ref_sink(gpointer);
35
36namespace WTF {
37
38enum GRefPtrAdoptType { GRefPtrAdopt };
39template <typename T> inline T* refGPtr(T*);
40template <typename T> inline void derefGPtr(T*);
41template <typename T> class GRefPtr;
42template <typename T> GRefPtr<T> adoptGRef(T*);
43
44template <typename T> class GRefPtr {
45public:
46    GRefPtr() : m_ptr(0) { }
47
48    GRefPtr(T* ptr)
49        : m_ptr(ptr)
50    {
51        if (ptr)
52            refGPtr(ptr);
53    }
54
55    GRefPtr(const GRefPtr& o)
56        : m_ptr(o.m_ptr)
57    {
58        if (T* ptr = m_ptr)
59            refGPtr(ptr);
60    }
61
62    template <typename U> GRefPtr(const GRefPtr<U>& o)
63        : m_ptr(o.get())
64    {
65        if (T* ptr = m_ptr)
66            refGPtr(ptr);
67    }
68
69    ~GRefPtr()
70    {
71        if (T* ptr = m_ptr)
72            derefGPtr(ptr);
73    }
74
75    void clear()
76    {
77        T* ptr = m_ptr;
78        m_ptr = 0;
79        if (ptr)
80            derefGPtr(ptr);
81    }
82
83    T* leakRef() WARN_UNUSED_RETURN
84    {
85        T* ptr = m_ptr;
86        m_ptr = 0;
87        return ptr;
88    }
89
90    // Hash table deleted values, which are only constructed and never copied or destroyed.
91    GRefPtr(HashTableDeletedValueType) : m_ptr(hashTableDeletedValue()) { }
92    bool isHashTableDeletedValue() const { return m_ptr == hashTableDeletedValue(); }
93
94    T* get() const { return m_ptr; }
95    T& operator*() const { return *m_ptr; }
96    ALWAYS_INLINE T* operator->() const { return m_ptr; }
97
98    bool operator!() const { return !m_ptr; }
99
100    // This conversion operator allows implicit conversion to bool but not to other integer types.
101    typedef T* GRefPtr::*UnspecifiedBoolType;
102    operator UnspecifiedBoolType() const { return m_ptr ? &GRefPtr::m_ptr : 0; }
103
104    GRefPtr& operator=(const GRefPtr&);
105    GRefPtr& operator=(T*);
106    template <typename U> GRefPtr& operator=(const GRefPtr<U>&);
107
108    void swap(GRefPtr&);
109    friend GRefPtr adoptGRef<T>(T*);
110
111private:
112    static T* hashTableDeletedValue() { return reinterpret_cast<T*>(-1); }
113    // Adopting constructor.
114    GRefPtr(T* ptr, GRefPtrAdoptType) : m_ptr(ptr) {}
115
116    T* m_ptr;
117};
118
119template <typename T> inline GRefPtr<T>& GRefPtr<T>::operator=(const GRefPtr<T>& o)
120{
121    T* optr = o.get();
122    if (optr)
123        refGPtr(optr);
124    T* ptr = m_ptr;
125    m_ptr = optr;
126    if (ptr)
127        derefGPtr(ptr);
128    return *this;
129}
130
131template <typename T> inline GRefPtr<T>& GRefPtr<T>::operator=(T* optr)
132{
133    T* ptr = m_ptr;
134    if (optr)
135        refGPtr(optr);
136    m_ptr = optr;
137    if (ptr)
138        derefGPtr(ptr);
139    return *this;
140}
141
142template <class T> inline void GRefPtr<T>::swap(GRefPtr<T>& o)
143{
144    std::swap(m_ptr, o.m_ptr);
145}
146
147template <class T> inline void swap(GRefPtr<T>& a, GRefPtr<T>& b)
148{
149    a.swap(b);
150}
151
152template <typename T, typename U> inline bool operator==(const GRefPtr<T>& a, const GRefPtr<U>& b)
153{
154    return a.get() == b.get();
155}
156
157template <typename T, typename U> inline bool operator==(const GRefPtr<T>& a, U* b)
158{
159    return a.get() == b;
160}
161
162template <typename T, typename U> inline bool operator==(T* a, const GRefPtr<U>& b)
163{
164    return a == b.get();
165}
166
167template <typename T, typename U> inline bool operator!=(const GRefPtr<T>& a, const GRefPtr<U>& b)
168{
169    return a.get() != b.get();
170}
171
172template <typename T, typename U> inline bool operator!=(const GRefPtr<T>& a, U* b)
173{
174    return a.get() != b;
175}
176
177template <typename T, typename U> inline bool operator!=(T* a, const GRefPtr<U>& b)
178{
179    return a != b.get();
180}
181
182template <typename T, typename U> inline GRefPtr<T> static_pointer_cast(const GRefPtr<U>& p)
183{
184    return GRefPtr<T>(static_cast<T*>(p.get()));
185}
186
187template <typename T, typename U> inline GRefPtr<T> const_pointer_cast(const GRefPtr<U>& p)
188{
189    return GRefPtr<T>(const_cast<T*>(p.get()));
190}
191
192template <typename T> inline T* getPtr(const GRefPtr<T>& p)
193{
194    return p.get();
195}
196
197template <typename T> GRefPtr<T> adoptGRef(T* p)
198{
199    return GRefPtr<T>(p, GRefPtrAdopt);
200}
201
202template <> GHashTable* refGPtr(GHashTable* ptr);
203template <> void derefGPtr(GHashTable* ptr);
204template <> GVariant* refGPtr(GVariant* ptr);
205template <> void derefGPtr(GVariant* ptr);
206template <> GSource* refGPtr(GSource* ptr);
207template <> void derefGPtr(GSource* ptr);
208
209template <typename T> inline T* refGPtr(T* ptr)
210{
211    if (ptr)
212        g_object_ref_sink(ptr);
213    return ptr;
214}
215
216template <typename T> inline void derefGPtr(T* ptr)
217{
218    if (ptr)
219        g_object_unref(ptr);
220}
221
222} // namespace WTF
223
224using WTF::GRefPtr;
225using WTF::adoptGRef;
226
227#endif // ENABLE(GLIB_SUPPORT)
228
229#endif // WTF_GRefPtr_h
230