1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2019 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker *
4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker */
7*c8dee2aaSAndroid Build Coastguard Worker
8*c8dee2aaSAndroid Build Coastguard Worker #ifndef SkCFObject_DEFINED
9*c8dee2aaSAndroid Build Coastguard Worker #define SkCFObject_DEFINED
10*c8dee2aaSAndroid Build Coastguard Worker
11*c8dee2aaSAndroid Build Coastguard Worker #ifdef __APPLE__
12*c8dee2aaSAndroid Build Coastguard Worker
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
14*c8dee2aaSAndroid Build Coastguard Worker
15*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef> // std::nullptr_t
16*c8dee2aaSAndroid Build Coastguard Worker
17*c8dee2aaSAndroid Build Coastguard Worker #import <CoreFoundation/CoreFoundation.h>
18*c8dee2aaSAndroid Build Coastguard Worker
19*c8dee2aaSAndroid Build Coastguard Worker /**
20*c8dee2aaSAndroid Build Coastguard Worker * Wrapper class for managing lifetime of CoreFoundation objects. It will call
21*c8dee2aaSAndroid Build Coastguard Worker * CFRetain and CFRelease appropriately on creation, assignment, and deletion.
22*c8dee2aaSAndroid Build Coastguard Worker * Based on sk_sp<>.
23*c8dee2aaSAndroid Build Coastguard Worker */
SkCFSafeRetain(T obj)24*c8dee2aaSAndroid Build Coastguard Worker template <typename T> static inline T SkCFSafeRetain(T obj) {
25*c8dee2aaSAndroid Build Coastguard Worker if (obj) {
26*c8dee2aaSAndroid Build Coastguard Worker CFRetain(obj);
27*c8dee2aaSAndroid Build Coastguard Worker }
28*c8dee2aaSAndroid Build Coastguard Worker return obj;
29*c8dee2aaSAndroid Build Coastguard Worker }
30*c8dee2aaSAndroid Build Coastguard Worker
SkCFSafeRelease(T obj)31*c8dee2aaSAndroid Build Coastguard Worker template <typename T> static inline void SkCFSafeRelease(T obj) {
32*c8dee2aaSAndroid Build Coastguard Worker if (obj) {
33*c8dee2aaSAndroid Build Coastguard Worker CFRelease(obj);
34*c8dee2aaSAndroid Build Coastguard Worker }
35*c8dee2aaSAndroid Build Coastguard Worker }
36*c8dee2aaSAndroid Build Coastguard Worker
37*c8dee2aaSAndroid Build Coastguard Worker template <typename T> class sk_cfp {
38*c8dee2aaSAndroid Build Coastguard Worker public:
39*c8dee2aaSAndroid Build Coastguard Worker using element_type = T;
40*c8dee2aaSAndroid Build Coastguard Worker
sk_cfp()41*c8dee2aaSAndroid Build Coastguard Worker constexpr sk_cfp() {}
sk_cfp(std::nullptr_t)42*c8dee2aaSAndroid Build Coastguard Worker constexpr sk_cfp(std::nullptr_t) {}
43*c8dee2aaSAndroid Build Coastguard Worker
44*c8dee2aaSAndroid Build Coastguard Worker /**
45*c8dee2aaSAndroid Build Coastguard Worker * Shares the underlying object by calling CFRetain(), so that both the argument and the newly
46*c8dee2aaSAndroid Build Coastguard Worker * created sk_cfp both have a reference to it.
47*c8dee2aaSAndroid Build Coastguard Worker */
sk_cfp(const sk_cfp<T> & that)48*c8dee2aaSAndroid Build Coastguard Worker sk_cfp(const sk_cfp<T>& that) : fObject(SkCFSafeRetain(that.get())) {}
49*c8dee2aaSAndroid Build Coastguard Worker
50*c8dee2aaSAndroid Build Coastguard Worker /**
51*c8dee2aaSAndroid Build Coastguard Worker * Move the underlying object from the argument to the newly created sk_cfp. Afterwards only
52*c8dee2aaSAndroid Build Coastguard Worker * the new sk_cfp will have a reference to the object, and the argument will point to null.
53*c8dee2aaSAndroid Build Coastguard Worker * No call to CFRetain() or CFRelease() will be made.
54*c8dee2aaSAndroid Build Coastguard Worker */
sk_cfp(sk_cfp<T> && that)55*c8dee2aaSAndroid Build Coastguard Worker sk_cfp(sk_cfp<T>&& that) : fObject(that.release()) {}
56*c8dee2aaSAndroid Build Coastguard Worker
57*c8dee2aaSAndroid Build Coastguard Worker /**
58*c8dee2aaSAndroid Build Coastguard Worker * Adopt the bare object into the newly created sk_cfp.
59*c8dee2aaSAndroid Build Coastguard Worker * No call to CFRetain() or CFRelease() will be made.
60*c8dee2aaSAndroid Build Coastguard Worker */
sk_cfp(T obj)61*c8dee2aaSAndroid Build Coastguard Worker explicit sk_cfp(T obj) {
62*c8dee2aaSAndroid Build Coastguard Worker fObject = obj;
63*c8dee2aaSAndroid Build Coastguard Worker }
64*c8dee2aaSAndroid Build Coastguard Worker
65*c8dee2aaSAndroid Build Coastguard Worker /**
66*c8dee2aaSAndroid Build Coastguard Worker * Calls CFRelease() on the underlying object pointer.
67*c8dee2aaSAndroid Build Coastguard Worker */
~sk_cfp()68*c8dee2aaSAndroid Build Coastguard Worker ~sk_cfp() {
69*c8dee2aaSAndroid Build Coastguard Worker SkCFSafeRelease(fObject);
70*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(fObject = nil);
71*c8dee2aaSAndroid Build Coastguard Worker }
72*c8dee2aaSAndroid Build Coastguard Worker
73*c8dee2aaSAndroid Build Coastguard Worker sk_cfp<T>& operator=(std::nullptr_t) { this->reset(); return *this; }
74*c8dee2aaSAndroid Build Coastguard Worker
75*c8dee2aaSAndroid Build Coastguard Worker /**
76*c8dee2aaSAndroid Build Coastguard Worker * Shares the underlying object referenced by the argument by calling CFRetain() on it. If this
77*c8dee2aaSAndroid Build Coastguard Worker * sk_cfp previously had a reference to an object (i.e. not null) it will call CFRelease()
78*c8dee2aaSAndroid Build Coastguard Worker * on that object.
79*c8dee2aaSAndroid Build Coastguard Worker */
80*c8dee2aaSAndroid Build Coastguard Worker sk_cfp<T>& operator=(const sk_cfp<T>& that) {
81*c8dee2aaSAndroid Build Coastguard Worker if (this != &that) {
82*c8dee2aaSAndroid Build Coastguard Worker this->reset(SkCFSafeRetain(that.get()));
83*c8dee2aaSAndroid Build Coastguard Worker }
84*c8dee2aaSAndroid Build Coastguard Worker return *this;
85*c8dee2aaSAndroid Build Coastguard Worker }
86*c8dee2aaSAndroid Build Coastguard Worker
87*c8dee2aaSAndroid Build Coastguard Worker /**
88*c8dee2aaSAndroid Build Coastguard Worker * Move the underlying object from the argument to the sk_cfp. If the sk_cfp
89*c8dee2aaSAndroid Build Coastguard Worker * previously held a reference to another object, CFRelease() will be called on that object.
90*c8dee2aaSAndroid Build Coastguard Worker * No call to CFRetain() will be made.
91*c8dee2aaSAndroid Build Coastguard Worker */
92*c8dee2aaSAndroid Build Coastguard Worker sk_cfp<T>& operator=(sk_cfp<T>&& that) {
93*c8dee2aaSAndroid Build Coastguard Worker this->reset(that.release());
94*c8dee2aaSAndroid Build Coastguard Worker return *this;
95*c8dee2aaSAndroid Build Coastguard Worker }
96*c8dee2aaSAndroid Build Coastguard Worker
97*c8dee2aaSAndroid Build Coastguard Worker explicit operator bool() const { return this->get() != nil; }
98*c8dee2aaSAndroid Build Coastguard Worker
get()99*c8dee2aaSAndroid Build Coastguard Worker T get() const { return fObject; }
100*c8dee2aaSAndroid Build Coastguard Worker T operator*() const {
101*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fObject);
102*c8dee2aaSAndroid Build Coastguard Worker return fObject;
103*c8dee2aaSAndroid Build Coastguard Worker }
104*c8dee2aaSAndroid Build Coastguard Worker
105*c8dee2aaSAndroid Build Coastguard Worker /**
106*c8dee2aaSAndroid Build Coastguard Worker * Adopt the new object, and call CFRelease() on any previously held object (if not null).
107*c8dee2aaSAndroid Build Coastguard Worker * No call to CFRetain() will be made.
108*c8dee2aaSAndroid Build Coastguard Worker */
109*c8dee2aaSAndroid Build Coastguard Worker void reset(T object = nil) {
110*c8dee2aaSAndroid Build Coastguard Worker // Need to unref after assigning, see
111*c8dee2aaSAndroid Build Coastguard Worker // http://wg21.cmeerw.net/lwg/issue998
112*c8dee2aaSAndroid Build Coastguard Worker // http://wg21.cmeerw.net/lwg/issue2262
113*c8dee2aaSAndroid Build Coastguard Worker T oldObject = fObject;
114*c8dee2aaSAndroid Build Coastguard Worker fObject = object;
115*c8dee2aaSAndroid Build Coastguard Worker SkCFSafeRelease(oldObject);
116*c8dee2aaSAndroid Build Coastguard Worker }
117*c8dee2aaSAndroid Build Coastguard Worker
118*c8dee2aaSAndroid Build Coastguard Worker /**
119*c8dee2aaSAndroid Build Coastguard Worker * Shares the new object by calling CFRetain() on it. If this sk_cfp previously had a
120*c8dee2aaSAndroid Build Coastguard Worker * reference to an object (i.e. not null) it will call CFRelease() on that object.
121*c8dee2aaSAndroid Build Coastguard Worker */
retain(T object)122*c8dee2aaSAndroid Build Coastguard Worker void retain(T object) {
123*c8dee2aaSAndroid Build Coastguard Worker if (fObject != object) {
124*c8dee2aaSAndroid Build Coastguard Worker this->reset(SkCFSafeRetain(object));
125*c8dee2aaSAndroid Build Coastguard Worker }
126*c8dee2aaSAndroid Build Coastguard Worker }
127*c8dee2aaSAndroid Build Coastguard Worker
128*c8dee2aaSAndroid Build Coastguard Worker /**
129*c8dee2aaSAndroid Build Coastguard Worker * Return the original object, and set the internal object to nullptr.
130*c8dee2aaSAndroid Build Coastguard Worker * The caller must assume ownership of the object, and manage its reference count directly.
131*c8dee2aaSAndroid Build Coastguard Worker * No call to CFRelease() will be made.
132*c8dee2aaSAndroid Build Coastguard Worker */
release()133*c8dee2aaSAndroid Build Coastguard Worker [[nodiscard]] T release() {
134*c8dee2aaSAndroid Build Coastguard Worker T obj = fObject;
135*c8dee2aaSAndroid Build Coastguard Worker fObject = nil;
136*c8dee2aaSAndroid Build Coastguard Worker return obj;
137*c8dee2aaSAndroid Build Coastguard Worker }
138*c8dee2aaSAndroid Build Coastguard Worker
139*c8dee2aaSAndroid Build Coastguard Worker private:
140*c8dee2aaSAndroid Build Coastguard Worker T fObject = nil;
141*c8dee2aaSAndroid Build Coastguard Worker };
142*c8dee2aaSAndroid Build Coastguard Worker
143*c8dee2aaSAndroid Build Coastguard Worker template <typename T> inline bool operator==(const sk_cfp<T>& a,
144*c8dee2aaSAndroid Build Coastguard Worker const sk_cfp<T>& b) {
145*c8dee2aaSAndroid Build Coastguard Worker return a.get() == b.get();
146*c8dee2aaSAndroid Build Coastguard Worker }
147*c8dee2aaSAndroid Build Coastguard Worker template <typename T> inline bool operator==(const sk_cfp<T>& a,
148*c8dee2aaSAndroid Build Coastguard Worker std::nullptr_t) {
149*c8dee2aaSAndroid Build Coastguard Worker return !a;
150*c8dee2aaSAndroid Build Coastguard Worker }
151*c8dee2aaSAndroid Build Coastguard Worker template <typename T> inline bool operator==(std::nullptr_t,
152*c8dee2aaSAndroid Build Coastguard Worker const sk_cfp<T>& b) {
153*c8dee2aaSAndroid Build Coastguard Worker return !b;
154*c8dee2aaSAndroid Build Coastguard Worker }
155*c8dee2aaSAndroid Build Coastguard Worker
156*c8dee2aaSAndroid Build Coastguard Worker template <typename T> inline bool operator!=(const sk_cfp<T>& a,
157*c8dee2aaSAndroid Build Coastguard Worker const sk_cfp<T>& b) {
158*c8dee2aaSAndroid Build Coastguard Worker return a.get() != b.get();
159*c8dee2aaSAndroid Build Coastguard Worker }
160*c8dee2aaSAndroid Build Coastguard Worker template <typename T> inline bool operator!=(const sk_cfp<T>& a,
161*c8dee2aaSAndroid Build Coastguard Worker std::nullptr_t) {
162*c8dee2aaSAndroid Build Coastguard Worker return static_cast<bool>(a);
163*c8dee2aaSAndroid Build Coastguard Worker }
164*c8dee2aaSAndroid Build Coastguard Worker template <typename T> inline bool operator!=(std::nullptr_t,
165*c8dee2aaSAndroid Build Coastguard Worker const sk_cfp<T>& b) {
166*c8dee2aaSAndroid Build Coastguard Worker return static_cast<bool>(b);
167*c8dee2aaSAndroid Build Coastguard Worker }
168*c8dee2aaSAndroid Build Coastguard Worker
169*c8dee2aaSAndroid Build Coastguard Worker /*
170*c8dee2aaSAndroid Build Coastguard Worker * Returns a sk_cfp wrapping the provided object AND calls retain on it (if not null).
171*c8dee2aaSAndroid Build Coastguard Worker *
172*c8dee2aaSAndroid Build Coastguard Worker * This is different than the semantics of the constructor for sk_cfp, which just wraps the
173*c8dee2aaSAndroid Build Coastguard Worker * object, effectively "adopting" it.
174*c8dee2aaSAndroid Build Coastguard Worker */
sk_ret_cfp(T obj)175*c8dee2aaSAndroid Build Coastguard Worker template <typename T> sk_cfp<T> sk_ret_cfp(T obj) {
176*c8dee2aaSAndroid Build Coastguard Worker return sk_cfp<T>(SkCFSafeRetain(obj));
177*c8dee2aaSAndroid Build Coastguard Worker }
178*c8dee2aaSAndroid Build Coastguard Worker
179*c8dee2aaSAndroid Build Coastguard Worker #endif // __APPLE__
180*c8dee2aaSAndroid Build Coastguard Worker #endif // SkCFObject_DEFINED
181