Coverage Report

Created: 2024-11-21 12:31

/root/doris/be/src/gutil/ref_counted.h
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2
// Use of this source code is governed by a BSD-style license that can be
3
// found in the LICENSE file.
4
5
#pragma once
6
7
#include <cassert>
8
#include <cstddef>
9
#include <utility> // IWYU pragma: keep
10
11
#include "gutil/atomicops.h"
12
// IWYU pragma: no_include <butil/macros.h>
13
#include "gutil/macros.h" // IWYU pragma: keep
14
#include "gutil/threading/thread_collision_warner.h"
15
16
namespace doris {
17
namespace subtle {
18
19
typedef Atomic32 AtomicRefCount;
20
21
class RefCountedBase {
22
public:
23
0
    bool HasOneRef() const { return ref_count_ == 1; }
24
25
protected:
26
    RefCountedBase();
27
    ~RefCountedBase();
28
29
    void AddRef() const;
30
31
    // Returns true if the object should self-delete.
32
    bool Release() const;
33
34
private:
35
    mutable int ref_count_;
36
#ifndef NDEBUG
37
    mutable bool in_dtor_;
38
#endif
39
40
    DFAKE_MUTEX(add_release_);
41
42
    DISALLOW_COPY_AND_ASSIGN(RefCountedBase);
43
};
44
45
class RefCountedThreadSafeBase {
46
public:
47
    bool HasOneRef() const;
48
49
protected:
50
    RefCountedThreadSafeBase();
51
    ~RefCountedThreadSafeBase();
52
53
    void AddRef() const;
54
55
    // Returns true if the object should self-delete.
56
    bool Release() const;
57
58
private:
59
    mutable AtomicRefCount ref_count_;
60
#ifndef NDEBUG
61
    mutable bool in_dtor_;
62
#endif
63
64
    DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafeBase);
65
};
66
67
} // namespace subtle
68
69
//
70
// A base class for reference counted classes.  Otherwise, known as a cheap
71
// knock-off of WebKit's RefCounted<T> class.  To use this guy just extend your
72
// class from it like so:
73
//
74
//   class MyFoo : public RefCounted<MyFoo> {
75
//    ...
76
//    private:
77
//     friend class RefCounted<MyFoo>;
78
//     ~MyFoo();
79
//   };
80
//
81
// You should always make your destructor private, to avoid any code deleting
82
// the object accidentally while there are references to it.
83
template <class T>
84
class RefCounted : public subtle::RefCountedBase {
85
public:
86
5
    RefCounted() {}
87
88
27
    void AddRef() const { subtle::RefCountedBase::AddRef(); }
89
90
27
    void Release() const {
91
27
        if (subtle::RefCountedBase::Release()) {
92
5
            delete static_cast<const T*>(this);
93
5
        }
94
27
    }
95
96
protected:
97
5
    ~RefCounted() {}
98
};
99
100
// Forward declaration.
101
template <class T, typename Traits>
102
class RefCountedThreadSafe;
103
104
// Default traits for RefCountedThreadSafe<T>.  Deletes the object when its ref
105
// count reaches 0.  Overload to delete it on a different thread etc.
106
template <typename T>
107
struct DefaultRefCountedThreadSafeTraits {
108
2.42k
    static void Destruct(const T* x) {
109
        // Delete through RefCountedThreadSafe to make child classes only need to be
110
        // friend with RefCountedThreadSafe instead of this struct, which is an
111
        // implementation detail.
112
2.42k
        RefCountedThreadSafe<T, DefaultRefCountedThreadSafeTraits>::DeleteInternal(x);
113
2.42k
    }
114
};
115
116
//
117
// A thread-safe variant of RefCounted<T>
118
//
119
//   class MyFoo : public RefCountedThreadSafe<MyFoo> {
120
//    ...
121
//   };
122
//
123
// If you're using the default trait, then you should add compile time
124
// asserts that no one else is deleting your object.  i.e.
125
//    private:
126
//     friend class RefCountedThreadSafe<MyFoo>;
127
//     ~MyFoo();
128
template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T>>
129
class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase {
130
public:
131
2.44k
    RefCountedThreadSafe() {}
132
133
5.91k
    void AddRef() const { subtle::RefCountedThreadSafeBase::AddRef(); }
134
135
5.89k
    void Release() const {
136
5.89k
        if (subtle::RefCountedThreadSafeBase::Release()) {
137
2.42k
            Traits::Destruct(static_cast<const T*>(this));
138
2.42k
        }
139
5.89k
    }
140
141
protected:
142
2.42k
    ~RefCountedThreadSafe() {}
143
144
private:
145
    friend struct DefaultRefCountedThreadSafeTraits<T>;
146
2.42k
    static void DeleteInternal(const T* x) { delete x; }
147
148
    DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafe);
149
};
150
151
//
152
// A thread-safe wrapper for some piece of data so we can place other
153
// things in scoped_refptrs<>.
154
//
155
template <typename T>
156
class RefCountedData : public doris::RefCountedThreadSafe<doris::RefCountedData<T>> {
157
public:
158
    RefCountedData() : data() {}
159
    RefCountedData(const T& in_value) : data(in_value) {}
160
161
    T data;
162
163
private:
164
    friend class doris::RefCountedThreadSafe<doris::RefCountedData<T>>;
165
    ~RefCountedData() {}
166
};
167
168
} // namespace doris
169
170
//
171
// A smart pointer class for reference counted objects.  Use this class instead
172
// of calling AddRef and Release manually on a reference counted object to
173
// avoid common memory leaks caused by forgetting to Release an object
174
// reference.  Sample usage:
175
//
176
//   class MyFoo : public RefCounted<MyFoo> {
177
//    ...
178
//   };
179
//
180
//   void some_function() {
181
//     scoped_refptr<MyFoo> foo = new MyFoo();
182
//     foo->Method(param);
183
//     // |foo| is released when this function returns
184
//   }
185
//
186
//   void some_other_function() {
187
//     scoped_refptr<MyFoo> foo = new MyFoo();
188
//     ...
189
//     foo = NULL;  // explicitly releases |foo|
190
//     ...
191
//     if (foo)
192
//       foo->Method(param);
193
//   }
194
//
195
// The above examples show how scoped_refptr<T> acts like a pointer to T.
196
// Given two scoped_refptr<T> classes, it is also possible to exchange
197
// references between the two objects, like so:
198
//
199
//   {
200
//     scoped_refptr<MyFoo> a = new MyFoo();
201
//     scoped_refptr<MyFoo> b;
202
//
203
//     b.swap(a);
204
//     // now, |b| references the MyFoo object, and |a| references NULL.
205
//   }
206
//
207
// To make both |a| and |b| in the above example reference the same MyFoo
208
// object, simply use the assignment operator:
209
//
210
//   {
211
//     scoped_refptr<MyFoo> a = new MyFoo();
212
//     scoped_refptr<MyFoo> b;
213
//
214
//     b = a;
215
//     // now, |a| and |b| each own a reference to the same MyFoo object.
216
//   }
217
//
218
template <class T>
219
class scoped_refptr {
220
public:
221
    typedef T element_type;
222
223
3.27k
    scoped_refptr() : ptr_(NULL) {}
224
225
2.44k
    scoped_refptr(T* p) : ptr_(p) {
226
2.44k
        if (ptr_) ptr_->AddRef();
227
2.44k
    }
_ZN13scoped_refptrIN5doris8EasyJson17EasyJsonAllocatorEEC2EPS2_
Line
Count
Source
225
5
    scoped_refptr(T* p) : ptr_(p) {
226
5
        if (ptr_) ptr_->AddRef();
227
5
    }
_ZN13scoped_refptrIN5doris6ThreadEEC2EPS1_
Line
Count
Source
225
2.44k
    scoped_refptr(T* p) : ptr_(p) {
226
2.44k
        if (ptr_) ptr_->AddRef();
227
2.44k
    }
228
229
    // Copy constructor.
230
22
    scoped_refptr(const scoped_refptr<T>& r) : ptr_(r.ptr_) {
231
22
        if (ptr_) ptr_->AddRef();
232
22
    }
Unexecuted instantiation: _ZN13scoped_refptrIN5doris6ThreadEEC2ERKS2_
_ZN13scoped_refptrIN5doris8EasyJson17EasyJsonAllocatorEEC2ERKS3_
Line
Count
Source
230
22
    scoped_refptr(const scoped_refptr<T>& r) : ptr_(r.ptr_) {
231
22
        if (ptr_) ptr_->AddRef();
232
22
    }
233
234
    // Copy conversion constructor.
235
    template <typename U>
236
    scoped_refptr(const scoped_refptr<U>& r) : ptr_(r.get()) {
237
        if (ptr_) ptr_->AddRef();
238
    }
239
240
    // Move constructor. This is required in addition to the conversion
241
    // constructor below in order for clang to warn about pessimizing moves.
242
21
    scoped_refptr(scoped_refptr&& r) noexcept : ptr_(r.get()) { // NOLINT
243
21
        r.ptr_ = nullptr;
244
21
    }
_ZN13scoped_refptrIN5doris6ThreadEEC2EOS2_
Line
Count
Source
242
1
    scoped_refptr(scoped_refptr&& r) noexcept : ptr_(r.get()) { // NOLINT
243
1
        r.ptr_ = nullptr;
244
1
    }
_ZN13scoped_refptrIN5doris8EasyJson17EasyJsonAllocatorEEC2EOS3_
Line
Count
Source
242
20
    scoped_refptr(scoped_refptr&& r) noexcept : ptr_(r.get()) { // NOLINT
243
20
        r.ptr_ = nullptr;
244
20
    }
245
246
    // Move conversion constructor.
247
    template <typename U>
248
    scoped_refptr(scoped_refptr<U>&& r) noexcept : ptr_(r.get()) { // NOLINT
249
        r.ptr_ = nullptr;
250
    }
251
252
5.76k
    ~scoped_refptr() {
253
5.76k
        if (ptr_) ptr_->Release();
254
5.76k
    }
_ZN13scoped_refptrIN5doris6ThreadEED2Ev
Line
Count
Source
252
5.72k
    ~scoped_refptr() {
253
5.72k
        if (ptr_) ptr_->Release();
254
5.72k
    }
_ZN13scoped_refptrIN5doris8EasyJson17EasyJsonAllocatorEED2Ev
Line
Count
Source
252
47
    ~scoped_refptr() {
253
47
        if (ptr_) ptr_->Release();
254
47
    }
255
256
2.46k
    T* get() const { return ptr_; }
_ZNK13scoped_refptrIN5doris6ThreadEE3getEv
Line
Count
Source
256
2.44k
    T* get() const { return ptr_; }
_ZNK13scoped_refptrIN5doris8EasyJson17EasyJsonAllocatorEE3getEv
Line
Count
Source
256
20
    T* get() const { return ptr_; }
257
258
// The following is disabled in Kudu's version of this file since it's
259
// relatively dangerous. Chromium is planning on doing the same in their
260
// tree, but hasn't done so yet. See http://code.google.com/p/chromium/issues/detail?id=110610
261
#if SCOPED_REFPTR_ALLOW_IMPLICIT_CONVERSION_TO_PTR
262
    // Allow scoped_refptr<C> to be used in boolean expression
263
    // and comparison operations.
264
    operator T*() const { return ptr_; }
265
#else
266
    typedef T* scoped_refptr::*Testable;
267
1.51k
    operator Testable() const { return ptr_ ? &scoped_refptr::ptr_ : NULL; }
268
#endif
269
270
11.8k
    T* operator->() const {
271
11.8k
        assert(ptr_ != NULL);
272
0
        return ptr_;
273
11.8k
    }
_ZNK13scoped_refptrIN5doris6ThreadEEptEv
Line
Count
Source
270
11.7k
    T* operator->() const {
271
11.7k
        assert(ptr_ != NULL);
272
0
        return ptr_;
273
11.7k
    }
_ZNK13scoped_refptrIN5doris8EasyJson17EasyJsonAllocatorEEptEv
Line
Count
Source
270
28
    T* operator->() const {
271
28
        assert(ptr_ != NULL);
272
0
        return ptr_;
273
28
    }
274
275
1.03k
    scoped_refptr<T>& operator=(T* p) {
276
        // AddRef first so that self assignment should work
277
1.03k
        if (p) p->AddRef();
278
1.03k
        T* old_ptr = ptr_;
279
1.03k
        ptr_ = p;
280
1.03k
        if (old_ptr) old_ptr->Release();
281
1.03k
        return *this;
282
1.03k
    }
_ZN13scoped_refptrIN5doris6ThreadEEaSEPS1_
Line
Count
Source
275
1.03k
    scoped_refptr<T>& operator=(T* p) {
276
        // AddRef first so that self assignment should work
277
1.03k
        if (p) p->AddRef();
278
1.03k
        T* old_ptr = ptr_;
279
1.03k
        ptr_ = p;
280
1.03k
        if (old_ptr) old_ptr->Release();
281
1.03k
        return *this;
282
1.03k
    }
Unexecuted instantiation: _ZN13scoped_refptrIN5doris8EasyJson17EasyJsonAllocatorEEaSEPS2_
283
284
1.03k
    scoped_refptr<T>& operator=(const scoped_refptr<T>& r) { return *this = r.ptr_; }
_ZN13scoped_refptrIN5doris6ThreadEEaSERKS2_
Line
Count
Source
284
1.03k
    scoped_refptr<T>& operator=(const scoped_refptr<T>& r) { return *this = r.ptr_; }
Unexecuted instantiation: _ZN13scoped_refptrIN5doris8EasyJson17EasyJsonAllocatorEEaSERKS3_
285
286
    template <typename U>
287
    scoped_refptr<T>& operator=(const scoped_refptr<U>& r) {
288
        return *this = r.get();
289
    }
290
291
    scoped_refptr<T>& operator=(scoped_refptr<T>&& r) {
292
        scoped_refptr<T>(std::move(r)).swap(*this);
293
        return *this;
294
    }
295
296
    template <typename U>
297
    scoped_refptr<T>& operator=(scoped_refptr<U>&& r) {
298
        scoped_refptr<T>(std::move(r)).swap(*this);
299
        return *this;
300
    }
301
302
    void swap(T** pp) {
303
        T* p = ptr_;
304
        ptr_ = *pp;
305
        *pp = p;
306
    }
307
308
    void swap(scoped_refptr<T>& r) { swap(&r.ptr_); }
309
310
    // Like gscoped_ptr::reset(), drops a reference on the currently held object
311
    // (if any), and adds a reference to the passed-in object (if not NULL).
312
    void reset(T* p = NULL) { *this = p; }
313
314
protected:
315
    T* ptr_ = nullptr;
316
317
private:
318
    template <typename U>
319
    friend class scoped_refptr;
320
};
321
322
// Handy utility for creating a scoped_refptr<T> out of a T* explicitly without
323
// having to retype all the template arguments
324
template <typename T>
325
scoped_refptr<T> make_scoped_refptr(T* t) {
326
    return scoped_refptr<T>(t);
327
}
328
329
// equal_to and hash implementations for templated scoped_refptrs suitable for
330
// use with STL unordered_* containers.
331
template <class T>
332
struct ScopedRefPtrEqualToFunctor {
333
    bool operator()(const scoped_refptr<T>& x, const scoped_refptr<T>& y) const {
334
        return x.get() == y.get();
335
    }
336
};
337
338
template <class T>
339
struct ScopedRefPtrHashFunctor {
340
    size_t operator()(const scoped_refptr<T>& p) const { return reinterpret_cast<size_t>(p.get()); }
341
};