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