Coverage Report

Created: 2025-06-16 19:37

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