Coverage Report

Created: 2026-03-28 06:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
15.2k
  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
15.6k
  {
59
15.6k
    return ++m_refcount;
60
15.6k
  }
61
62
  // Decrement the reference count, returning the new count.
63
  int
64
  refcount_dec()
65
15.6k
  {
66
15.6k
    return --m_refcount;
67
15.6k
  }
68
69
  int
70
  refcount() const
71
14.7k
  {
72
14.7k
    return m_refcount;
73
14.7k
  }
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
96.8k
  {
118
96.8k
    return (m_ptr);
119
96.8k
  }
Ptr<IOBufferData>::operator->() const
Line
Count
Source
117
720
  {
118
720
    return (m_ptr);
119
720
  }
Ptr<IOBufferBlock>::operator->() const
Line
Count
Source
117
1.95k
  {
118
1.95k
    return (m_ptr);
119
1.95k
  }
Ptr<ProxyMutex>::operator->() const
Line
Count
Source
117
2
  {
118
2
    return (m_ptr);
119
2
  }
Ptr<HdrStrHeap>::operator->() const
Line
Count
Source
117
94.1k
  {
118
94.1k
    return (m_ptr);
119
94.1k
  }
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
  }
Ptr<IOBufferBlock>::operator bool() const
Line
Count
Source
129
875
  {
130
875
    return m_ptr != nullptr;
131
875
  }
Ptr<ProxyMutex>::operator bool() const
Line
Count
Source
129
3
  {
130
3
    return m_ptr != nullptr;
131
3
  }
Ptr<HdrStrHeap>::operator bool() const
Line
Count
Source
129
108k
  {
130
108k
    return m_ptr != nullptr;
131
108k
  }
132
133
  bool
134
  operator==(const T *p)
135
182
  {
136
182
    return (m_ptr == p);
137
182
  }
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
1.30k
  {
161
1.30k
    return m_ptr;
162
1.30k
  }
Ptr<IOBufferBlock>::get() const
Line
Count
Source
160
1.30k
  {
161
1.30k
    return m_ptr;
162
1.30k
  }
Unexecuted instantiation: Ptr<IOBufferData>::get() const
Ptr<ProxyMutex>::get() const
Line
Count
Source
160
3
  {
161
3
    return m_ptr;
162
3
  }
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.7k
  {
177
75.7k
    T *tmp = m_ptr;
178
75.7k
    m_ptr  = nullptr;
179
75.7k
    return tmp;
180
75.7k
  }
Ptr<IOBufferBlock>::detach()
Line
Count
Source
176
240
  {
177
240
    T *tmp = m_ptr;
178
240
    m_ptr  = nullptr;
179
240
    return tmp;
180
240
  }
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.6k
  {
177
56.6k
    T *tmp = m_ptr;
178
56.6k
    m_ptr  = nullptr;
179
56.6k
    return tmp;
180
56.6k
  }
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
55.8k
template <class T> inline Ptr<T>::Ptr(T *ptr /* = 0 */) : m_ptr(ptr)
208
55.8k
{
209
55.8k
  if (m_ptr) {
210
0
    m_ptr->refcount_inc();
211
0
  }
212
55.8k
}
Ptr<IOBufferBlock>::Ptr(IOBufferBlock*)
Line
Count
Source
207
1.15k
template <class T> inline Ptr<T>::Ptr(T *ptr /* = 0 */) : m_ptr(ptr)
208
1.15k
{
209
1.15k
  if (m_ptr) {
210
0
    m_ptr->refcount_inc();
211
0
  }
212
1.15k
}
Ptr<IOBufferData>::Ptr(IOBufferData*)
Line
Count
Source
207
240
template <class T> inline Ptr<T>::Ptr(T *ptr /* = 0 */) : m_ptr(ptr)
208
240
{
209
240
  if (m_ptr) {
210
0
    m_ptr->refcount_inc();
211
0
  }
212
240
}
Ptr<ProxyMutex>::Ptr(ProxyMutex*)
Line
Count
Source
207
27
template <class T> inline Ptr<T>::Ptr(T *ptr /* = 0 */) : m_ptr(ptr)
208
27
{
209
27
  if (m_ptr) {
210
0
    m_ptr->refcount_inc();
211
0
  }
212
27
}
Ptr<RefCountObj>::Ptr(RefCountObj*)
Line
Count
Source
207
54.4k
template <class T> inline Ptr<T>::Ptr(T *ptr /* = 0 */) : m_ptr(ptr)
208
54.4k
{
209
54.4k
  if (m_ptr) {
210
0
    m_ptr->refcount_inc();
211
0
  }
212
54.4k
}
213
214
1
template <class T> inline Ptr<T>::Ptr(const Ptr<T> &src) : m_ptr(src.m_ptr)
215
1
{
216
1
  if (m_ptr) {
217
1
    m_ptr->refcount_inc();
218
1
  }
219
1
}
Unexecuted instantiation: Ptr<IOBufferBlock>::Ptr(Ptr<IOBufferBlock> const&)
Ptr<ProxyMutex>::Ptr(Ptr<ProxyMutex> const&)
Line
Count
Source
214
1
template <class T> inline Ptr<T>::Ptr(const Ptr<T> &src) : m_ptr(src.m_ptr)
215
1
{
216
1
  if (m_ptr) {
217
1
    m_ptr->refcount_inc();
218
1
  }
219
1
}
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.4k
{
228
54.4k
  if (m_ptr && m_ptr->refcount_dec() == 0) {
229
0
    m_ptr->free();
230
0
  }
231
54.4k
}
Ptr<IOBufferBlock>::~Ptr()
Line
Count
Source
227
10
{
228
10
  if (m_ptr && m_ptr->refcount_dec() == 0) {
229
0
    m_ptr->free();
230
0
  }
231
10
}
Unexecuted instantiation: Ptr<IOBufferData>::~Ptr()
Ptr<ProxyMutex>::~Ptr()
Line
Count
Source
227
2
{
228
2
  if (m_ptr && m_ptr->refcount_dec() == 0) {
229
0
    m_ptr->free();
230
0
  }
231
2
}
Ptr<RefCountObj>::~Ptr()
Line
Count
Source
227
54.4k
{
228
54.4k
  if (m_ptr && m_ptr->refcount_dec() == 0) {
229
0
    m_ptr->free();
230
0
  }
231
54.4k
}
232
233
template <class T>
234
inline Ptr<T> &
235
Ptr<T>::operator=(T *p)
236
91.8k
{
237
91.8k
  T *temp_ptr = m_ptr;
238
239
91.8k
  if (m_ptr == p) {
240
61.0k
    return (*this);
241
61.0k
  }
242
243
30.7k
  m_ptr = p;
244
245
30.7k
  if (m_ptr) {
246
15.4k
    m_ptr->refcount_inc();
247
15.4k
  }
248
249
30.7k
  if (temp_ptr && temp_ptr->refcount_dec() == 0) {
250
15.2k
    temp_ptr->free();
251
15.2k
  }
252
253
30.7k
  return (*this);
254
91.8k
}
Ptr<IOBufferBlock>::operator=(IOBufferBlock*)
Line
Count
Source
236
1.07k
{
237
1.07k
  T *temp_ptr = m_ptr;
238
239
1.07k
  if (m_ptr == p) {
240
298
    return (*this);
241
298
  }
242
243
778
  m_ptr = p;
244
245
778
  if (m_ptr) {
246
480
    m_ptr->refcount_inc();
247
480
  }
248
249
778
  if (temp_ptr && temp_ptr->refcount_dec() == 0) {
250
240
    temp_ptr->free();
251
240
  }
252
253
778
  return (*this);
254
1.07k
}
Ptr<ProxyMutex>::operator=(ProxyMutex*)
Line
Count
Source
236
9
{
237
9
  T *temp_ptr = m_ptr;
238
239
9
  if (m_ptr == p) {
240
6
    return (*this);
241
6
  }
242
243
3
  m_ptr = p;
244
245
3
  if (m_ptr) {
246
2
    m_ptr->refcount_inc();
247
2
  }
248
249
3
  if (temp_ptr && temp_ptr->refcount_dec() == 0) {
250
0
    temp_ptr->free();
251
0
  }
252
253
3
  return (*this);
254
9
}
Ptr<IOBufferData>::operator=(IOBufferData*)
Line
Count
Source
236
480
{
237
480
  T *temp_ptr = m_ptr;
238
239
480
  if (m_ptr == p) {
240
0
    return (*this);
241
0
  }
242
243
480
  m_ptr = p;
244
245
480
  if (m_ptr) {
246
240
    m_ptr->refcount_inc();
247
240
  }
248
249
480
  if (temp_ptr && temp_ptr->refcount_dec() == 0) {
250
240
    temp_ptr->free();
251
240
  }
252
253
480
  return (*this);
254
480
}
Ptr<RefCountObj>::operator=(RefCountObj*)
Line
Count
Source
236
56.6k
{
237
56.6k
  T *temp_ptr = m_ptr;
238
239
56.6k
  if (m_ptr == p) {
240
56.6k
    return (*this);
241
56.6k
  }
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.6k
}
Ptr<HdrStrHeap>::operator=(HdrStrHeap*)
Line
Count
Source
236
33.6k
{
237
33.6k
  T *temp_ptr = m_ptr;
238
239
33.6k
  if (m_ptr == p) {
240
4.12k
    return (*this);
241
4.12k
  }
242
243
29.5k
  m_ptr = p;
244
245
29.5k
  if (m_ptr) {
246
14.7k
    m_ptr->refcount_inc();
247
14.7k
  }
248
249
29.5k
  if (temp_ptr && temp_ptr->refcount_dec() == 0) {
250
14.7k
    temp_ptr->free();
251
14.7k
  }
252
253
29.5k
  return (*this);
254
33.6k
}
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
245
{
272
245
  return (operator=(src.m_ptr));
273
245
}
Ptr<IOBufferBlock>::operator=(Ptr<IOBufferBlock> const&)
Line
Count
Source
271
240
{
272
240
  return (operator=(src.m_ptr));
273
240
}
Ptr<ProxyMutex>::operator=(Ptr<ProxyMutex> const&)
Line
Count
Source
271
5
{
272
5
  return (operator=(src.m_ptr));
273
5
}
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
}