| /* | |
| * Copyright 2019 Google LLC | |
| * | |
| * 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 |