1 /*
2  *  Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  *
10  */
11 
12 #ifndef SDK_OBJC_HELPERS_SCOPED_CFTYPEREF_H_
13 #define SDK_OBJC_HELPERS_SCOPED_CFTYPEREF_H_
14 
15 #include <CoreFoundation/CoreFoundation.h>
16 namespace rtc {
17 
18 // RETAIN: ScopedTypeRef should retain the object when it takes
19 // ownership.
20 // ASSUME: Assume the object already has already been retained.
21 // ScopedTypeRef takes over ownership.
22 enum class RetainPolicy { RETAIN, ASSUME };
23 
24 namespace internal {
25 template <typename T>
26 struct CFTypeRefTraits {
InvalidValueCFTypeRefTraits27   static T InvalidValue() { return nullptr; }
ReleaseCFTypeRefTraits28   static void Release(T ref) { CFRelease(ref); }
RetainCFTypeRefTraits29   static T Retain(T ref) {
30     CFRetain(ref);
31     return ref;
32   }
33 };
34 
35 template <typename T, typename Traits>
36 class ScopedTypeRef {
37  public:
ScopedTypeRef()38   ScopedTypeRef() : ptr_(Traits::InvalidValue()) {}
ScopedTypeRef(T ptr)39   explicit ScopedTypeRef(T ptr) : ptr_(ptr) {}
ScopedTypeRef(T ptr,RetainPolicy policy)40   ScopedTypeRef(T ptr, RetainPolicy policy) : ScopedTypeRef(ptr) {
41     if (ptr_ && policy == RetainPolicy::RETAIN)
42       Traits::Retain(ptr_);
43   }
44 
ScopedTypeRef(const ScopedTypeRef<T,Traits> & rhs)45   ScopedTypeRef(const ScopedTypeRef<T, Traits>& rhs) : ptr_(rhs.ptr_) {
46     if (ptr_)
47       ptr_ = Traits::Retain(ptr_);
48   }
49 
~ScopedTypeRef()50   ~ScopedTypeRef() {
51     if (ptr_) {
52       Traits::Release(ptr_);
53     }
54   }
55 
get()56   T get() const { return ptr_; }
57   T operator->() const { return ptr_; }
58   explicit operator bool() const { return ptr_; }
59 
60   bool operator!() const { return !ptr_; }
61 
62   ScopedTypeRef& operator=(const T& rhs) {
63     if (ptr_)
64       Traits::Release(ptr_);
65     ptr_ = rhs;
66     return *this;
67   }
68 
69   ScopedTypeRef& operator=(const ScopedTypeRef<T, Traits>& rhs) {
70     reset(rhs.get(), RetainPolicy::RETAIN);
71     return *this;
72   }
73 
74   // This is intended to take ownership of objects that are
75   // created by pass-by-pointer initializers.
InitializeInto()76   T* InitializeInto() {
77     RTC_DCHECK(!ptr_);
78     return &ptr_;
79   }
80 
81   void reset(T ptr, RetainPolicy policy = RetainPolicy::ASSUME) {
82     if (ptr && policy == RetainPolicy::RETAIN)
83       Traits::Retain(ptr);
84     if (ptr_)
85       Traits::Release(ptr_);
86     ptr_ = ptr;
87   }
88 
release()89   T release() {
90     T temp = ptr_;
91     ptr_ = Traits::InvalidValue();
92     return temp;
93   }
94 
95  private:
96   T ptr_;
97 };
98 }  // namespace internal
99 
100 template <typename T>
101 using ScopedCFTypeRef =
102     internal::ScopedTypeRef<T, internal::CFTypeRefTraits<T>>;
103 
104 template <typename T>
AdoptCF(T cftype)105 static ScopedCFTypeRef<T> AdoptCF(T cftype) {
106   return ScopedCFTypeRef<T>(cftype, RetainPolicy::RETAIN);
107 }
108 
109 template <typename T>
ScopedCF(T cftype)110 static ScopedCFTypeRef<T> ScopedCF(T cftype) {
111   return ScopedCFTypeRef<T>(cftype);
112 }
113 
114 }  // namespace rtc
115 
116 #endif  // SDK_OBJC_HELPERS_SCOPED_CFTYPEREF_H_
117