1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef BASE_MAC_SCOPED_TYPEREF_H_ 6 #define BASE_MAC_SCOPED_TYPEREF_H_ 7 8 #include "base/compiler_specific.h" 9 #include "base/logging.h" 10 #include "base/memory/scoped_policy.h" 11 12 namespace base { 13 14 // ScopedTypeRef<> is patterned after std::unique_ptr<>, but maintains ownership 15 // of a reference to any type that is maintained by Retain and Release methods. 16 // 17 // The Traits structure must provide the Retain and Release methods for type T. 18 // A default ScopedTypeRefTraits is used but not defined, and should be defined 19 // for each type to use this interface. For example, an appropriate definition 20 // of ScopedTypeRefTraits for CGLContextObj would be: 21 // 22 // template<> 23 // struct ScopedTypeRefTraits<CGLContextObj> { 24 // static CGLContextObj InvalidValue() { return nullptr; } 25 // static CGLContextObj Retain(CGLContextObj object) { 26 // CGLContextRetain(object); 27 // return object; 28 // } 29 // static void Release(CGLContextObj object) { CGLContextRelease(object); } 30 // }; 31 // 32 // For the many types that have pass-by-pointer create functions, the function 33 // InitializeInto() is provided to allow direct initialization and assumption 34 // of ownership of the object. For example, continuing to use the above 35 // CGLContextObj specialization: 36 // 37 // base::ScopedTypeRef<CGLContextObj> context; 38 // CGLCreateContext(pixel_format, share_group, context.InitializeInto()); 39 // 40 // For initialization with an existing object, the caller may specify whether 41 // the ScopedTypeRef<> being initialized is assuming the caller's existing 42 // ownership of the object (and should not call Retain in initialization) or if 43 // it should not assume this ownership and must create its own (by calling 44 // Retain in initialization). This behavior is based on the |policy| parameter, 45 // with |ASSUME| for the former and |RETAIN| for the latter. The default policy 46 // is to |ASSUME|. 47 48 template<typename T> 49 struct ScopedTypeRefTraits; 50 51 template<typename T, typename Traits = ScopedTypeRefTraits<T>> 52 class ScopedTypeRef { 53 public: 54 typedef T element_type; 55 56 explicit ScopedTypeRef( 57 __unsafe_unretained T object = Traits::InvalidValue(), 58 base::scoped_policy::OwnershipPolicy policy = base::scoped_policy::ASSUME) object_(object)59 : object_(object) { 60 if (object_ && policy == base::scoped_policy::RETAIN) 61 object_ = Traits::Retain(object_); 62 } 63 ScopedTypeRef(const ScopedTypeRef<T,Traits> & that)64 ScopedTypeRef(const ScopedTypeRef<T, Traits>& that) 65 : object_(that.object_) { 66 if (object_) 67 object_ = Traits::Retain(object_); 68 } 69 70 // This allows passing an object to a function that takes its superclass. 71 template <typename R, typename RTraits> ScopedTypeRef(const ScopedTypeRef<R,RTraits> & that_as_subclass)72 explicit ScopedTypeRef(const ScopedTypeRef<R, RTraits>& that_as_subclass) 73 : object_(that_as_subclass.get()) { 74 if (object_) 75 object_ = Traits::Retain(object_); 76 } 77 ScopedTypeRef(ScopedTypeRef<T,Traits> && that)78 ScopedTypeRef(ScopedTypeRef<T, Traits>&& that) : object_(that.object_) { 79 that.object_ = Traits::InvalidValue(); 80 } 81 ~ScopedTypeRef()82 ~ScopedTypeRef() { 83 if (object_) 84 Traits::Release(object_); 85 } 86 87 ScopedTypeRef& operator=(const ScopedTypeRef<T, Traits>& that) { 88 reset(that.get(), base::scoped_policy::RETAIN); 89 return *this; 90 } 91 92 // This is to be used only to take ownership of objects that are created 93 // by pass-by-pointer create functions. To enforce this, require that the 94 // object be reset to NULL before this may be used. InitializeInto()95 T* InitializeInto() WARN_UNUSED_RESULT { 96 DCHECK(!object_); 97 return &object_; 98 } 99 100 void reset(__unsafe_unretained T object = Traits::InvalidValue(), 101 base::scoped_policy::OwnershipPolicy policy = 102 base::scoped_policy::ASSUME) { 103 if (object && policy == base::scoped_policy::RETAIN) 104 object = Traits::Retain(object); 105 if (object_) 106 Traits::Release(object_); 107 object_ = object; 108 } 109 110 bool operator==(__unsafe_unretained T that) const { return object_ == that; } 111 112 bool operator!=(__unsafe_unretained T that) const { return object_ != that; } 113 T()114 operator T() const __attribute((ns_returns_not_retained)) { return object_; } 115 get()116 T get() const __attribute((ns_returns_not_retained)) { return object_; } 117 swap(ScopedTypeRef & that)118 void swap(ScopedTypeRef& that) { 119 __unsafe_unretained T temp = that.object_; 120 that.object_ = object_; 121 object_ = temp; 122 } 123 124 // ScopedTypeRef<>::release() is like std::unique_ptr<>::release. It is NOT 125 // a wrapper for Release(). To force a ScopedTypeRef<> object to call 126 // Release(), use ScopedTypeRef<>::reset(). release()127 T release() __attribute((ns_returns_not_retained)) WARN_UNUSED_RESULT { 128 __unsafe_unretained T temp = object_; 129 object_ = Traits::InvalidValue(); 130 return temp; 131 } 132 133 private: 134 __unsafe_unretained T object_; 135 }; 136 137 } // namespace base 138 139 #endif // BASE_MAC_SCOPED_TYPEREF_H_ 140