Coverage Report

Created: 2026-02-10 06:42

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
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()
Ptr<RefCountObj>::~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
}