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 USE(GLIB)
27
28#include <wtf/RefPtr.h>
29#include <algorithm>
30
31extern "C" void g_object_unref(gpointer);
32extern "C" gpointer g_object_ref_sink(gpointer);
33
34namespace WTF {
35
36enum GRefPtrAdoptType { GRefPtrAdopt };
37template <typename T> inline T* refGPtr(T*);
38template <typename T> inline void derefGPtr(T*);
39template <typename T> class GRefPtr;
40template <typename T> GRefPtr<T> adoptGRef(T*);
41
42template <typename T> class GRefPtr {
43public:
44    GRefPtr() : m_ptr(0) { }
45
46    GRefPtr(T* ptr)
47        : m_ptr(ptr)
48    {
49        if (ptr)
50            refGPtr(ptr);
51    }
52
53    GRefPtr(const GRefPtr& o)
54        : m_ptr(o.m_ptr)
55    {
56        if (T* ptr = m_ptr)
57            refGPtr(ptr);
58    }
59
60    template <typename U> GRefPtr(const GRefPtr<U>& o)
61        : m_ptr(o.get())
62    {
63        if (T* ptr = m_ptr)
64            refGPtr(ptr);
65    }
66
67    ~GRefPtr()
68    {
69        if (T* ptr = m_ptr)
70            derefGPtr(ptr);
71    }
72
73    void clear()
74    {
75        T* ptr = m_ptr;
76        m_ptr = 0;
77        if (ptr)
78            derefGPtr(ptr);
79    }
80
81    T* leakRef() WARN_UNUSED_RETURN
82    {
83        T* ptr = m_ptr;
84        m_ptr = 0;
85        return ptr;
86    }
87
88    T*& outPtr()
89    {
90        ASSERT(!m_ptr);
91        return m_ptr;
92    }
93
94    // Hash table deleted values, which are only constructed and never copied or destroyed.
95    GRefPtr(HashTableDeletedValueType) : m_ptr(hashTableDeletedValue()) { }
96    bool isHashTableDeletedValue() const { return m_ptr == hashTableDeletedValue(); }
97
98    T* get() const { return m_ptr; }
99    T& operator*() const { return *m_ptr; }
100    ALWAYS_INLINE T* operator->() const { return m_ptr; }
101
102    bool operator!() const { return !m_ptr; }
103
104    // This conversion operator allows implicit conversion to bool but not to other integer types.
105    typedef T* GRefPtr::*UnspecifiedBoolType;
106    operator UnspecifiedBoolType() const { return m_ptr ? &GRefPtr::m_ptr : 0; }
107
108    GRefPtr& operator=(const GRefPtr&);
109    GRefPtr& operator=(T*);
110    template <typename U> GRefPtr& operator=(const GRefPtr<U>&);
111
112    void swap(GRefPtr&);
113    friend GRefPtr adoptGRef<T>(T*);
114
115private:
116    static T* hashTableDeletedValue() { return reinterpret_cast<T*>(-1); }
117    // Adopting constructor.
118    GRefPtr(T* ptr, GRefPtrAdoptType) : m_ptr(ptr) {}
119
120    T* m_ptr;
121};
122
123template <typename T> inline GRefPtr<T>& GRefPtr<T>::operator=(const GRefPtr<T>& o)
124{
125    T* optr = o.get();
126    if (optr)
127        refGPtr(optr);
128    T* ptr = m_ptr;
129    m_ptr = optr;
130    if (ptr)
131        derefGPtr(ptr);
132    return *this;
133}
134
135template <typename T> inline GRefPtr<T>& GRefPtr<T>::operator=(T* optr)
136{
137    T* ptr = m_ptr;
138    if (optr)
139        refGPtr(optr);
140    m_ptr = optr;
141    if (ptr)
142        derefGPtr(ptr);
143    return *this;
144}
145
146template <class T> inline void GRefPtr<T>::swap(GRefPtr<T>& o)
147{
148    std::swap(m_ptr, o.m_ptr);
149}
150
151template <class T> inline void swap(GRefPtr<T>& a, GRefPtr<T>& b)
152{
153    a.swap(b);
154}
155
156template <typename T, typename U> inline bool operator==(const GRefPtr<T>& a, const GRefPtr<U>& b)
157{
158    return a.get() == b.get();
159}
160
161template <typename T, typename U> inline bool operator==(const GRefPtr<T>& a, U* b)
162{
163    return a.get() == b;
164}
165
166template <typename T, typename U> inline bool operator==(T* a, const GRefPtr<U>& b)
167{
168    return a == b.get();
169}
170
171template <typename T, typename U> inline bool operator!=(const GRefPtr<T>& a, const GRefPtr<U>& b)
172{
173    return a.get() != b.get();
174}
175
176template <typename T, typename U> inline bool operator!=(const GRefPtr<T>& a, U* b)
177{
178    return a.get() != b;
179}
180
181template <typename T, typename U> inline bool operator!=(T* a, const GRefPtr<U>& b)
182{
183    return a != b.get();
184}
185
186template <typename T, typename U> inline GRefPtr<T> static_pointer_cast(const GRefPtr<U>& p)
187{
188    return GRefPtr<T>(static_cast<T*>(p.get()));
189}
190
191template <typename T, typename U> inline GRefPtr<T> const_pointer_cast(const GRefPtr<U>& p)
192{
193    return GRefPtr<T>(const_cast<T*>(p.get()));
194}
195
196template <typename T> inline T* getPtr(const GRefPtr<T>& p)
197{
198    return p.get();
199}
200
201template <typename T> GRefPtr<T> adoptGRef(T* p)
202{
203    return GRefPtr<T>(p, GRefPtrAdopt);
204}
205
206template <> WTF_EXPORT_PRIVATE GHashTable* refGPtr(GHashTable* ptr);
207template <> WTF_EXPORT_PRIVATE void derefGPtr(GHashTable* ptr);
208template <> WTF_EXPORT_PRIVATE GMainContext* refGPtr(GMainContext* ptr);
209template <> WTF_EXPORT_PRIVATE void derefGPtr(GMainContext* ptr);
210template <> WTF_EXPORT_PRIVATE GMainLoop* refGPtr(GMainLoop* ptr);
211template <> WTF_EXPORT_PRIVATE void derefGPtr(GMainLoop* ptr);
212template <> WTF_EXPORT_PRIVATE GVariant* refGPtr(GVariant* ptr);
213template <> WTF_EXPORT_PRIVATE void derefGPtr(GVariant* ptr);
214template <> WTF_EXPORT_PRIVATE GSource* refGPtr(GSource* ptr);
215template <> WTF_EXPORT_PRIVATE void derefGPtr(GSource* ptr);
216template <> WTF_EXPORT_PRIVATE GPtrArray* refGPtr(GPtrArray*);
217template <> WTF_EXPORT_PRIVATE void derefGPtr(GPtrArray*);
218template <> WTF_EXPORT_PRIVATE GByteArray* refGPtr(GByteArray*);
219template <> WTF_EXPORT_PRIVATE void derefGPtr(GByteArray*);
220template <> WTF_EXPORT_PRIVATE GBytes* refGPtr(GBytes*);
221template <> WTF_EXPORT_PRIVATE void derefGPtr(GBytes*);
222template <> WTF_EXPORT_PRIVATE GClosure* refGPtr(GClosure*);
223template <> WTF_EXPORT_PRIVATE void derefGPtr(GClosure*);
224
225template <typename T> inline T* refGPtr(T* ptr)
226{
227    if (ptr)
228        g_object_ref_sink(ptr);
229    return ptr;
230}
231
232template <typename T> inline void derefGPtr(T* ptr)
233{
234    if (ptr)
235        g_object_unref(ptr);
236}
237
238} // namespace WTF
239
240using WTF::GRefPtr;
241using WTF::adoptGRef;
242
243#endif // USE(GLIB)
244
245#endif // WTF_GRefPtr_h
246