• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 The PDFium Authors
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 CORE_FXCRT_RETAIN_PTR_H_
6 #define CORE_FXCRT_RETAIN_PTR_H_
7 
8 #include <stdint.h>
9 
10 #include <functional>
11 #include <memory>
12 #include <type_traits>
13 #include <utility>
14 
15 #include "core/fxcrt/check.h"
16 #include "core/fxcrt/compiler_specific.h"
17 
18 namespace fxcrt {
19 
20 // Used with std::unique_ptr to Release() objects that can't be deleted.
21 template <class T>
22 struct ReleaseDeleter {
operatorReleaseDeleter23   inline void operator()(T* ptr) const { ptr->Release(); }
24 };
25 
26 // Analogous to base's scoped_refptr.
27 template <class T>
28 class TRIVIAL_ABI RetainPtr {
29  public:
30   RetainPtr() noexcept = default;
31 
32   // Deliberately implicit to allow returning nullptrs.
33   // NOLINTNEXTLINE(runtime/explicit)
RetainPtr(std::nullptr_t ptr)34   RetainPtr(std::nullptr_t ptr) {}
35 
RetainPtr(T * pObj)36   explicit RetainPtr(T* pObj) noexcept : m_pObj(pObj) {
37     if (m_pObj)
38       m_pObj->Retain();
39   }
40 
41   // Copy-construct a RetainPtr.
42   // Required in addition to copy conversion constructor below.
RetainPtr(const RetainPtr & that)43   RetainPtr(const RetainPtr& that) noexcept : RetainPtr(that.Get()) {}
44 
45   // Move-construct a RetainPtr. After construction, |that| will be NULL.
46   // Required in addition to move conversion constructor below.
RetainPtr(RetainPtr && that)47   RetainPtr(RetainPtr&& that) noexcept { Unleak(that.Leak()); }
48 
49   // Copy conversion constructor.
50   template <class U,
51             typename = typename std::enable_if<
52                 std::is_convertible<U*, T*>::value>::type>
RetainPtr(const RetainPtr<U> & that)53   RetainPtr(const RetainPtr<U>& that) : RetainPtr(that.Get()) {}
54 
55   // Move-conversion constructor.
56   template <class U,
57             typename = typename std::enable_if<
58                 std::is_convertible<U*, T*>::value>::type>
RetainPtr(RetainPtr<U> && that)59   RetainPtr(RetainPtr<U>&& that) noexcept {
60     Unleak(that.Leak());
61   }
62 
63   // Assign a RetainPtr from nullptr;
64   RetainPtr& operator=(std::nullptr_t) noexcept {
65     Reset();
66     return *this;
67   }
68 
69   // Copy-assign a RetainPtr.
70   // Required in addition to copy conversion assignment below.
71   RetainPtr& operator=(const RetainPtr& that) {
72     if (*this != that)
73       Reset(that.Get());
74     return *this;
75   }
76 
77   // Move-assign a RetainPtr. After assignment, |that| will be NULL.
78   // Required in addition to move conversion assignment below.
79   RetainPtr& operator=(RetainPtr&& that) noexcept {
80     Unleak(that.Leak());
81     return *this;
82   }
83 
84   // Copy-convert assign a RetainPtr.
85   template <class U,
86             typename = typename std::enable_if<
87                 std::is_convertible<U*, T*>::value>::type>
88   RetainPtr& operator=(const RetainPtr<U>& that) {
89     if (*this != that)
90       Reset(that.Get());
91     return *this;
92   }
93 
94   // Move-convert assign a RetainPtr. After assignment, |that| will be NULL.
95   template <class U,
96             typename = typename std::enable_if<
97                 std::is_convertible<U*, T*>::value>::type>
98   RetainPtr& operator=(RetainPtr<U>&& that) noexcept {
99     Unleak(that.Leak());
100     return *this;
101   }
102 
103   ~RetainPtr() = default;
104 
105   template <class U>
AsRaw()106   U* AsRaw() const {
107     return static_cast<U*>(Get());
108   }
109 
110   template <class U>
As()111   RetainPtr<U> As() const {
112     return RetainPtr<U>(AsRaw<U>());
113   }
114 
115   void Reset(T* obj = nullptr) {
116     if (obj)
117       obj->Retain();
118     m_pObj.reset(obj);
119   }
120 
121   operator T*() const noexcept { return Get(); }
Get()122   T* Get() const noexcept { return m_pObj.get(); }
123 
Swap(RetainPtr & that)124   void Swap(RetainPtr& that) { m_pObj.swap(that.m_pObj); }
125 
126   // Useful for passing notion of object ownership across a C API.
Leak()127   T* Leak() { return m_pObj.release(); }
Unleak(T * ptr)128   void Unleak(T* ptr) { m_pObj.reset(ptr); }
129 
130   bool operator==(const RetainPtr& that) const { return Get() == that.Get(); }
131   bool operator!=(const RetainPtr& that) const { return !(*this == that); }
132 
133   template <typename U>
134   bool operator==(const U& that) const {
135     return Get() == that;
136   }
137 
138   template <typename U>
139   bool operator!=(const U& that) const {
140     return !(*this == that);
141   }
142 
143   bool operator<(const RetainPtr& that) const {
144     return std::less<T*>()(Get(), that.Get());
145   }
146 
147   explicit operator bool() const { return !!m_pObj; }
148   T& operator*() const { return *m_pObj; }
149   T* operator->() const { return m_pObj.get(); }
150 
151  private:
152   std::unique_ptr<T, ReleaseDeleter<T>> m_pObj;
153 };
154 
155 // Trivial implementation - internal ref count with virtual destructor.
156 class Retainable {
157  public:
158   Retainable() = default;
159 
HasOneRef()160   bool HasOneRef() const { return m_nRefCount == 1; }
161 
162  protected:
163   virtual ~Retainable() = default;
164 
165  private:
166   template <typename U>
167   friend struct ReleaseDeleter;
168 
169   template <typename U>
170   friend class RetainPtr;
171 
172   Retainable(const Retainable& that) = delete;
173   Retainable& operator=(const Retainable& that) = delete;
174 
175   // These need to be const methods operating on a mutable member so that
176   // RetainPtr<const T> can be used for an object that is otherwise const
177   // apart from the internal ref-counting.
Retain()178   void Retain() const {
179     ++m_nRefCount;
180     CHECK(m_nRefCount > 0);
181   }
Release()182   void Release() const {
183     CHECK(m_nRefCount > 0);
184     if (--m_nRefCount == 0)
185       delete this;
186   }
187 
188   mutable uintptr_t m_nRefCount = 0;
189   static_assert(std::is_unsigned<decltype(m_nRefCount)>::value,
190                 "m_nRefCount must be an unsigned type for overflow check"
191                 "to work properly in Retain()");
192 };
193 
194 }  // namespace fxcrt
195 
196 using fxcrt::ReleaseDeleter;
197 using fxcrt::Retainable;
198 using fxcrt::RetainPtr;
199 
200 namespace pdfium {
201 
202 // Helper to make a RetainPtr along the lines of std::make_unique<>().
203 // Arguments are forwarded to T's constructor. Classes managed by RetainPtr
204 // should have protected (or private) constructors, and should friend this
205 // function.
206 template <typename T, typename... Args>
MakeRetain(Args &&...args)207 RetainPtr<T> MakeRetain(Args&&... args) {
208   return RetainPtr<T>(new T(std::forward<Args>(args)...));
209 }
210 
211 // Type-deducing wrapper to make a RetainPtr from an ordinary pointer,
212 // since equivalent constructor is explicit.
213 template <typename T>
WrapRetain(T * that)214 RetainPtr<T> WrapRetain(T* that) {
215   return RetainPtr<T>(that);
216 }
217 
218 }  // namespace pdfium
219 
220 // Macro to allow construction via MakeRetain<>() only, when used
221 // with a private constructor in a class.
222 #define CONSTRUCT_VIA_MAKE_RETAIN         \
223   template <typename T, typename... Args> \
224   friend RetainPtr<T> pdfium::MakeRetain(Args&&... args)
225 
226 #endif  // CORE_FXCRT_RETAIN_PTR_H_
227