1 //
2 // Copyright 2025 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // ObjCPtr.h:
7 // Implements smart pointer for Objective-C objects
8
9 #ifndef COMMON_APPLE_OBJCPTR_H_
10 #define COMMON_APPLE_OBJCPTR_H_
11
12 #ifndef __OBJC__
13 # error For Objective-C++ only.
14 #endif
15
16 #import <Foundation/Foundation.h>
17 #import <type_traits>
18 #import <utility>
19 #import "common/platform.h"
20
21 namespace angle
22 {
23
24 // Smart pointer for holding Objective-C objects. Use adoptObjCPtr for create functions
25 // that return owned reference, e.g. functions that begin with 'new', 'copy', 'create'.
26 template <typename T>
27 class ObjCPtr
28 {
29 public:
30 using PtrType = std::remove_pointer_t<T> *;
31
32 constexpr ObjCPtr() = default;
ObjCPtr(std::nullptr_t other)33 constexpr ObjCPtr(std::nullptr_t other) {}
34 ObjCPtr(PtrType other);
35 ObjCPtr(const ObjCPtr &other);
36 template <typename U>
37 constexpr ObjCPtr(ObjCPtr<U> &&other);
38 ~ObjCPtr();
39 ObjCPtr &operator=(const ObjCPtr &other);
40 ObjCPtr &operator=(PtrType other);
41 template <typename U>
42 constexpr ObjCPtr &operator=(ObjCPtr<U> &&other);
43
44 [[nodiscard]] constexpr PtrType leakObject();
45 void reset();
46
47 constexpr explicit operator bool() const { return get(); }
PtrType()48 constexpr operator PtrType() const { return get(); }
get()49 constexpr PtrType get() const { return mObject; }
50 constexpr void swap(ObjCPtr<T> &other);
51
52 template <typename U>
53 friend ObjCPtr<std::remove_pointer_t<U>> adoptObjCPtr(U NS_RELEASES_ARGUMENT);
54
55 private:
56 struct AdoptTag
57 {};
58 constexpr ObjCPtr(PtrType other, AdoptTag);
59
60 PtrType mObject = nil;
61 };
62
63 template <typename T>
64 ObjCPtr(T) -> ObjCPtr<std::remove_pointer_t<T>>;
65
66 template <typename T>
ObjCPtr(PtrType other)67 ObjCPtr<T>::ObjCPtr(PtrType other) : mObject(other)
68 {
69 #if !__has_feature(objc_arc)
70 [mObject retain];
71 #endif
72 }
73
74 template <typename T>
ObjCPtr(const ObjCPtr & other)75 ObjCPtr<T>::ObjCPtr(const ObjCPtr &other) : ObjCPtr(other.mObject)
76 {}
77
78 template <typename T>
79 template <typename U>
ObjCPtr(ObjCPtr<U> && other)80 constexpr ObjCPtr<T>::ObjCPtr(ObjCPtr<U> &&other) : mObject(other.leakObject())
81 {}
82
83 template <typename T>
~ObjCPtr()84 ObjCPtr<T>::~ObjCPtr()
85 {
86 #if !__has_feature(objc_arc)
87 [mObject release];
88 #endif
89 }
90
91 template <typename T>
92 ObjCPtr<T> &ObjCPtr<T>::operator=(const ObjCPtr &other)
93 {
94 ObjCPtr temp = other;
95 swap(temp);
96 return *this;
97 }
98
99 template <typename T>
100 template <typename U>
101 constexpr ObjCPtr<T> &ObjCPtr<T>::operator=(ObjCPtr<U> &&other)
102 {
103 ObjCPtr temp = std::move(other);
104 swap(temp);
105 return *this;
106 }
107
108 template <typename T>
109 ObjCPtr<T> &ObjCPtr<T>::operator=(PtrType other)
110 {
111 ObjCPtr temp = other;
112 swap(temp);
113 return *this;
114 }
115
116 template <typename T>
ObjCPtr(PtrType other,AdoptTag)117 constexpr ObjCPtr<T>::ObjCPtr(PtrType other, AdoptTag) : mObject(other)
118 {}
119
120 template <typename T>
swap(ObjCPtr<T> & other)121 constexpr void ObjCPtr<T>::swap(ObjCPtr<T> &other)
122 {
123 // std::swap is constexpr only in c++20.
124 auto object = other.mObject;
125 other.mObject = mObject;
126 mObject = object;
127 }
128
129 template <typename T>
leakObject()130 constexpr typename ObjCPtr<T>::PtrType ObjCPtr<T>::leakObject()
131 {
132 // std::exchange is constexper only in c++20.
133 auto object = mObject;
134 mObject = nullptr;
135 return object;
136 }
137
138 template <typename T>
reset()139 void ObjCPtr<T>::reset()
140 {
141 *this = {};
142 }
143
144 template <typename T, typename U>
145 constexpr bool operator==(const ObjCPtr<T> &a, const ObjCPtr<U> &b)
146 {
147 return a.get() == b.get();
148 }
149
150 template <typename T, typename U>
151 constexpr bool operator==(const ObjCPtr<T> &a, U *b)
152 {
153 return a.get() == b;
154 }
155
156 template <typename T, typename U>
157 constexpr bool operator==(T *a, const ObjCPtr<U> &b)
158 {
159 return a == b.get();
160 }
161
162 template <typename U>
adoptObjCPtr(U NS_RELEASES_ARGUMENT other)163 ObjCPtr<std::remove_pointer_t<U>> adoptObjCPtr(U NS_RELEASES_ARGUMENT other)
164 {
165 using ResultType = ObjCPtr<std::remove_pointer_t<U>>;
166 return ResultType(other, typename ResultType::AdoptTag{});
167 }
168
169 } // namespace angle
170
171 #endif
172