Remove home-brewed nullptr
[WebKit-https.git] / Source / WTF / wtf / RetainPtr.h
1 /*
2  *  Copyright (C) 2005, 2006, 2007, 2008, 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 RetainPtr_h
22 #define RetainPtr_h
23
24 #if USE(CF) || defined(__OBJC__)
25
26 #include <wtf/HashTraits.h>
27 #include <algorithm>
28 #include <cstddef>
29
30 #if USE(CF)
31 #include <CoreFoundation/CoreFoundation.h>
32 #endif
33
34 #ifdef __OBJC__
35 #import <Foundation/Foundation.h>
36 #endif
37
38 #ifndef CF_RELEASES_ARGUMENT
39 #define CF_RELEASES_ARGUMENT
40 #endif
41
42 #ifndef NS_RELEASES_ARGUMENT
43 #define NS_RELEASES_ARGUMENT
44 #endif
45
46 namespace WTF {
47
48     // Unlike most most of our smart pointers, RetainPtr can take either the pointer type or the pointed-to type,
49     // so both RetainPtr<NSDictionary> and RetainPtr<CFDictionaryRef> will work.
50
51 #if !PLATFORM(IOS)
52     #define AdoptCF DeprecatedAdoptCF
53     #define AdoptNS DeprecatedAdoptNS
54 #endif
55
56     enum AdoptCFTag { AdoptCF };
57     enum AdoptNSTag { AdoptNS };
58     
59 #if defined(__OBJC__) && !__has_feature(objc_arc)
60 #ifdef OBJC_NO_GC
61     inline void adoptNSReference(id)
62     {
63     }
64 #else
65     inline void adoptNSReference(id ptr)
66     {
67         if (ptr) {
68             CFRetain(ptr);
69             [ptr release];
70         }
71     }
72 #endif
73 #endif
74
75     template<typename T> class RetainPtr {
76     public:
77         typedef typename std::remove_pointer<T>::type ValueType;
78         typedef ValueType* PtrType;
79         typedef CFTypeRef StorageType;
80
81         RetainPtr() : m_ptr(0) {}
82         RetainPtr(PtrType ptr) : m_ptr(toStorageType(ptr)) { if (m_ptr) CFRetain(m_ptr); }
83
84         RetainPtr(AdoptCFTag, PtrType ptr)
85             : m_ptr(toStorageType(ptr))
86         {
87 #ifdef __OBJC__
88             static_assert((!std::is_convertible<T, id>::value), "Don't use adoptCF with Objective-C pointer types, use adoptNS.");
89 #endif
90         }
91
92 #if __has_feature(objc_arc)
93         RetainPtr(AdoptNSTag, PtrType ptr) : m_ptr(toStorageType(ptr)) { if (m_ptr) CFRetain(m_ptr); }
94 #else
95         RetainPtr(AdoptNSTag, PtrType ptr)
96             : m_ptr(toStorageType(ptr))
97         {
98             adoptNSReference(ptr);
99         }
100 #endif
101         
102         RetainPtr(const RetainPtr& o) : m_ptr(o.m_ptr) { if (StorageType ptr = m_ptr) CFRetain(ptr); }
103
104 #if COMPILER_SUPPORTS(CXX_RVALUE_REFERENCES)
105         RetainPtr(RetainPtr&& o) : m_ptr(toStorageType(o.leakRef())) { }
106         template<typename U> RetainPtr(RetainPtr<U>&& o) : m_ptr(toStorageType(o.leakRef())) { }
107 #endif
108
109         // Hash table deleted values, which are only constructed and never copied or destroyed.
110         RetainPtr(HashTableDeletedValueType) : m_ptr(hashTableDeletedValue()) { }
111         bool isHashTableDeletedValue() const { return m_ptr == hashTableDeletedValue(); }
112         
113         ~RetainPtr() { if (StorageType ptr = m_ptr) CFRelease(ptr); }
114         
115         template<typename U> RetainPtr(const RetainPtr<U>&);
116
117         void clear();
118         PtrType leakRef() WARN_UNUSED_RETURN;
119
120         PtrType get() const { return fromStorageType(m_ptr); }
121         PtrType operator->() const { return fromStorageType(m_ptr); }
122 #if COMPILER_SUPPORTS(CXX_EXPLICIT_CONVERSIONS)
123         explicit operator PtrType() const { return fromStorageType(m_ptr); }
124 #endif
125
126         bool operator!() const { return !m_ptr; }
127     
128         // This conversion operator allows implicit conversion to bool but not to other integer types.
129         typedef StorageType RetainPtr::*UnspecifiedBoolType;
130         operator UnspecifiedBoolType() const { return m_ptr ? &RetainPtr::m_ptr : 0; }
131         
132         RetainPtr& operator=(const RetainPtr&);
133         template<typename U> RetainPtr& operator=(const RetainPtr<U>&);
134         RetainPtr& operator=(PtrType);
135         template<typename U> RetainPtr& operator=(U*);
136
137 #if COMPILER_SUPPORTS(CXX_RVALUE_REFERENCES)
138         RetainPtr& operator=(RetainPtr&&);
139         template<typename U> RetainPtr& operator=(RetainPtr<U>&&);
140 #endif
141
142 #if !COMPILER_SUPPORTS(CXX_NULLPTR)
143         RetainPtr& operator=(std::nullptr_t) { clear(); return *this; }
144 #endif
145
146         void swap(RetainPtr&);
147
148     private:
149         static PtrType hashTableDeletedValue() { return reinterpret_cast<PtrType>(-1); }
150
151 #if defined (__OBJC__) && __has_feature(objc_arc)
152         template<typename U>
153         typename std::enable_if<std::is_convertible<U, id>::value, PtrType>::type
154         fromStorageTypeHelper(StorageType ptr) const
155         {
156             return (__bridge PtrType)ptr;
157         }
158
159         template<typename U>
160         typename std::enable_if<!std::is_convertible<U, id>::value, PtrType>::type
161         fromStorageTypeHelper(StorageType ptr) const
162         {
163             return (PtrType)ptr;
164         }
165
166         PtrType fromStorageType(StorageType ptr) const { return fromStorageTypeHelper<PtrType>(ptr); }
167         StorageType toStorageType(id ptr) const { return (__bridge StorageType)ptr; }
168         StorageType toStorageType(CFTypeRef ptr) const { return (StorageType)ptr; }
169 #else
170         PtrType fromStorageType(StorageType ptr) const { return (PtrType)ptr; }
171         StorageType toStorageType(PtrType ptr) const { return (StorageType)ptr; }
172 #endif
173
174         StorageType m_ptr;
175     };
176
177     template<typename T> template<typename U> inline RetainPtr<T>::RetainPtr(const RetainPtr<U>& o)
178         : m_ptr(toStorageType(o.get()))
179     {
180         if (StorageType ptr = m_ptr)
181             CFRetain(ptr);
182     }
183
184     template<typename T> inline void RetainPtr<T>::clear()
185     {
186         if (StorageType ptr = m_ptr) {
187             m_ptr = 0;
188             CFRelease(ptr);
189         }
190     }
191
192     template<typename T> inline typename RetainPtr<T>::PtrType RetainPtr<T>::leakRef()
193     {
194         PtrType ptr = fromStorageType(m_ptr);
195         m_ptr = 0;
196         return ptr;
197     }
198
199     template<typename T> inline RetainPtr<T>& RetainPtr<T>::operator=(const RetainPtr& o)
200     {
201         RetainPtr ptr = o;
202         swap(ptr);
203         return *this;
204     }
205
206     template<typename T> template<typename U> inline RetainPtr<T>& RetainPtr<T>::operator=(const RetainPtr<U>& o)
207     {
208         RetainPtr ptr = o;
209         swap(ptr);
210         return *this;
211     }
212
213     template<typename T> inline RetainPtr<T>& RetainPtr<T>::operator=(PtrType optr)
214     {
215         RetainPtr ptr = optr;
216         swap(ptr);
217         return *this;
218     }
219
220     template<typename T> template<typename U> inline RetainPtr<T>& RetainPtr<T>::operator=(U* optr)
221     {
222         RetainPtr ptr = optr;
223         swap(ptr);
224         return *this;
225     }
226
227 #if COMPILER_SUPPORTS(CXX_RVALUE_REFERENCES)
228
229     template<typename T> inline RetainPtr<T>& RetainPtr<T>::operator=(RetainPtr&& o)
230     {
231         RetainPtr ptr = std::move(o);
232         swap(ptr);
233         return *this;
234     }
235
236     template<typename T> template<typename U> inline RetainPtr<T>& RetainPtr<T>::operator=(RetainPtr<U>&& o)
237     {
238         RetainPtr ptr = std::move(o);
239         swap(ptr);
240         return *this;
241     }
242
243 #endif
244
245     template<typename T> inline void RetainPtr<T>::swap(RetainPtr& o)
246     {
247         std::swap(m_ptr, o.m_ptr);
248     }
249
250     template<typename T> inline void swap(RetainPtr<T>& a, RetainPtr<T>& b)
251     {
252         a.swap(b);
253     }
254
255     template<typename T, typename U> inline bool operator==(const RetainPtr<T>& a, const RetainPtr<U>& b)
256     { 
257         return a.get() == b.get(); 
258     }
259
260     template<typename T, typename U> inline bool operator==(const RetainPtr<T>& a, U* b)
261     {
262         return a.get() == b; 
263     }
264
265     template<typename T, typename U> inline bool operator==(T* a, const RetainPtr<U>& b) 
266     {
267         return a == b.get(); 
268     }
269
270     template<typename T, typename U> inline bool operator!=(const RetainPtr<T>& a, const RetainPtr<U>& b)
271     { 
272         return a.get() != b.get(); 
273     }
274
275     template<typename T, typename U> inline bool operator!=(const RetainPtr<T>& a, U* b)
276     {
277         return a.get() != b; 
278     }
279
280     template<typename T, typename U> inline bool operator!=(T* a, const RetainPtr<U>& b)
281     { 
282         return a != b.get(); 
283     }
284
285     template<typename T> inline RetainPtr<T> adoptCF(T CF_RELEASES_ARGUMENT) WARN_UNUSED_RETURN;
286     template<typename T> inline RetainPtr<T> adoptCF(T CF_RELEASES_ARGUMENT o)
287     {
288         return RetainPtr<T>(AdoptCF, o);
289     }
290
291     template<typename T> inline RetainPtr<T> adoptNS(T NS_RELEASES_ARGUMENT) WARN_UNUSED_RETURN;
292     template<typename T> inline RetainPtr<T> adoptNS(T NS_RELEASES_ARGUMENT o)
293     {
294         return RetainPtr<T>(AdoptNS, o);
295     }
296
297     // Helper function for creating a RetainPtr using template argument deduction.
298     template<typename T> inline RetainPtr<T> retainPtr(T) WARN_UNUSED_RETURN;
299     template<typename T> inline RetainPtr<T> retainPtr(T o)
300     {
301         return o;
302     }
303
304     template<typename P> struct HashTraits<RetainPtr<P> > : SimpleClassHashTraits<RetainPtr<P> > { };
305     
306     template<typename P> struct PtrHash<RetainPtr<P> > : PtrHash<typename RetainPtr<P>::PtrType> {
307         using PtrHash<typename RetainPtr<P>::PtrType>::hash;
308         static unsigned hash(const RetainPtr<P>& key) { return hash(key.get()); }
309         using PtrHash<typename RetainPtr<P>::PtrType>::equal;
310         static bool equal(const RetainPtr<P>& a, const RetainPtr<P>& b) { return a == b; }
311         static bool equal(typename RetainPtr<P>::PtrType a, const RetainPtr<P>& b) { return a == b; }
312         static bool equal(const RetainPtr<P>& a, typename RetainPtr<P>::PtrType b) { return a == b; }
313     };
314     
315     template<typename P> struct DefaultHash<RetainPtr<P> > { typedef PtrHash<RetainPtr<P> > Hash; };
316
317     template <typename P>
318     struct RetainPtrObjectHashTraits : SimpleClassHashTraits<RetainPtr<P> > {
319         static const RetainPtr<P>& emptyValue()
320         {
321             static RetainPtr<P>& null = *(new RetainPtr<P>);
322             return null;
323         }
324     };
325
326     template <typename P>
327     struct RetainPtrObjectHash {
328         static unsigned hash(const RetainPtr<P>& o)
329         {
330             ASSERT_WITH_MESSAGE(o.get(), "attempt to use null RetainPtr in HashTable");
331             return static_cast<unsigned>(CFHash(o.get()));
332         }
333         static bool equal(const RetainPtr<P>& a, const RetainPtr<P>& b)
334         {
335             return CFEqual(a.get(), b.get());
336         }
337         static const bool safeToCompareToEmptyOrDeleted = false;
338     };
339
340 #if !PLATFORM(IOS)
341     #undef AdoptCF
342     #undef AdoptNS
343 #endif
344
345 } // namespace WTF
346
347 using WTF::RetainPtr;
348 using WTF::adoptCF;
349 using WTF::adoptNS;
350 using WTF::retainPtr;
351
352 #if PLATFORM(IOS)
353 using WTF::AdoptCF;
354 using WTF::AdoptNS;
355 #endif
356
357 #endif // USE(CF) || defined(__OBJC__)
358
359 #endif // WTF_RetainPtr_h