1 /* 2 * Copyright (C) 2005, 2006, 2007, 2008, 2010 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/HashTableDeletedValueType.h" 25 #include "wtf/HashTraits.h" 26 #include "wtf/NullPtr.h" 27 #include "wtf/TypeTraits.h" 28 #include <algorithm> 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 enum AdoptCFTag { AdoptCF }; 52 enum AdoptNSTag { AdoptNS }; 53 54 #ifdef __OBJC__ 55 inline void adoptNSReference(id ptr) 56 { 57 if (ptr) { 58 CFRetain(ptr); 59 [ptr release]; 60 } 61 } 62 #endif 63 64 template<typename T> class RetainPtr { 65 public: 66 typedef typename RemovePointer<T>::Type ValueType; 67 typedef ValueType* PtrType; 68 69 RetainPtr() : m_ptr(0) {} 70 RetainPtr(PtrType ptr) : m_ptr(ptr) { if (ptr) CFRetain(ptr); } 71 72 RetainPtr(AdoptCFTag, PtrType ptr) : m_ptr(ptr) { } 73 RetainPtr(AdoptNSTag, PtrType ptr) : m_ptr(ptr) { adoptNSReference(ptr); } 74 75 RetainPtr(const RetainPtr& o) : m_ptr(o.m_ptr) { if (PtrType ptr = m_ptr) CFRetain(ptr); } 76 77 #if COMPILER_SUPPORTS(CXX_RVALUE_REFERENCES) 78 RetainPtr(RetainPtr&& o) : m_ptr(o.leakRef()) { } 79 #endif 80 81 // Hash table deleted values, which are only constructed and never copied or destroyed. 82 RetainPtr(HashTableDeletedValueType) : m_ptr(hashTableDeletedValue()) { } 83 bool isHashTableDeletedValue() const { return m_ptr == hashTableDeletedValue(); } 84 85 ~RetainPtr() { if (PtrType ptr = m_ptr) CFRelease(ptr); } 86 87 template<typename U> RetainPtr(const RetainPtr<U>&); 88 89 void clear(); 90 PtrType leakRef() WARN_UNUSED_RETURN; 91 92 PtrType get() const { return m_ptr; } 93 PtrType operator->() const { return m_ptr; } 94 #if COMPILER_SUPPORTS(CXX_EXPLICIT_CONVERSIONS) 95 explicit operator PtrType() const { return m_ptr; } 96 #endif 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 PtrType RetainPtr::*UnspecifiedBoolType; 102 operator UnspecifiedBoolType() const { return m_ptr ? &RetainPtr::m_ptr : 0; } 103 104 RetainPtr& operator=(const RetainPtr&); 105 template<typename U> RetainPtr& operator=(const RetainPtr<U>&); 106 RetainPtr& operator=(PtrType); 107 template<typename U> RetainPtr& operator=(U*); 108 109 #if COMPILER_SUPPORTS(CXX_RVALUE_REFERENCES) 110 RetainPtr& operator=(RetainPtr&&); 111 template<typename U> RetainPtr& operator=(RetainPtr<U>&&); 112 #endif 113 114 #if !COMPILER_SUPPORTS(CXX_NULLPTR) 115 RetainPtr& operator=(std::nullptr_t) { clear(); return *this; } 116 #endif 117 118 void adoptCF(PtrType); 119 void adoptNS(PtrType); 120 121 void swap(RetainPtr&); 122 123 private: 124 static PtrType hashTableDeletedValue() { return reinterpret_cast<PtrType>(-1); } 125 126 PtrType m_ptr; 127 }; 128 129 template<typename T> template<typename U> inline RetainPtr<T>::RetainPtr(const RetainPtr<U>& o) 130 : m_ptr(o.get()) 131 { 132 if (PtrType ptr = m_ptr) 133 CFRetain(ptr); 134 } 135 136 template<typename T> inline void RetainPtr<T>::clear() 137 { 138 if (PtrType ptr = m_ptr) { 139 m_ptr = 0; 140 CFRelease(ptr); 141 } 142 } 143 144 template<typename T> inline typename RetainPtr<T>::PtrType RetainPtr<T>::leakRef() 145 { 146 PtrType ptr = m_ptr; 147 m_ptr = 0; 148 return ptr; 149 } 150 151 template<typename T> inline RetainPtr<T>& RetainPtr<T>::operator=(const RetainPtr<T>& o) 152 { 153 PtrType optr = o.get(); 154 if (optr) 155 CFRetain(optr); 156 PtrType ptr = m_ptr; 157 m_ptr = optr; 158 if (ptr) 159 CFRelease(ptr); 160 return *this; 161 } 162 163 template<typename T> template<typename U> inline RetainPtr<T>& RetainPtr<T>::operator=(const RetainPtr<U>& o) 164 { 165 PtrType optr = o.get(); 166 if (optr) 167 CFRetain(optr); 168 PtrType ptr = m_ptr; 169 m_ptr = optr; 170 if (ptr) 171 CFRelease(ptr); 172 return *this; 173 } 174 175 template<typename T> inline RetainPtr<T>& RetainPtr<T>::operator=(PtrType optr) 176 { 177 if (optr) 178 CFRetain(optr); 179 PtrType ptr = m_ptr; 180 m_ptr = optr; 181 if (ptr) 182 CFRelease(ptr); 183 return *this; 184 } 185 186 template<typename T> template<typename U> inline RetainPtr<T>& RetainPtr<T>::operator=(U* optr) 187 { 188 if (optr) 189 CFRetain(optr); 190 PtrType ptr = m_ptr; 191 m_ptr = optr; 192 if (ptr) 193 CFRelease(ptr); 194 return *this; 195 } 196 197 #if COMPILER_SUPPORTS(CXX_RVALUE_REFERENCES) 198 template<typename T> inline RetainPtr<T>& RetainPtr<T>::operator=(RetainPtr<T>&& o) 199 { 200 adoptCF(o.leakRef()); 201 return *this; 202 } 203 204 template<typename T> template<typename U> inline RetainPtr<T>& RetainPtr<T>::operator=(RetainPtr<U>&& o) 205 { 206 adoptCF(o.leakRef()); 207 return *this; 208 } 209 #endif 210 211 template<typename T> inline void RetainPtr<T>::adoptCF(PtrType optr) 212 { 213 PtrType ptr = m_ptr; 214 m_ptr = optr; 215 if (ptr) 216 CFRelease(ptr); 217 } 218 219 template<typename T> inline void RetainPtr<T>::adoptNS(PtrType optr) 220 { 221 adoptNSReference(optr); 222 223 PtrType ptr = m_ptr; 224 m_ptr = optr; 225 if (ptr) 226 CFRelease(ptr); 227 } 228 229 template<typename T> inline void RetainPtr<T>::swap(RetainPtr<T>& o) 230 { 231 std::swap(m_ptr, o.m_ptr); 232 } 233 234 template<typename T> inline void swap(RetainPtr<T>& a, RetainPtr<T>& b) 235 { 236 a.swap(b); 237 } 238 239 template<typename T, typename U> inline bool operator==(const RetainPtr<T>& a, const RetainPtr<U>& b) 240 { 241 return a.get() == b.get(); 242 } 243 244 template<typename T, typename U> inline bool operator==(const RetainPtr<T>& a, U* b) 245 { 246 return a.get() == b; 247 } 248 249 template<typename T, typename U> inline bool operator==(T* a, const RetainPtr<U>& b) 250 { 251 return a == b.get(); 252 } 253 254 template<typename T, typename U> inline bool operator!=(const RetainPtr<T>& a, const RetainPtr<U>& b) 255 { 256 return a.get() != b.get(); 257 } 258 259 template<typename T, typename U> inline bool operator!=(const RetainPtr<T>& a, U* b) 260 { 261 return a.get() != b; 262 } 263 264 template<typename T, typename U> inline bool operator!=(T* a, const RetainPtr<U>& b) 265 { 266 return a != b.get(); 267 } 268 269 template<typename T> inline RetainPtr<T> adoptCF(T CF_RELEASES_ARGUMENT) WARN_UNUSED_RETURN; 270 template<typename T> inline RetainPtr<T> adoptCF(T o) 271 { 272 return RetainPtr<T>(AdoptCF, o); 273 } 274 275 template<typename T> inline RetainPtr<T> adoptNS(T NS_RELEASES_ARGUMENT) WARN_UNUSED_RETURN; 276 template<typename T> inline RetainPtr<T> adoptNS(T o) 277 { 278 return RetainPtr<T>(AdoptNS, o); 279 } 280 281 // Helper function for creating a RetainPtr using template argument deduction. 282 template<typename T> inline RetainPtr<T> retainPtr(T) WARN_UNUSED_RETURN; 283 template<typename T> inline RetainPtr<T> retainPtr(T o) 284 { 285 return RetainPtr<T>(o); 286 } 287 288 template<typename P> struct HashTraits<RetainPtr<P> > : SimpleClassHashTraits<RetainPtr<P> > { }; 289 290 template<typename P> struct PtrHash<RetainPtr<P> > : PtrHash<typename RetainPtr<P>::PtrType> { 291 using PtrHash<typename RetainPtr<P>::PtrType>::hash; 292 static unsigned hash(const RetainPtr<P>& key) { return hash(key.get()); } 293 using PtrHash<typename RetainPtr<P>::PtrType>::equal; 294 static bool equal(const RetainPtr<P>& a, const RetainPtr<P>& b) { return a == b; } 295 static bool equal(typename RetainPtr<P>::PtrType a, const RetainPtr<P>& b) { return a == b; } 296 static bool equal(const RetainPtr<P>& a, typename RetainPtr<P>::PtrType b) { return a == b; } 297 }; 298 299 template<typename P> struct DefaultHash<RetainPtr<P> > { typedef PtrHash<RetainPtr<P> > Hash; }; 300 } // namespace WTF 301 302 using WTF::AdoptCF; 303 using WTF::AdoptNS; 304 using WTF::adoptCF; 305 using WTF::adoptNS; 306 using WTF::RetainPtr; 307 using WTF::retainPtr; 308 309 #endif // WTF_RetainPtr_h 310