• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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