/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef CFTypeRefPtr_h #define CFTypeRefPtr_h #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" #include "mozilla/DbgMacro.h" #include "mozilla/HashFunctions.h" // A smart pointer for CoreFoundation classes which does reference counting. // // Manual reference counting: // // UInt32 someNumber = 10; // CFNumberRef numberObject = // CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &someNumber); // // do something with numberObject // CFRelease(numberObject); // // Automatic reference counting using CFTypeRefPtr: // // UInt32 someNumber = 10; // auto numberObject = // CFTypeRefPtr::WrapUnderCreateRule( // CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &someNumber)); // // do something with numberObject // // no CFRelease template class CFTypeRefPtr { private: void assign_with_CFRetain(PtrT aRawPtr) { CFRetain(aRawPtr); assign_assuming_CFRetain(aRawPtr); } void assign_assuming_CFRetain(PtrT aNewPtr) { PtrT oldPtr = mRawPtr; mRawPtr = aNewPtr; if (oldPtr) { CFRelease(oldPtr); } } private: PtrT mRawPtr; public: ~CFTypeRefPtr() { if (mRawPtr) { CFRelease(mRawPtr); } } // Constructors CFTypeRefPtr() : mRawPtr(nullptr) {} CFTypeRefPtr(const CFTypeRefPtr& aSmartPtr) : mRawPtr(aSmartPtr.mRawPtr) { if (mRawPtr) { CFRetain(mRawPtr); } } CFTypeRefPtr(CFTypeRefPtr&& aRefPtr) : mRawPtr(aRefPtr.mRawPtr) { aRefPtr.mRawPtr = nullptr; } MOZ_IMPLICIT CFTypeRefPtr(decltype(nullptr)) : mRawPtr(nullptr) {} // There is no constructor from a raw pointer value. // Use one of the static WrapUnder*Rule methods below instead. static CFTypeRefPtr WrapUnderCreateRule(PtrT aRawPtr) { CFTypeRefPtr ptr; ptr.AssignUnderCreateRule(aRawPtr); return ptr; } static CFTypeRefPtr WrapUnderGetRule(PtrT aRawPtr) { CFTypeRefPtr ptr; ptr.AssignUnderGetRule(aRawPtr); return ptr; } // Assignment operators CFTypeRefPtr& operator=(decltype(nullptr)) { assign_assuming_CFRetain(nullptr); return *this; } CFTypeRefPtr& operator=(const CFTypeRefPtr& aRhs) { assign_with_CFRetain(aRhs.mRawPtr); return *this; } CFTypeRefPtr& operator=(CFTypeRefPtr&& aRefPtr) { assign_assuming_CFRetain(aRefPtr.mRawPtr); aRefPtr.mRawPtr = nullptr; return *this; } // There is no operator= for a raw pointer value. // Use one of the AssignUnder*Rule methods below instead. CFTypeRefPtr& AssignUnderCreateRule(PtrT aRawPtr) { // Freshly-created objects come with a retain count of 1. assign_assuming_CFRetain(aRawPtr); return *this; } CFTypeRefPtr& AssignUnderGetRule(PtrT aRawPtr) { assign_with_CFRetain(aRawPtr); return *this; } // Other pointer operators // This is the only way to get the raw pointer out of the smart pointer. // There is no implicit conversion to a raw pointer. PtrT get() const { return mRawPtr; } // Don't allow implicit conversion of temporary CFTypeRefPtr to raw pointer, // because the refcount might be one and the pointer will immediately become // invalid. operator PtrT() const&& = delete; // Also don't allow implicit conversion of non-temporary CFTypeRefPtr. operator PtrT() const& = delete; // These let you null-check a pointer without calling get(). explicit operator bool() const { return !!mRawPtr; } }; template inline bool operator==(const CFTypeRefPtr& aLhs, const CFTypeRefPtr& aRhs) { return aLhs.get() == aRhs.get(); } template inline bool operator!=(const CFTypeRefPtr& aLhs, const CFTypeRefPtr& aRhs) { return !(aLhs == aRhs); } // Comparing an |CFTypeRefPtr| to |nullptr| template inline bool operator==(const CFTypeRefPtr& aLhs, decltype(nullptr)) { return aLhs.get() == nullptr; } template inline bool operator==(decltype(nullptr), const CFTypeRefPtr& aRhs) { return nullptr == aRhs.get(); } template inline bool operator!=(const CFTypeRefPtr& aLhs, decltype(nullptr)) { return aLhs.get() != nullptr; } template inline bool operator!=(decltype(nullptr), const CFTypeRefPtr& aRhs) { return nullptr != aRhs.get(); } // MOZ_DBG support template std::ostream& operator<<(std::ostream& aOut, const CFTypeRefPtr& aObj) { return mozilla::DebugValue(aOut, aObj.get()); } // std::hash support (e.g. for unordered_map) namespace std { template struct hash> { typedef CFTypeRefPtr argument_type; typedef std::size_t result_type; result_type operator()(argument_type const& aPtr) const { return mozilla::HashGeneric(reinterpret_cast(aPtr.get())); } }; } // namespace std #endif /* CFTypeRefPtr_h */