OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef BASE_MAC_SCOPED_NSOBJECT_H_ | 5 #ifndef BASE_MAC_SCOPED_NSOBJECT_H_ |
6 #define BASE_MAC_SCOPED_NSOBJECT_H_ | 6 #define BASE_MAC_SCOPED_NSOBJECT_H_ |
7 | 7 |
8 #include <type_traits> | 8 #include <type_traits> |
9 | 9 |
10 // Include NSObject.h directly because Foundation.h pulls in many dependencies. | 10 // Include NSObject.h directly because Foundation.h pulls in many dependencies. |
11 // (Approx 100k lines of code versus 1.5k for NSObject.h). scoped_nsobject gets | 11 // (Approx 100k lines of code versus 1.5k for NSObject.h). scoped_nsobject gets |
12 // singled out because it is most typically included from other header files. | 12 // singled out because it is most typically included from other header files. |
13 #import <Foundation/NSObject.h> | 13 #import <Foundation/NSObject.h> |
14 | 14 |
| 15 #include "base/base_export.h" |
15 #include "base/compiler_specific.h" | 16 #include "base/compiler_specific.h" |
16 #include "base/mac/scoped_typeref.h" | 17 #include "base/mac/scoped_typeref.h" |
17 | 18 |
| 19 #if !defined(__has_feature) || !__has_feature(objc_arc) |
18 @class NSAutoreleasePool; | 20 @class NSAutoreleasePool; |
| 21 #endif |
19 | 22 |
20 namespace base { | 23 namespace base { |
21 | 24 |
22 // scoped_nsobject<> is patterned after std::unique_ptr<>, but maintains | 25 // scoped_nsobject<> is patterned after std::unique_ptr<>, but maintains |
23 // ownership of an NSObject subclass object. Style deviations here are solely | 26 // ownership of an NSObject subclass object. Style deviations here are solely |
24 // for compatibility with std::unique_ptr<>'s interface, with which everyone is | 27 // for compatibility with std::unique_ptr<>'s interface, with which everyone is |
25 // already familiar. | 28 // already familiar. |
26 // | 29 // |
27 // scoped_nsobject<> takes ownership of an object (in the constructor or in | 30 // scoped_nsobject<> takes ownership of an object (in the constructor or in |
28 // reset()) by taking over the caller's existing ownership claim. The caller | 31 // reset()) by taking over the caller's existing ownership claim. The caller |
29 // must own the object it gives to scoped_nsobject<>, and relinquishes an | 32 // must own the object it gives to scoped_nsobject<>, and relinquishes an |
30 // ownership claim to that object. scoped_nsobject<> does not call -retain, | 33 // ownership claim to that object. scoped_nsobject<> does not call -retain, |
31 // callers have to call this manually if appropriate. | 34 // callers have to call this manually if appropriate. |
32 // | 35 // |
33 // scoped_nsprotocol<> has the same behavior as scoped_nsobject, but can be used | 36 // scoped_nsprotocol<> has the same behavior as scoped_nsobject, but can be used |
34 // with protocols. | 37 // with protocols. |
35 // | 38 // |
36 // scoped_nsobject<> is not to be used for NSAutoreleasePools. For | 39 // scoped_nsobject<> is not to be used for NSAutoreleasePools. For |
37 // NSAutoreleasePools use ScopedNSAutoreleasePool from | 40 // NSAutoreleasePools use ScopedNSAutoreleasePool from |
38 // scoped_nsautorelease_pool.h instead. | 41 // scoped_nsautorelease_pool.h instead. |
39 // We check for bad uses of scoped_nsobject and NSAutoreleasePool at compile | 42 // We check for bad uses of scoped_nsobject and NSAutoreleasePool at compile |
40 // time with a template specialization (see below). | 43 // time with a template specialization (see below). |
| 44 // |
| 45 // If Automatic Reference Counting (aka ARC) is enabled then the ownership |
| 46 // policy is not controllable by the user as ARC make it really difficult to |
| 47 // transfer ownership (the reference passed to scoped_nsobject constructor is |
| 48 // sunk by ARC and __attribute((ns_consumed)) appears to not work correctly |
| 49 // with Objective-C++ see https://llvm.org/bugs/show_bug.cgi?id=27887). Due to |
| 50 // that, the policy is always to |RETAIN| when using ARC. |
41 | 51 |
42 namespace internal { | 52 namespace internal { |
43 | 53 |
| 54 BASE_EXPORT id ScopedNSProtocolTraitsRetain(__unsafe_unretained id obj) |
| 55 __attribute((ns_returns_not_retained)); |
| 56 BASE_EXPORT id ScopedNSProtocolTraitsAutoRelease(__unsafe_unretained id obj) |
| 57 __attribute((ns_returns_not_retained)); |
| 58 BASE_EXPORT void ScopedNSProtocolTraitsRelease(__unsafe_unretained id obj); |
| 59 |
| 60 // Traits for ScopedTypeRef<>. As this class may be compiled from file with |
| 61 // Automatic Reference Counting enable or not all methods have annotation to |
| 62 // enforce the same code generation in both case (in particular, the Retain |
| 63 // method uses ns_returns_not_retained to prevent ARC to insert a -release |
| 64 // call on the returned value and thus defeating the -retain). |
44 template <typename NST> | 65 template <typename NST> |
45 struct ScopedNSProtocolTraits { | 66 struct ScopedNSProtocolTraits { |
46 static NST InvalidValue() { return nil; } | 67 static NST InvalidValue() __attribute((ns_returns_not_retained)) { |
47 static NST Retain(NST nst) { return [nst retain]; } | 68 return nil; |
48 static void Release(NST nst) { [nst release]; } | 69 } |
| 70 static NST Retain(__unsafe_unretained NST nst) |
| 71 __attribute((ns_returns_not_retained)) { |
| 72 return ScopedNSProtocolTraitsRetain(nst); |
| 73 } |
| 74 static void Release(__unsafe_unretained NST nst) { |
| 75 ScopedNSProtocolTraitsRelease(nst); |
| 76 } |
49 }; | 77 }; |
50 | 78 |
51 } // namespace internal | 79 } // namespace internal |
52 | 80 |
53 template <typename NST> | 81 template <typename NST> |
54 class scoped_nsprotocol | 82 class scoped_nsprotocol |
55 : public ScopedTypeRef<NST, internal::ScopedNSProtocolTraits<NST>> { | 83 : public ScopedTypeRef<NST, internal::ScopedNSProtocolTraits<NST>> { |
56 public: | 84 public: |
57 using ScopedTypeRef<NST, | 85 using Traits = internal::ScopedNSProtocolTraits<NST>; |
58 internal::ScopedNSProtocolTraits<NST>>::ScopedTypeRef; | 86 |
| 87 #if !defined(__has_feature) || !__has_feature(objc_arc) |
| 88 explicit scoped_nsprotocol( |
| 89 NST object = Traits::InvalidValue(), |
| 90 base::scoped_policy::OwnershipPolicy policy = base::scoped_policy::ASSUME) |
| 91 : ScopedTypeRef<NST, Traits>(object, policy) {} |
| 92 #else |
| 93 explicit scoped_nsprotocol(NST object = Traits::InvalidValue()) |
| 94 : ScopedTypeRef<NST, Traits>(object, base::scoped_policy::RETAIN) {} |
| 95 #endif |
| 96 |
| 97 scoped_nsprotocol(const scoped_nsprotocol<NST>& that) |
| 98 : ScopedTypeRef<NST, Traits>(that) {} |
| 99 |
| 100 template <typename NSR> |
| 101 explicit scoped_nsprotocol(const scoped_nsprotocol<NSR>& that_as_subclass) |
| 102 : ScopedTypeRef<NST, Traits>(that_as_subclass) {} |
| 103 |
| 104 scoped_nsprotocol(scoped_nsprotocol<NST>&& that) |
| 105 : ScopedTypeRef<NST, Traits>(that) {} |
| 106 |
| 107 scoped_nsprotocol& operator=(const scoped_nsprotocol<NST>& that) { |
| 108 ScopedTypeRef<NST, Traits>::operator=(that); |
| 109 return *this; |
| 110 } |
| 111 |
| 112 #if !defined(__has_feature) || !__has_feature(objc_arc) |
| 113 void reset(NST object = Traits::InvalidValue(), |
| 114 base::scoped_policy::OwnershipPolicy policy = |
| 115 base::scoped_policy::ASSUME) { |
| 116 ScopedTypeRef<NST, Traits>::reset(object, policy); |
| 117 } |
| 118 #else |
| 119 void reset(NST object = Traits::InvalidValue()) { |
| 120 ScopedTypeRef<NST, Traits>::reset(object, base::scoped_policy::RETAIN); |
| 121 } |
| 122 #endif |
59 | 123 |
60 // Shift reference to the autorelease pool to be released later. | 124 // Shift reference to the autorelease pool to be released later. |
61 NST autorelease() { return [this->release() autorelease]; } | 125 NST autorelease() __attribute((ns_returns_not_retained)) { |
| 126 return internal::ScopedNSProtocolTraitsAutoRelease(this->release()); |
| 127 } |
62 }; | 128 }; |
63 | 129 |
64 // Free functions | 130 // Free functions |
65 template <class C> | 131 template <class C> |
66 void swap(scoped_nsprotocol<C>& p1, scoped_nsprotocol<C>& p2) { | 132 void swap(scoped_nsprotocol<C>& p1, scoped_nsprotocol<C>& p2) { |
67 p1.swap(p2); | 133 p1.swap(p2); |
68 } | 134 } |
69 | 135 |
70 template <class C> | 136 template <class C> |
71 bool operator==(C p1, const scoped_nsprotocol<C>& p2) { | 137 bool operator==(C p1, const scoped_nsprotocol<C>& p2) { |
72 return p1 == p2.get(); | 138 return p1 == p2.get(); |
73 } | 139 } |
74 | 140 |
75 template <class C> | 141 template <class C> |
76 bool operator!=(C p1, const scoped_nsprotocol<C>& p2) { | 142 bool operator!=(C p1, const scoped_nsprotocol<C>& p2) { |
77 return p1 != p2.get(); | 143 return p1 != p2.get(); |
78 } | 144 } |
79 | 145 |
80 template <typename NST> | 146 template <typename NST> |
81 class scoped_nsobject : public scoped_nsprotocol<NST*> { | 147 class scoped_nsobject : public scoped_nsprotocol<NST*> { |
82 public: | 148 public: |
83 using scoped_nsprotocol<NST*>::scoped_nsprotocol; | 149 using Traits = typename scoped_nsprotocol<NST*>::Traits; |
84 | 150 |
| 151 #if !defined(__has_feature) || !__has_feature(objc_arc) |
| 152 explicit scoped_nsobject( |
| 153 NST* object = Traits::InvalidValue(), |
| 154 base::scoped_policy::OwnershipPolicy policy = base::scoped_policy::ASSUME) |
| 155 : scoped_nsprotocol<NST*>(object, policy) {} |
| 156 #else |
| 157 explicit scoped_nsobject(NST* object = Traits::InvalidValue()) |
| 158 : scoped_nsprotocol<NST*>(object) {} |
| 159 #endif |
| 160 |
| 161 scoped_nsobject(const scoped_nsobject<NST>& that) |
| 162 : scoped_nsprotocol<NST*>(that) {} |
| 163 |
| 164 template <typename NSR> |
| 165 explicit scoped_nsobject(const scoped_nsobject<NSR>& that_as_subclass) |
| 166 : scoped_nsprotocol<NST*>(that_as_subclass) {} |
| 167 |
| 168 scoped_nsobject(scoped_nsobject<NST>&& that) |
| 169 : scoped_nsprotocol<NST*>(that) {} |
| 170 |
| 171 scoped_nsobject& operator=(const scoped_nsobject<NST>& that) { |
| 172 scoped_nsprotocol<NST*>::operator=(that); |
| 173 return *this; |
| 174 } |
| 175 |
| 176 #if !defined(__has_feature) || !__has_feature(objc_arc) |
| 177 void reset(NST* object = Traits::InvalidValue(), |
| 178 base::scoped_policy::OwnershipPolicy policy = |
| 179 base::scoped_policy::ASSUME) { |
| 180 scoped_nsprotocol<NST*>::reset(object, policy); |
| 181 } |
| 182 #else |
| 183 void reset(NST* object = Traits::InvalidValue()) { |
| 184 scoped_nsprotocol<NST*>::reset(object); |
| 185 } |
| 186 #endif |
| 187 |
| 188 #if !defined(__has_feature) || !__has_feature(objc_arc) |
85 static_assert(std::is_same<NST, NSAutoreleasePool>::value == false, | 189 static_assert(std::is_same<NST, NSAutoreleasePool>::value == false, |
86 "Use ScopedNSAutoreleasePool instead"); | 190 "Use ScopedNSAutoreleasePool instead"); |
| 191 #endif |
87 }; | 192 }; |
88 | 193 |
89 // Specialization to make scoped_nsobject<id> work. | 194 // Specialization to make scoped_nsobject<id> work. |
90 template<> | 195 template<> |
91 class scoped_nsobject<id> : public scoped_nsprotocol<id> { | 196 class scoped_nsobject<id> : public scoped_nsprotocol<id> { |
92 public: | 197 public: |
93 using scoped_nsprotocol<id>::scoped_nsprotocol; | 198 using Traits = typename scoped_nsprotocol<id>::Traits; |
| 199 |
| 200 #if !defined(__has_feature) || !__has_feature(objc_arc) |
| 201 explicit scoped_nsobject( |
| 202 id object = Traits::InvalidValue(), |
| 203 base::scoped_policy::OwnershipPolicy policy = base::scoped_policy::ASSUME) |
| 204 : scoped_nsprotocol<id>(object, policy) {} |
| 205 #else |
| 206 explicit scoped_nsobject(id object = Traits::InvalidValue()) |
| 207 : scoped_nsprotocol<id>(object) {} |
| 208 #endif |
| 209 |
| 210 scoped_nsobject(const scoped_nsobject<id>& that) |
| 211 : scoped_nsprotocol<id>(that) {} |
| 212 |
| 213 template <typename NSR> |
| 214 explicit scoped_nsobject(const scoped_nsobject<NSR>& that_as_subclass) |
| 215 : scoped_nsprotocol<id>(that_as_subclass) {} |
| 216 |
| 217 scoped_nsobject(scoped_nsobject<id>&& that) : scoped_nsprotocol<id>(that) {} |
| 218 |
| 219 scoped_nsobject& operator=(const scoped_nsobject<id>& that) { |
| 220 scoped_nsprotocol<id>::operator=(that); |
| 221 return *this; |
| 222 } |
| 223 |
| 224 #if !defined(__has_feature) || !__has_feature(objc_arc) |
| 225 void reset(id object = Traits::InvalidValue(), |
| 226 base::scoped_policy::OwnershipPolicy policy = |
| 227 base::scoped_policy::ASSUME) { |
| 228 scoped_nsprotocol<id>::reset(object, policy); |
| 229 } |
| 230 #else |
| 231 void reset(id object = Traits::InvalidValue()) { |
| 232 scoped_nsprotocol<id>::reset(object); |
| 233 } |
| 234 #endif |
94 }; | 235 }; |
95 | 236 |
96 } // namespace base | 237 } // namespace base |
97 | 238 |
98 #endif // BASE_MAC_SCOPED_NSOBJECT_H_ | 239 #endif // BASE_MAC_SCOPED_NSOBJECT_H_ |
OLD | NEW |