/src/trafficserver/include/tscore/Ptr.h
Line | Count | Source |
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 <atomic> |
27 | | #include <cstddef> |
28 | | |
29 | | //////////////////////////////////////////////////////////////////// |
30 | | //////////////////////////////////////////////////////////////////// |
31 | | ////// ATOMIC VERSIONS |
32 | | //////////////////////////////////////////////////////////////////// |
33 | | //////////////////////////////////////////////////////////////////// |
34 | | |
35 | | struct ForceVFPTToTop { |
36 | 0 | virtual ~ForceVFPTToTop() {} |
37 | | }; |
38 | | |
39 | | //////////////////////////////////////////////////////////////////////// |
40 | | // |
41 | | // class RefCountObj |
42 | | // prototypical class for reference counting |
43 | | // not necessarily allocated with new |
44 | | // |
45 | | //////////////////////////////////////////////////////////////////////// |
46 | | class RefCountObj : public ForceVFPTToTop |
47 | | { |
48 | | public: |
49 | 14.6k | RefCountObj() {} |
50 | | RefCountObj(const RefCountObj &) = delete; |
51 | 0 | ~RefCountObj() override {} |
52 | | |
53 | | RefCountObj &operator=(const RefCountObj &) = delete; |
54 | | |
55 | | // Increment the reference count, returning the new count. |
56 | | int |
57 | | refcount_inc() |
58 | 14.6k | { |
59 | 14.6k | return ++m_refcount; |
60 | 14.6k | } |
61 | | |
62 | | // Decrement the reference count, returning the new count. |
63 | | int |
64 | | refcount_dec() |
65 | 14.6k | { |
66 | 14.6k | return --m_refcount; |
67 | 14.6k | } |
68 | | |
69 | | int |
70 | | refcount() const |
71 | 14.6k | { |
72 | 14.6k | return m_refcount; |
73 | 14.6k | } |
74 | | |
75 | | virtual void free() = 0; |
76 | | |
77 | | private: |
78 | | std::atomic<int> m_refcount = 0; |
79 | | }; |
80 | | |
81 | | //////////////////////////////////////////////////////////////////////// |
82 | | // |
83 | | // class RefCountObjInHeap |
84 | | // reference counted object allocated with new |
85 | | // |
86 | | //////////////////////////////////////////////////////////////////////// |
87 | | class RefCountObjInHeap : public RefCountObj |
88 | | { |
89 | | public: |
90 | | void |
91 | | free() override |
92 | 0 | { |
93 | 0 | delete this; |
94 | 0 | } |
95 | | }; |
96 | | |
97 | | //////////////////////////////////////////////////////////////////////// |
98 | | // |
99 | | // class Ptr |
100 | | // |
101 | | //////////////////////////////////////////////////////////////////////// |
102 | | template <class T> class Ptr |
103 | | { |
104 | | public: |
105 | | explicit Ptr(T *p = nullptr); |
106 | | Ptr(const Ptr<T> &); |
107 | | Ptr(Ptr<T> &&); |
108 | | ~Ptr(); |
109 | | |
110 | | void clear(); |
111 | | Ptr<T> &operator=(const Ptr<T> &); |
112 | | Ptr<T> &operator=(Ptr<T> &&); |
113 | | Ptr<T> &operator=(T *); |
114 | | |
115 | | T * |
116 | | operator->() const |
117 | 95.2k | { |
118 | 95.2k | return (m_ptr); |
119 | 95.2k | } Unexecuted instantiation: Ptr<IOBufferData>::operator->() const Unexecuted instantiation: Ptr<IOBufferBlock>::operator->() const Unexecuted instantiation: Ptr<ProxyMutex>::operator->() const Ptr<HdrStrHeap>::operator->() const Line | Count | Source | 117 | 95.2k | { | 118 | 95.2k | return (m_ptr); | 119 | 95.2k | } |
|
120 | | T & |
121 | | operator*() const |
122 | | { |
123 | | return (*m_ptr); |
124 | | } |
125 | | |
126 | | // Making this explicit avoids unwanted conversions. See https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Safe_bool . |
127 | | explicit |
128 | | operator bool() const |
129 | 109k | { |
130 | 109k | return m_ptr != nullptr; |
131 | 109k | } Unexecuted instantiation: Ptr<IOBufferBlock>::operator bool() const Unexecuted instantiation: Ptr<ProxyMutex>::operator bool() const Ptr<HdrStrHeap>::operator bool() const Line | Count | Source | 129 | 109k | { | 130 | 109k | return m_ptr != nullptr; | 131 | 109k | } |
|
132 | | |
133 | | bool |
134 | | operator==(const T *p) |
135 | 0 | { |
136 | 0 | return (m_ptr == p); |
137 | 0 | } |
138 | | |
139 | | bool |
140 | | operator==(const Ptr<T> &p) const |
141 | | { |
142 | | return (m_ptr == p.m_ptr); |
143 | | } |
144 | | |
145 | | bool |
146 | | operator!=(const T *p) |
147 | 0 | { |
148 | 0 | return (m_ptr != p); |
149 | 0 | } |
150 | | |
151 | | bool |
152 | | operator!=(const Ptr<T> &p) |
153 | | { |
154 | | return (m_ptr != p.m_ptr); |
155 | | } |
156 | | |
157 | | // Return the raw pointer. |
158 | | T * |
159 | | get() const |
160 | 0 | { |
161 | 0 | return m_ptr; |
162 | 0 | } Unexecuted instantiation: Ptr<IOBufferBlock>::get() const Unexecuted instantiation: Ptr<IOBufferData>::get() const Unexecuted instantiation: Ptr<ProxyMutex>::get() const Unexecuted instantiation: Ptr<HdrStrHeap>::get() const Unexecuted instantiation: Ptr<RefCountObj>::get() const |
163 | | |
164 | | // Return the raw pointer as a RefCount object. Typically |
165 | | // this is for keeping a collection of ogenous objects. |
166 | | RefCountObj * |
167 | | object() const |
168 | 0 | { |
169 | 0 | return static_cast<RefCountObj *>(m_ptr); |
170 | 0 | } Unexecuted instantiation: Ptr<RefCountObj>::object() const Unexecuted instantiation: Ptr<HdrStrHeap>::object() const |
171 | | |
172 | | // Return the stored pointer, storing NULL instead. Do not increment |
173 | | // the refcount; the caller is now responsible for owning the RefCountObj. |
174 | | T * |
175 | | detach() |
176 | 75.2k | { |
177 | 75.2k | T *tmp = m_ptr; |
178 | 75.2k | m_ptr = nullptr; |
179 | 75.2k | return tmp; |
180 | 75.2k | } Unexecuted instantiation: Ptr<IOBufferBlock>::detach() Ptr<HdrStrHeap>::detach() Line | Count | Source | 176 | 18.8k | { | 177 | 18.8k | T *tmp = m_ptr; | 178 | 18.8k | m_ptr = nullptr; | 179 | 18.8k | return tmp; | 180 | 18.8k | } |
Ptr<RefCountObj>::detach() Line | Count | Source | 176 | 56.4k | { | 177 | 56.4k | T *tmp = m_ptr; | 178 | 56.4k | m_ptr = nullptr; | 179 | 56.4k | return tmp; | 180 | 56.4k | } |
|
181 | | |
182 | | // XXX Clearly this is not safe. This is used in HdrHeap::unmarshal() to swizzle |
183 | | // the refcount of the managed heap pointers. That code needs to be cleaned up |
184 | | // so that this can be removed. Do not use this in new code. |
185 | | void |
186 | | swizzle(RefCountObj *ptr) |
187 | 0 | { |
188 | 0 | m_ptr = ptr; |
189 | 0 | } |
190 | | |
191 | | private: |
192 | | T *m_ptr; |
193 | | }; |
194 | | |
195 | | template <typename T> |
196 | | Ptr<T> |
197 | | make_ptr(T *p) |
198 | 0 | { |
199 | 0 | return Ptr<T>(p); |
200 | 0 | } |
201 | | |
202 | | //////////////////////////////////////////////////////////////////////// |
203 | | // |
204 | | // inline functions definitions |
205 | | // |
206 | | //////////////////////////////////////////////////////////////////////// |
207 | 54.9k | template <class T> inline Ptr<T>::Ptr(T *ptr /* = 0 */) : m_ptr(ptr) |
208 | 54.9k | { |
209 | 54.9k | if (m_ptr) { |
210 | 0 | m_ptr->refcount_inc(); |
211 | 0 | } |
212 | 54.9k | } Unexecuted instantiation: Ptr<IOBufferBlock>::Ptr(IOBufferBlock*) Unexecuted instantiation: Ptr<IOBufferData>::Ptr(IOBufferData*) Ptr<ProxyMutex>::Ptr(ProxyMutex*) Line | Count | Source | 207 | 12 | template <class T> inline Ptr<T>::Ptr(T *ptr /* = 0 */) : m_ptr(ptr) | 208 | 12 | { | 209 | 12 | if (m_ptr) { | 210 | 0 | m_ptr->refcount_inc(); | 211 | 0 | } | 212 | 12 | } |
Ptr<RefCountObj>::Ptr(RefCountObj*) Line | Count | Source | 207 | 54.9k | template <class T> inline Ptr<T>::Ptr(T *ptr /* = 0 */) : m_ptr(ptr) | 208 | 54.9k | { | 209 | 54.9k | if (m_ptr) { | 210 | 0 | m_ptr->refcount_inc(); | 211 | 0 | } | 212 | 54.9k | } |
|
213 | | |
214 | 0 | template <class T> inline Ptr<T>::Ptr(const Ptr<T> &src) : m_ptr(src.m_ptr) |
215 | 0 | { |
216 | 0 | if (m_ptr) { |
217 | 0 | m_ptr->refcount_inc(); |
218 | 0 | } |
219 | 0 | } Unexecuted instantiation: Ptr<IOBufferBlock>::Ptr(Ptr<IOBufferBlock> const&) Unexecuted instantiation: Ptr<ProxyMutex>::Ptr(Ptr<ProxyMutex> const&) |
220 | | |
221 | | template <class T> inline Ptr<T>::Ptr(Ptr<T> &&src) : m_ptr(src.m_ptr) |
222 | | { |
223 | | src.m_ptr = nullptr; |
224 | | } |
225 | | |
226 | | template <class T> inline Ptr<T>::~Ptr() |
227 | 54.9k | { |
228 | 54.9k | if (m_ptr && m_ptr->refcount_dec() == 0) { |
229 | 0 | m_ptr->free(); |
230 | 0 | } |
231 | 54.9k | } Unexecuted instantiation: Ptr<IOBufferBlock>::~Ptr() Unexecuted instantiation: Ptr<IOBufferData>::~Ptr() Unexecuted instantiation: Ptr<ProxyMutex>::~Ptr() Line | Count | Source | 227 | 54.9k | { | 228 | 54.9k | if (m_ptr && m_ptr->refcount_dec() == 0) { | 229 | 0 | m_ptr->free(); | 230 | 0 | } | 231 | 54.9k | } |
|
232 | | |
233 | | template <class T> |
234 | | inline Ptr<T> & |
235 | | Ptr<T>::operator=(T *p) |
236 | 89.9k | { |
237 | 89.9k | T *temp_ptr = m_ptr; |
238 | | |
239 | 89.9k | if (m_ptr == p) { |
240 | 60.6k | return (*this); |
241 | 60.6k | } |
242 | | |
243 | 29.3k | m_ptr = p; |
244 | | |
245 | 29.3k | if (m_ptr) { |
246 | 14.6k | m_ptr->refcount_inc(); |
247 | 14.6k | } |
248 | | |
249 | 29.3k | if (temp_ptr && temp_ptr->refcount_dec() == 0) { |
250 | 14.6k | temp_ptr->free(); |
251 | 14.6k | } |
252 | | |
253 | 29.3k | return (*this); |
254 | 89.9k | } Unexecuted instantiation: Ptr<IOBufferBlock>::operator=(IOBufferBlock*) Unexecuted instantiation: Ptr<ProxyMutex>::operator=(ProxyMutex*) Unexecuted instantiation: Ptr<IOBufferData>::operator=(IOBufferData*) Ptr<RefCountObj>::operator=(RefCountObj*) Line | Count | Source | 236 | 56.4k | { | 237 | 56.4k | T *temp_ptr = m_ptr; | 238 | | | 239 | 56.4k | if (m_ptr == p) { | 240 | 56.4k | return (*this); | 241 | 56.4k | } | 242 | | | 243 | 0 | m_ptr = p; | 244 | |
| 245 | 0 | if (m_ptr) { | 246 | 0 | m_ptr->refcount_inc(); | 247 | 0 | } | 248 | |
| 249 | 0 | if (temp_ptr && temp_ptr->refcount_dec() == 0) { | 250 | 0 | temp_ptr->free(); | 251 | 0 | } | 252 | |
| 253 | 0 | return (*this); | 254 | 56.4k | } |
Ptr<HdrStrHeap>::operator=(HdrStrHeap*) Line | Count | Source | 236 | 33.4k | { | 237 | 33.4k | T *temp_ptr = m_ptr; | 238 | | | 239 | 33.4k | if (m_ptr == p) { | 240 | 4.16k | return (*this); | 241 | 4.16k | } | 242 | | | 243 | 29.3k | m_ptr = p; | 244 | | | 245 | 29.3k | if (m_ptr) { | 246 | 14.6k | m_ptr->refcount_inc(); | 247 | 14.6k | } | 248 | | | 249 | 29.3k | if (temp_ptr && temp_ptr->refcount_dec() == 0) { | 250 | 14.6k | temp_ptr->free(); | 251 | 14.6k | } | 252 | | | 253 | 29.3k | return (*this); | 254 | 33.4k | } |
|
255 | | |
256 | | template <class T> |
257 | | inline void |
258 | | Ptr<T>::clear() |
259 | | { |
260 | | if (m_ptr) { |
261 | | if (!m_ptr->refcount_dec()) { |
262 | | m_ptr->free(); |
263 | | } |
264 | | m_ptr = nullptr; |
265 | | } |
266 | | } |
267 | | |
268 | | template <class T> |
269 | | inline Ptr<T> & |
270 | | Ptr<T>::operator=(const Ptr<T> &src) |
271 | 0 | { |
272 | 0 | return (operator=(src.m_ptr)); |
273 | 0 | } Unexecuted instantiation: Ptr<IOBufferBlock>::operator=(Ptr<IOBufferBlock> const&) Unexecuted instantiation: Ptr<ProxyMutex>::operator=(Ptr<ProxyMutex> const&) Unexecuted instantiation: Ptr<IOBufferData>::operator=(Ptr<IOBufferData> const&) Unexecuted instantiation: Ptr<RefCountObj>::operator=(Ptr<RefCountObj> const&) |
274 | | |
275 | | template <class T> |
276 | | inline Ptr<T> & |
277 | | Ptr<T>::operator=(Ptr<T> &&src) |
278 | 0 | { |
279 | 0 | if (this != &src) { |
280 | 0 | this->~Ptr(); |
281 | 0 | m_ptr = src.m_ptr; |
282 | 0 | src.m_ptr = nullptr; |
283 | 0 | } |
284 | 0 | return *this; |
285 | 0 | } Unexecuted instantiation: Ptr<ProxyMutex>::operator=(Ptr<ProxyMutex>&&) Unexecuted instantiation: Ptr<IOBufferBlock>::operator=(Ptr<IOBufferBlock>&&) |
286 | | |
287 | | // Bit of subtly here for the flipped version of equality checks |
288 | | // With only the template versions, the compiler will try to substitute @c nullptr_t |
289 | | // for @c T and fail, because that's not the type and no operator will be found. |
290 | | // Therefore there needs to be specific overrides for @c nullptr_t. |
291 | | |
292 | | template <typename T> |
293 | | inline bool |
294 | | operator==(std::nullptr_t, Ptr<T> const &rhs) |
295 | | { |
296 | | return rhs.get() == nullptr; |
297 | | } |
298 | | |
299 | | template <typename T> |
300 | | inline bool |
301 | | operator!=(std::nullptr_t, Ptr<T> const &rhs) |
302 | | { |
303 | | return rhs.get() != nullptr; |
304 | | } |
305 | | |
306 | | template <typename T> |
307 | | inline bool |
308 | | operator==(T const *lhs, Ptr<T> const &rhs) |
309 | | { |
310 | | return rhs.get() == lhs; |
311 | | } |
312 | | |
313 | | template <typename T> |
314 | | inline bool |
315 | | operator!=(T const *lhs, Ptr<T> const &rhs) |
316 | | { |
317 | | return rhs.get() != lhs; |
318 | | } |