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