1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
|
/*
* 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
|