summaryrefslogtreecommitdiffstats
path: root/widget/cocoa/CFTypeRefPtr.h
diff options
context:
space:
mode:
Diffstat (limited to 'widget/cocoa/CFTypeRefPtr.h')
-rw-r--r--widget/cocoa/CFTypeRefPtr.h194
1 files changed, 194 insertions, 0 deletions
diff --git a/widget/cocoa/CFTypeRefPtr.h b/widget/cocoa/CFTypeRefPtr.h
new file mode 100644
index 0000000000..185355777e
--- /dev/null
+++ b/widget/cocoa/CFTypeRefPtr.h
@@ -0,0 +1,194 @@
+/* -*- 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<CFNumberRef>::WrapUnderCreateRule(
+// CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &someNumber));
+// // do something with numberObject
+// // no CFRelease
+
+template <class PtrT>
+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<PtrT>& aSmartPtr)
+ : mRawPtr(aSmartPtr.mRawPtr) {
+ if (mRawPtr) {
+ CFRetain(mRawPtr);
+ }
+ }
+
+ CFTypeRefPtr(CFTypeRefPtr<PtrT>&& 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<PtrT> WrapUnderCreateRule(PtrT aRawPtr) {
+ CFTypeRefPtr<PtrT> ptr;
+ ptr.AssignUnderCreateRule(aRawPtr);
+ return ptr;
+ }
+
+ static CFTypeRefPtr<PtrT> WrapUnderGetRule(PtrT aRawPtr) {
+ CFTypeRefPtr<PtrT> ptr;
+ ptr.AssignUnderGetRule(aRawPtr);
+ return ptr;
+ }
+
+ // Assignment operators
+
+ CFTypeRefPtr<PtrT>& operator=(decltype(nullptr)) {
+ assign_assuming_CFRetain(nullptr);
+ return *this;
+ }
+
+ CFTypeRefPtr<PtrT>& operator=(const CFTypeRefPtr<PtrT>& aRhs) {
+ assign_with_CFRetain(aRhs.mRawPtr);
+ return *this;
+ }
+
+ CFTypeRefPtr<PtrT>& operator=(CFTypeRefPtr<PtrT>&& 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<PtrT>& AssignUnderCreateRule(PtrT aRawPtr) {
+ // Freshly-created objects come with a retain count of 1.
+ assign_assuming_CFRetain(aRawPtr);
+ return *this;
+ }
+
+ CFTypeRefPtr<PtrT>& 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 <class PtrT>
+inline bool operator==(const CFTypeRefPtr<PtrT>& aLhs,
+ const CFTypeRefPtr<PtrT>& aRhs) {
+ return aLhs.get() == aRhs.get();
+}
+
+template <class PtrT>
+inline bool operator!=(const CFTypeRefPtr<PtrT>& aLhs,
+ const CFTypeRefPtr<PtrT>& aRhs) {
+ return !(aLhs == aRhs);
+}
+
+// Comparing an |CFTypeRefPtr| to |nullptr|
+
+template <class PtrT>
+inline bool operator==(const CFTypeRefPtr<PtrT>& aLhs, decltype(nullptr)) {
+ return aLhs.get() == nullptr;
+}
+
+template <class PtrT>
+inline bool operator==(decltype(nullptr), const CFTypeRefPtr<PtrT>& aRhs) {
+ return nullptr == aRhs.get();
+}
+
+template <class PtrT>
+inline bool operator!=(const CFTypeRefPtr<PtrT>& aLhs, decltype(nullptr)) {
+ return aLhs.get() != nullptr;
+}
+
+template <class PtrT>
+inline bool operator!=(decltype(nullptr), const CFTypeRefPtr<PtrT>& aRhs) {
+ return nullptr != aRhs.get();
+}
+
+// MOZ_DBG support
+
+template <class PtrT>
+std::ostream& operator<<(std::ostream& aOut, const CFTypeRefPtr<PtrT>& aObj) {
+ return mozilla::DebugValue(aOut, aObj.get());
+}
+
+// std::hash support (e.g. for unordered_map)
+namespace std {
+template <class PtrT>
+struct hash<CFTypeRefPtr<PtrT>> {
+ typedef CFTypeRefPtr<PtrT> argument_type;
+ typedef std::size_t result_type;
+ result_type operator()(argument_type const& aPtr) const {
+ return mozilla::HashGeneric(reinterpret_cast<uintptr_t>(aPtr.get()));
+ }
+};
+} // namespace std
+
+#endif /* CFTypeRefPtr_h */