/* * Copyright 2019 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef SkCFObject_DEFINED #define SkCFObject_DEFINED #ifdef __APPLE__ #include "include/core/SkTypes.h" #include <cstddef> // std::nullptr_t #import <CoreFoundation/CoreFoundation.h> /** * Wrapper class for managing lifetime of CoreFoundation objects. It will call * CFRetain and CFRelease appropriately on creation, assignment, and deletion. * Based on sk_sp<>. */ template <typename T> static inline T SkCFSafeRetain(T obj) { if (obj) { CFRetain(obj); } return obj; } template <typename T> static inline void SkCFSafeRelease(T obj) { if (obj) { CFRelease(obj); } } template <typename T> class sk_cfp { public: using element_type = T; constexpr sk_cfp() {} constexpr sk_cfp(std::nullptr_t) {} /** * Shares the underlying object by calling CFRetain(), so that both the argument and the newly * created sk_cfp both have a reference to it. */ sk_cfp(const sk_cfp<T>& that) : fObject(SkCFSafeRetain(that.get())) {} /** * Move the underlying object from the argument to the newly created sk_cfp. Afterwards only * the new sk_cfp will have a reference to the object, and the argument will point to null. * No call to CFRetain() or CFRelease() will be made. */ sk_cfp(sk_cfp<T>&& that) : fObject(that.release()) {} /** * Adopt the bare object into the newly created sk_cfp. * No call to CFRetain() or CFRelease() will be made. */ explicit sk_cfp(T obj) { fObject = obj; } /** * Calls CFRelease() on the underlying object pointer. */ ~sk_cfp() { SkCFSafeRelease(fObject); SkDEBUGCODE(fObject = nil); } sk_cfp<T>& operator=(std::nullptr_t) { this->reset(); return *this; } /** * Shares the underlying object referenced by the argument by calling CFRetain() on it. If this * sk_cfp previously had a reference to an object (i.e. not null) it will call CFRelease() * on that object. */ sk_cfp<T>& operator=(const sk_cfp<T>& that) { if (this != &that) { this->reset(SkCFSafeRetain(that.get())); } return *this; } /** * Move the underlying object from the argument to the sk_cfp. If the sk_cfp * previously held a reference to another object, CFRelease() will be called on that object. * No call to CFRetain() will be made. */ sk_cfp<T>& operator=(sk_cfp<T>&& that) { this->reset(that.release()); return *this; } explicit operator bool() const { return this->get() != nil; } T get() const { return fObject; } T operator*() const { SkASSERT(fObject); return fObject; } /** * Adopt the new object, and call CFRelease() on any previously held object (if not null). * No call to CFRetain() will be made. */ void reset(T object = nil) { // Need to unref after assigning, see // http://wg21.cmeerw.net/lwg/issue998 // http://wg21.cmeerw.net/lwg/issue2262 T oldObject = fObject; fObject = object; SkCFSafeRelease(oldObject); } /** * Shares the new object by calling CFRetain() on it. If this sk_cfp previously had a * reference to an object (i.e. not null) it will call CFRelease() on that object. */ void retain(T object) { if (fObject != object) { this->reset(SkCFSafeRetain(object)); } } /** * Return the original object, and set the internal object to nullptr. * The caller must assume ownership of the object, and manage its reference count directly. * No call to CFRelease() will be made. */ [[nodiscard]] T release() { T obj = fObject; fObject = nil; return obj; } private: T fObject = nil; }; template <typename T> inline bool operator==(const sk_cfp<T>& a, const sk_cfp<T>& b) { return a.get() == b.get(); } template <typename T> inline bool operator==(const sk_cfp<T>& a, std::nullptr_t) { return !a; } template <typename T> inline bool operator==(std::nullptr_t, const sk_cfp<T>& b) { return !b; } template <typename T> inline bool operator!=(const sk_cfp<T>& a, const sk_cfp<T>& b) { return a.get() != b.get(); } template <typename T> inline bool operator!=(const sk_cfp<T>& a, std::nullptr_t) { return static_cast<bool>(a); } template <typename T> inline bool operator!=(std::nullptr_t, const sk_cfp<T>& b) { return static_cast<bool>(b); } /* * Returns a sk_cfp wrapping the provided object AND calls retain on it (if not null). * * This is different than the semantics of the constructor for sk_cfp, which just wraps the * object, effectively "adopting" it. */ template <typename T> sk_cfp<T> sk_ret_cfp(T obj) { return sk_cfp<T>(SkCFSafeRetain(obj)); } #endif // __APPLE__ #endif // SkCFObject_DEFINED