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 "HashTraits.h"
     25 #include "NullPtr.h"
     26 #include "TypeTraits.h"
     27 #include <algorithm>
     28 
     29 #if USE(CF)
     30 #include <CoreFoundation/CoreFoundation.h>
     31 #endif
     32 
     33 #ifdef __OBJC__
     34 #import <Foundation/Foundation.h>
     35 #endif
     36 
     37 namespace WTF {
     38 
     39     // Unlike most most of our smart pointers, RetainPtr can take either the pointer type or the pointed-to type,
     40     // so both RetainPtr<NSDictionary> and RetainPtr<CFDictionaryRef> will work.
     41 
     42     enum AdoptCFTag { AdoptCF };
     43     enum AdoptNSTag { AdoptNS };
     44 
     45 #ifdef __OBJC__
     46     inline void adoptNSReference(id ptr)
     47     {
     48         if (ptr) {
     49             CFRetain(ptr);
     50             [ptr release];
     51         }
     52     }
     53 #endif
     54 
     55     template<typename T> class RetainPtr {
     56     public:
     57         typedef typename RemovePointer<T>::Type ValueType;
     58         typedef ValueType* PtrType;
     59 
     60         RetainPtr() : m_ptr(0) {}
     61         RetainPtr(PtrType ptr) : m_ptr(ptr) { if (ptr) CFRetain(ptr); }
     62 
     63         RetainPtr(AdoptCFTag, PtrType ptr) : m_ptr(ptr) { }
     64         RetainPtr(AdoptNSTag, PtrType ptr) : m_ptr(ptr) { adoptNSReference(ptr); }
     65 
     66         RetainPtr(const RetainPtr& o) : m_ptr(o.m_ptr) { if (PtrType ptr = m_ptr) CFRetain(ptr); }
     67 
     68         // Hash table deleted values, which are only constructed and never copied or destroyed.
     69         RetainPtr(HashTableDeletedValueType) : m_ptr(hashTableDeletedValue()) { }
     70         bool isHashTableDeletedValue() const { return m_ptr == hashTableDeletedValue(); }
     71 
     72         ~RetainPtr() { if (PtrType ptr = m_ptr) CFRelease(ptr); }
     73 
     74         template<typename U> RetainPtr(const RetainPtr<U>&);
     75 
     76         PtrType get() const { return m_ptr; }
     77 
     78         void clear();
     79         PtrType leakRef() WARN_UNUSED_RETURN;
     80 
     81         PtrType operator->() const { return m_ptr; }
     82 
     83         bool operator!() const { return !m_ptr; }
     84 
     85         // This conversion operator allows implicit conversion to bool but not to other integer types.
     86         typedef PtrType RetainPtr::*UnspecifiedBoolType;
     87         operator UnspecifiedBoolType() const { return m_ptr ? &RetainPtr::m_ptr : 0; }
     88 
     89         RetainPtr& operator=(const RetainPtr&);
     90         template<typename U> RetainPtr& operator=(const RetainPtr<U>&);
     91         RetainPtr& operator=(PtrType);
     92         template<typename U> RetainPtr& operator=(U*);
     93 #if !HAVE(NULLPTR)
     94         RetainPtr& operator=(std::nullptr_t) { clear(); return *this; }
     95 #endif
     96 
     97         void adoptCF(PtrType);
     98         void adoptNS(PtrType);
     99 
    100         void swap(RetainPtr&);
    101 
    102         // FIXME: Remove releaseRef once we change all callers to call leakRef instead.
    103         PtrType releaseRef() { return leakRef(); }
    104 
    105     private:
    106         static T* hashTableDeletedValue() { return reinterpret_cast<T*>(-1); }
    107 
    108         PtrType m_ptr;
    109     };
    110 
    111     template<typename T> template<typename U> inline RetainPtr<T>::RetainPtr(const RetainPtr<U>& o)
    112         : m_ptr(o.get())
    113     {
    114         if (PtrType ptr = m_ptr)
    115             CFRetain(ptr);
    116     }
    117 
    118     template<typename T> inline void RetainPtr<T>::clear()
    119     {
    120         if (PtrType ptr = m_ptr) {
    121             m_ptr = 0;
    122             CFRelease(ptr);
    123         }
    124     }
    125 
    126     template<typename T> inline typename RetainPtr<T>::PtrType RetainPtr<T>::leakRef()
    127     {
    128         PtrType ptr = m_ptr;
    129         m_ptr = 0;
    130         return ptr;
    131     }
    132 
    133     template<typename T> inline RetainPtr<T>& RetainPtr<T>::operator=(const RetainPtr<T>& o)
    134     {
    135         PtrType optr = o.get();
    136         if (optr)
    137             CFRetain(optr);
    138         PtrType ptr = m_ptr;
    139         m_ptr = optr;
    140         if (ptr)
    141             CFRelease(ptr);
    142         return *this;
    143     }
    144 
    145     template<typename T> template<typename U> inline RetainPtr<T>& RetainPtr<T>::operator=(const RetainPtr<U>& o)
    146     {
    147         PtrType optr = o.get();
    148         if (optr)
    149             CFRetain(optr);
    150         PtrType ptr = m_ptr;
    151         m_ptr = optr;
    152         if (ptr)
    153             CFRelease(ptr);
    154         return *this;
    155     }
    156 
    157     template<typename T> inline RetainPtr<T>& RetainPtr<T>::operator=(PtrType optr)
    158     {
    159         if (optr)
    160             CFRetain(optr);
    161         PtrType ptr = m_ptr;
    162         m_ptr = optr;
    163         if (ptr)
    164             CFRelease(ptr);
    165         return *this;
    166     }
    167 
    168     template<typename T> inline void RetainPtr<T>::adoptCF(PtrType optr)
    169     {
    170         PtrType ptr = m_ptr;
    171         m_ptr = optr;
    172         if (ptr)
    173             CFRelease(ptr);
    174     }
    175 
    176     template<typename T> inline void RetainPtr<T>::adoptNS(PtrType optr)
    177     {
    178         adoptNSReference(optr);
    179 
    180         PtrType ptr = m_ptr;
    181         m_ptr = optr;
    182         if (ptr)
    183             CFRelease(ptr);
    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     template<typename T> inline void RetainPtr<T>::swap(RetainPtr<T>& o)
    198     {
    199         std::swap(m_ptr, o.m_ptr);
    200     }
    201 
    202     template<typename T> inline void swap(RetainPtr<T>& a, RetainPtr<T>& b)
    203     {
    204         a.swap(b);
    205     }
    206 
    207     template<typename T, typename U> inline bool operator==(const RetainPtr<T>& a, const RetainPtr<U>& b)
    208     {
    209         return a.get() == b.get();
    210     }
    211 
    212     template<typename T, typename U> inline bool operator==(const RetainPtr<T>& a, U* b)
    213     {
    214         return a.get() == b;
    215     }
    216 
    217     template<typename T, typename U> inline bool operator==(T* a, const RetainPtr<U>& b)
    218     {
    219         return a == b.get();
    220     }
    221 
    222     template<typename T, typename U> inline bool operator!=(const RetainPtr<T>& a, const RetainPtr<U>& b)
    223     {
    224         return a.get() != b.get();
    225     }
    226 
    227     template<typename T, typename U> inline bool operator!=(const RetainPtr<T>& a, U* b)
    228     {
    229         return a.get() != b;
    230     }
    231 
    232     template<typename T, typename U> inline bool operator!=(T* a, const RetainPtr<U>& b)
    233     {
    234         return a != b.get();
    235     }
    236 
    237     template<typename P> struct HashTraits<RetainPtr<P> > : SimpleClassHashTraits<RetainPtr<P> > { };
    238 
    239     template<typename P> struct PtrHash<RetainPtr<P> > : PtrHash<P*> {
    240         using PtrHash<P*>::hash;
    241         static unsigned hash(const RetainPtr<P>& key) { return hash(key.get()); }
    242         using PtrHash<P*>::equal;
    243         static bool equal(const RetainPtr<P>& a, const RetainPtr<P>& b) { return a == b; }
    244         static bool equal(P* a, const RetainPtr<P>& b) { return a == b; }
    245         static bool equal(const RetainPtr<P>& a, P* b) { return a == b; }
    246     };
    247 
    248     template<typename P> struct DefaultHash<RetainPtr<P> > { typedef PtrHash<RetainPtr<P> > Hash; };
    249 
    250 } // namespace WTF
    251 
    252 using WTF::AdoptCF;
    253 using WTF::AdoptNS;
    254 using WTF::RetainPtr;
    255 
    256 #endif // WTF_RetainPtr_h
    257