1 /** @file
2
3 Reference-counting shared pointer, like std::shared_ptr.
4
5 @section license License
6
7 Licensed to the Apache Software Foundation (ASF) under one
8 or more contributor license agreements. See the NOTICE file
9 distributed with this work for additional information
10 regarding copyright ownership. The ASF licenses this file
11 to you under the Apache License, Version 2.0 (the
12 "License"); you may not use this file except in compliance
13 with the License. You may obtain a copy of the License at
14
15 http://www.apache.org/licenses/LICENSE-2.0
16
17 Unless required by applicable law or agreed to in writing, software
18 distributed under the License is distributed on an "AS IS" BASIS,
19 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 See the License for the specific language governing permissions and
21 limitations under the License.
22 */
23
24 #pragma once
25
26 #include "tscore/ink_atomic.h"
27
28 ////////////////////////////////////////////////////////////////////
29 ////////////////////////////////////////////////////////////////////
30 ////// ATOMIC VERSIONS
31 ////////////////////////////////////////////////////////////////////
32 ////////////////////////////////////////////////////////////////////
33
34 struct ForceVFPTToTop {
~ForceVFPTToTopForceVFPTToTop35 virtual ~ForceVFPTToTop() {}
36 };
37
38 ////////////////////////////////////////////////////////////////////////
39 //
40 // class RefCountObj
41 // prototypical class for reference counting
42 //
43 ////////////////////////////////////////////////////////////////////////
44 class RefCountObj : public ForceVFPTToTop
45 {
46 public:
RefCountObj()47 RefCountObj() {}
RefCountObj(const RefCountObj & s)48 RefCountObj(const RefCountObj &s)
49 {
50 (void)s;
51 return;
52 }
53
~RefCountObj()54 ~RefCountObj() override {}
55 RefCountObj &
56 operator=(const RefCountObj &s)
57 {
58 (void)s;
59 return (*this);
60 }
61
62 // Increment the reference count, returning the new count.
63 int
refcount_inc()64 refcount_inc()
65 {
66 return ink_atomic_increment((int *)&m_refcount, 1) + 1;
67 }
68
69 // Decrement the reference count, returning the new count.
70 int
refcount_dec()71 refcount_dec()
72 {
73 return ink_atomic_increment((int *)&m_refcount, -1) - 1;
74 }
75
76 int
refcount()77 refcount() const
78 {
79 return m_refcount;
80 }
81
82 virtual void
free()83 free()
84 {
85 delete this;
86 }
87
88 private:
89 int m_refcount = 0;
90 };
91
92 ////////////////////////////////////////////////////////////////////////
93 //
94 // class Ptr
95 //
96 ////////////////////////////////////////////////////////////////////////
97 template <class T> class Ptr
98 {
99 public:
100 explicit Ptr(T *p = nullptr);
101 Ptr(const Ptr<T> &);
102 ~Ptr();
103
104 void clear();
105 Ptr<T> &operator=(const Ptr<T> &);
106 Ptr<T> &operator=(T *);
107
108 T *
109 operator->() const
110 {
111 return (m_ptr);
112 }
113 T &
114 operator*() const
115 {
116 return (*m_ptr);
117 }
118
119 // Making this explicit avoids unwanted conversions. See https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Safe_bool .
120 explicit operator bool() const { return m_ptr != nullptr; }
121
122 int
123 operator==(const T *p)
124 {
125 return (m_ptr == p);
126 }
127
128 int
129 operator==(const Ptr<T> &p)
130 {
131 return (m_ptr == p.m_ptr);
132 }
133
134 int
135 operator!=(const T *p)
136 {
137 return (m_ptr != p);
138 }
139
140 int
141 operator!=(const Ptr<T> &p)
142 {
143 return (m_ptr != p.m_ptr);
144 }
145
146 // Return the raw pointer.
147 T *
get()148 get() const
149 {
150 return m_ptr;
151 }
152
153 // Return the raw pointer as a RefCount object. Typically
154 // this is for keeping a collection of ogenous objects.
155 RefCountObj *
object()156 object() const
157 {
158 return static_cast<RefCountObj *>(m_ptr);
159 }
160
161 // Return the stored pointer, storing NULL instead. Do not increment
162 // the refcount; the caller is now responsible for owning the RefCountObj.
163 T *
detach()164 detach()
165 {
166 T *tmp = m_ptr;
167 m_ptr = nullptr;
168 return tmp;
169 }
170
171 // XXX Clearly this is not safe. This is used in HdrHeap::unmarshal() to swizzle
172 // the refcount of the managed heap pointers. That code needs to be cleaned up
173 // so that this can be removed. Do not use this in new code.
174 void
swizzle(RefCountObj * ptr)175 swizzle(RefCountObj *ptr)
176 {
177 m_ptr = ptr;
178 }
179
180 private:
181 T *m_ptr;
182
183 friend class CoreUtils;
184 };
185
186 template <typename T>
187 Ptr<T>
make_ptr(T * p)188 make_ptr(T *p)
189 {
190 return Ptr<T>(p);
191 }
192
193 ////////////////////////////////////////////////////////////////////////
194 //
195 // inline functions definitions
196 //
197 ////////////////////////////////////////////////////////////////////////
Ptr(T * ptr)198 template <class T> inline Ptr<T>::Ptr(T *ptr /* = 0 */) : m_ptr(ptr)
199 {
200 if (m_ptr) {
201 m_ptr->refcount_inc();
202 }
203 }
204
Ptr(const Ptr<T> & src)205 template <class T> inline Ptr<T>::Ptr(const Ptr<T> &src) : m_ptr(src.m_ptr)
206 {
207 if (m_ptr) {
208 m_ptr->refcount_inc();
209 }
210 }
211
~Ptr()212 template <class T> inline Ptr<T>::~Ptr()
213 {
214 if (m_ptr && m_ptr->refcount_dec() == 0) {
215 m_ptr->free();
216 }
217 }
218
219 template <class T>
220 inline Ptr<T> &
221 Ptr<T>::operator=(T *p)
222 {
223 T *temp_ptr = m_ptr;
224
225 if (m_ptr == p) {
226 return (*this);
227 }
228
229 m_ptr = p;
230
231 if (m_ptr) {
232 m_ptr->refcount_inc();
233 }
234
235 if (temp_ptr && temp_ptr->refcount_dec() == 0) {
236 temp_ptr->free();
237 }
238
239 return (*this);
240 }
241
242 template <class T>
243 inline void
clear()244 Ptr<T>::clear()
245 {
246 if (m_ptr) {
247 if (!m_ptr->refcount_dec())
248 m_ptr->free();
249 m_ptr = nullptr;
250 }
251 }
252
253 template <class T>
254 inline Ptr<T> &
255 Ptr<T>::operator=(const Ptr<T> &src)
256 {
257 return (operator=(src.m_ptr));
258 }
259
260 // Bit of subtly here for the flipped version of equality checks
261 // With only the template versions, the compiler will try to substitute @c nullptr_t
262 // for @c T and fail, because that's not the type and no operator will be found.
263 // Therefore there needs to be specific overrides for @c nullptr_t.
264
265 template <typename T>
266 inline bool
267 operator==(std::nullptr_t, Ptr<T> const &rhs)
268 {
269 return rhs.get() == nullptr;
270 }
271
272 template <typename T>
273 inline bool
274 operator!=(std::nullptr_t, Ptr<T> const &rhs)
275 {
276 return rhs.get() != nullptr;
277 }
278
279 template <typename T>
280 inline bool
281 operator==(T const *lhs, Ptr<T> const &rhs)
282 {
283 return rhs.get() == lhs;
284 }
285
286 template <typename T>
287 inline bool
288 operator!=(T const *lhs, Ptr<T> const &rhs)
289 {
290 return rhs.get() != lhs;
291 }
292