Home | History | Annotate | Download | only in wtf
      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