1 /*
2  *  Copyright (C) 2005, 2006, 2007 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 WTF_PassRefPtr_h
22 #define WTF_PassRefPtr_h
23 
24 #include "AlwaysInline.h"
25 
26 namespace WTF {
27 
28     template<typename T> class RefPtr;
29     template<typename T> class PassRefPtr;
30     template <typename T> PassRefPtr<T> adoptRef(T*);
31 
32     // Remove inline for winscw compiler to prevent the compiler agressively resolving
33     // T::deref(), which will fail compiling when PassRefPtr<T> is used as class member
34     // or function arguments before T is defined.
35     template<typename T>
36 #if !COMPILER(WINSCW)
37     inline
38 #endif
derefIfNotNull(T * ptr)39     void derefIfNotNull(T* ptr)
40     {
41         if (UNLIKELY(ptr != 0))
42             ptr->deref();
43     }
44 
45     template<typename T> class PassRefPtr {
46     public:
PassRefPtr()47         PassRefPtr() : m_ptr(0) {}
PassRefPtr(T * ptr)48         PassRefPtr(T* ptr) : m_ptr(ptr) { if (ptr) ptr->ref(); }
49         // It somewhat breaks the type system to allow transfer of ownership out of
50         // a const PassRefPtr. However, it makes it much easier to work with PassRefPtr
51         // temporaries, and we don't really have a need to use real const PassRefPtrs
52         // anyway.
PassRefPtr(const PassRefPtr & o)53         PassRefPtr(const PassRefPtr& o) : m_ptr(o.releaseRef()) {}
PassRefPtr(const PassRefPtr<U> & o)54         template <typename U> PassRefPtr(const PassRefPtr<U>& o) : m_ptr(o.releaseRef()) { }
55 
~PassRefPtr()56         ALWAYS_INLINE ~PassRefPtr() { derefIfNotNull<T>(m_ptr); }
57 
58         template <class U>
PassRefPtr(const RefPtr<U> & o)59         PassRefPtr(const RefPtr<U>& o) : m_ptr(o.get()) { if (T* ptr = m_ptr) ptr->ref(); }
60 
get()61         T* get() const { return m_ptr; }
62 
clear()63         void clear() { if (T* ptr = m_ptr) ptr->deref(); m_ptr = 0; }
releaseRef()64         T* releaseRef() const { T* tmp = m_ptr; m_ptr = 0; return tmp; }
65 
66         T& operator*() const { return *m_ptr; }
67         T* operator->() const { return m_ptr; }
68 
69         bool operator!() const { return !m_ptr; }
70 
71         // This conversion operator allows implicit conversion to bool but not to other integer types.
72         typedef T* (PassRefPtr::*UnspecifiedBoolType);
UnspecifiedBoolType()73         operator UnspecifiedBoolType() const { return m_ptr ? &PassRefPtr::m_ptr : 0; }
74 
75         PassRefPtr& operator=(T*);
76         PassRefPtr& operator=(const PassRefPtr&);
77         template <typename U> PassRefPtr& operator=(const PassRefPtr<U>&);
78         template <typename U> PassRefPtr& operator=(const RefPtr<U>&);
79 
80         friend PassRefPtr adoptRef<T>(T*);
81     private:
82         // adopting constructor
PassRefPtr(T * ptr,bool)83         PassRefPtr(T* ptr, bool) : m_ptr(ptr) {}
84         mutable T* m_ptr;
85     };
86 
87     // NonNullPassRefPtr: Optimized for passing non-null pointers. A NonNullPassRefPtr
88     // begins life non-null, and can only become null through a call to releaseRef()
89     // or clear().
90 
91     // FIXME: NonNullPassRefPtr could just inherit from PassRefPtr. However,
92     // if we use inheritance, GCC's optimizer fails to realize that destruction
93     // of a released NonNullPassRefPtr is a no-op. So, for now, just copy the
94     // most important code from PassRefPtr.
95     template <typename T> class NonNullPassRefPtr {
96     public:
NonNullPassRefPtr(T * ptr)97         NonNullPassRefPtr(T* ptr)
98             : m_ptr(ptr)
99         {
100             ASSERT(m_ptr);
101             m_ptr->ref();
102         }
103 
NonNullPassRefPtr(const RefPtr<U> & o)104         template <class U> NonNullPassRefPtr(const RefPtr<U>& o)
105             : m_ptr(o.get())
106         {
107             ASSERT(m_ptr);
108             m_ptr->ref();
109         }
110 
NonNullPassRefPtr(const NonNullPassRefPtr & o)111         NonNullPassRefPtr(const NonNullPassRefPtr& o)
112             : m_ptr(o.releaseRef())
113         {
114             ASSERT(m_ptr);
115         }
116 
NonNullPassRefPtr(const NonNullPassRefPtr<U> & o)117         template <class U> NonNullPassRefPtr(const NonNullPassRefPtr<U>& o)
118             : m_ptr(o.releaseRef())
119         {
120             ASSERT(m_ptr);
121         }
122 
NonNullPassRefPtr(const PassRefPtr<U> & o)123         template <class U> NonNullPassRefPtr(const PassRefPtr<U>& o)
124             : m_ptr(o.releaseRef())
125         {
126             ASSERT(m_ptr);
127         }
128 
~NonNullPassRefPtr()129         ALWAYS_INLINE ~NonNullPassRefPtr() { derefIfNotNull(m_ptr); }
130 
get()131         T* get() const { return m_ptr; }
132 
clear()133         void clear() { derefIfNotNull(m_ptr); m_ptr = 0; }
releaseRef()134         T* releaseRef() const { T* tmp = m_ptr; m_ptr = 0; return tmp; }
135 
136         T& operator*() const { return *m_ptr; }
137         T* operator->() const { return m_ptr; }
138 
139     private:
140         mutable T* m_ptr;
141     };
142 
143     template <typename T> template <typename U> inline PassRefPtr<T>& PassRefPtr<T>::operator=(const RefPtr<U>& o)
144     {
145         T* optr = o.get();
146         if (optr)
147             optr->ref();
148         T* ptr = m_ptr;
149         m_ptr = optr;
150         if (ptr)
151             ptr->deref();
152         return *this;
153     }
154 
155     template <typename T> inline PassRefPtr<T>& PassRefPtr<T>::operator=(T* optr)
156     {
157         if (optr)
158             optr->ref();
159         T* ptr = m_ptr;
160         m_ptr = optr;
161         if (ptr)
162             ptr->deref();
163         return *this;
164     }
165 
166     template <typename T> inline PassRefPtr<T>& PassRefPtr<T>::operator=(const PassRefPtr<T>& ref)
167     {
168         T* ptr = m_ptr;
169         m_ptr = ref.releaseRef();
170         if (ptr)
171             ptr->deref();
172         return *this;
173     }
174 
175     template <typename T> template <typename U> inline PassRefPtr<T>& PassRefPtr<T>::operator=(const PassRefPtr<U>& ref)
176     {
177         T* ptr = m_ptr;
178         m_ptr = ref.releaseRef();
179         if (ptr)
180             ptr->deref();
181         return *this;
182     }
183 
184     template <typename T, typename U> inline bool operator==(const PassRefPtr<T>& a, const PassRefPtr<U>& b)
185     {
186         return a.get() == b.get();
187     }
188 
189     template <typename T, typename U> inline bool operator==(const PassRefPtr<T>& a, const RefPtr<U>& b)
190     {
191         return a.get() == b.get();
192     }
193 
194     template <typename T, typename U> inline bool operator==(const RefPtr<T>& a, const PassRefPtr<U>& b)
195     {
196         return a.get() == b.get();
197     }
198 
199     template <typename T, typename U> inline bool operator==(const PassRefPtr<T>& a, U* b)
200     {
201         return a.get() == b;
202     }
203 
204     template <typename T, typename U> inline bool operator==(T* a, const PassRefPtr<U>& b)
205     {
206         return a == b.get();
207     }
208 
209     template <typename T, typename U> inline bool operator!=(const PassRefPtr<T>& a, const PassRefPtr<U>& b)
210     {
211         return a.get() != b.get();
212     }
213 
214     template <typename T, typename U> inline bool operator!=(const PassRefPtr<T>& a, const RefPtr<U>& b)
215     {
216         return a.get() != b.get();
217     }
218 
219     template <typename T, typename U> inline bool operator!=(const RefPtr<T>& a, const PassRefPtr<U>& b)
220     {
221         return a.get() != b.get();
222     }
223 
224     template <typename T, typename U> inline bool operator!=(const PassRefPtr<T>& a, U* b)
225     {
226         return a.get() != b;
227     }
228 
229     template <typename T, typename U> inline bool operator!=(T* a, const PassRefPtr<U>& b)
230     {
231         return a != b.get();
232     }
233 
adoptRef(T * p)234     template <typename T> inline PassRefPtr<T> adoptRef(T* p)
235     {
236         return PassRefPtr<T>(p, true);
237     }
238 
static_pointer_cast(const PassRefPtr<U> & p)239     template <typename T, typename U> inline PassRefPtr<T> static_pointer_cast(const PassRefPtr<U>& p)
240     {
241         return adoptRef(static_cast<T*>(p.releaseRef()));
242     }
243 
const_pointer_cast(const PassRefPtr<U> & p)244     template <typename T, typename U> inline PassRefPtr<T> const_pointer_cast(const PassRefPtr<U>& p)
245     {
246         return adoptRef(const_cast<T*>(p.releaseRef()));
247     }
248 
getPtr(const PassRefPtr<T> & p)249     template <typename T> inline T* getPtr(const PassRefPtr<T>& p)
250     {
251         return p.get();
252     }
253 
254 } // namespace WTF
255 
256 using WTF::PassRefPtr;
257 using WTF::NonNullPassRefPtr;
258 using WTF::adoptRef;
259 using WTF::static_pointer_cast;
260 using WTF::const_pointer_cast;
261 
262 #endif // WTF_PassRefPtr_h
263