blob: 37612add8c991576d41bcad068adaff621e82696 [file] [log] [blame]
perkj0489e492016-10-20 00:24:01 -07001/*
2 * Copyright 2016 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
Steve Anton10542f22019-01-11 09:11:00 -080010#ifndef RTC_BASE_REF_COUNTED_OBJECT_H_
11#define RTC_BASE_REF_COUNTED_OBJECT_H_
perkj0489e492016-10-20 00:24:01 -070012
Yves Gerey3e707812018-11-28 16:47:49 +010013#include <type_traits>
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020014#include <utility>
perkj0489e492016-10-20 00:24:01 -070015
Tomas Gunnarssond7842002021-04-22 17:41:33 +020016#include "api/scoped_refptr.h"
Steve Anton10542f22019-01-11 09:11:00 -080017#include "rtc_base/constructor_magic.h"
18#include "rtc_base/ref_count.h"
19#include "rtc_base/ref_counter.h"
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020020
21namespace rtc {
22
Niels Möllerbb57de22022-01-11 15:40:22 +010023namespace webrtc_make_ref_counted_internal {
24// Determines if the given class has AddRef and Release methods.
25template <typename T>
26class HasAddRefAndRelease {
27 private:
28 template <typename C,
29 decltype(std::declval<C>().AddRef())* = nullptr,
30 decltype(std::declval<C>().Release())* = nullptr>
31 static int Test(int);
32 template <typename>
33 static char Test(...);
34
35 public:
36 static constexpr bool value = std::is_same_v<decltype(Test<T>(0)), int>;
37};
38} // namespace webrtc_make_ref_counted_internal
39
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020040template <class T>
41class RefCountedObject : public T {
42 public:
43 RefCountedObject() {}
44
45 template <class P0>
46 explicit RefCountedObject(P0&& p0) : T(std::forward<P0>(p0)) {}
47
48 template <class P0, class P1, class... Args>
49 RefCountedObject(P0&& p0, P1&& p1, Args&&... args)
50 : T(std::forward<P0>(p0),
51 std::forward<P1>(p1),
52 std::forward<Args>(args)...) {}
53
Tomas Gunnarssone249d192021-04-26 11:46:54 +020054 void AddRef() const override { ref_count_.IncRef(); }
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020055
Tomas Gunnarssone249d192021-04-26 11:46:54 +020056 RefCountReleaseStatus Release() const override {
Niels Möller9155e492017-10-23 11:22:30 +020057 const auto status = ref_count_.DecRef();
58 if (status == RefCountReleaseStatus::kDroppedLastRef) {
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020059 delete this;
60 }
Niels Möller9155e492017-10-23 11:22:30 +020061 return status;
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020062 }
63
64 // Return whether the reference count is one. If the reference count is used
65 // in the conventional way, a reference count of 1 implies that the current
66 // thread owns the reference and no other thread shares it. This call
67 // performs the test for a reference count of one, and performs the memory
68 // barrier needed for the owning thread to act on the object, knowing that it
69 // has exclusive access to the object.
Niels Möller9155e492017-10-23 11:22:30 +020070 virtual bool HasOneRef() const { return ref_count_.HasOneRef(); }
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020071
72 protected:
Tomas Gunnarssone249d192021-04-26 11:46:54 +020073 ~RefCountedObject() override {}
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020074
Niels Möller9155e492017-10-23 11:22:30 +020075 mutable webrtc::webrtc_impl::RefCounter ref_count_{0};
76
77 RTC_DISALLOW_COPY_AND_ASSIGN(RefCountedObject);
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020078};
79
Danil Chapovalov8df643b2021-01-22 16:11:10 +010080template <class T>
81class FinalRefCountedObject final : public T {
82 public:
83 using T::T;
Niels Möllerbb57de22022-01-11 15:40:22 +010084 // Above using declaration propagates a default move constructor
85 // FinalRefCountedObject(FinalRefCountedObject&& other), but we also need
86 // move construction from T.
Danil Chapovalov80b76282021-04-26 16:32:27 +020087 explicit FinalRefCountedObject(T&& other) : T(std::move(other)) {}
Danil Chapovalov8df643b2021-01-22 16:11:10 +010088 FinalRefCountedObject(const FinalRefCountedObject&) = delete;
89 FinalRefCountedObject& operator=(const FinalRefCountedObject&) = delete;
90
91 void AddRef() const { ref_count_.IncRef(); }
Niels Möllerb7aac6f2021-08-23 15:48:06 +020092 RefCountReleaseStatus Release() const {
93 const auto status = ref_count_.DecRef();
94 if (status == RefCountReleaseStatus::kDroppedLastRef) {
Danil Chapovalov8df643b2021-01-22 16:11:10 +010095 delete this;
96 }
Niels Möllerb7aac6f2021-08-23 15:48:06 +020097 return status;
Danil Chapovalov8df643b2021-01-22 16:11:10 +010098 }
99 bool HasOneRef() const { return ref_count_.HasOneRef(); }
100
101 private:
102 ~FinalRefCountedObject() = default;
103
Danil Chapovalovd71e5912021-03-29 22:17:36 +0200104 mutable webrtc::webrtc_impl::RefCounter ref_count_{0};
Danil Chapovalov8df643b2021-01-22 16:11:10 +0100105};
106
Tomas Gunnarssond7842002021-04-22 17:41:33 +0200107// General utilities for constructing a reference counted class and the
108// appropriate reference count implementation for that class.
109//
110// These utilities select either the `RefCountedObject` implementation or
111// `FinalRefCountedObject` depending on whether the to-be-shared class is
112// derived from the RefCountInterface interface or not (respectively).
113
114// `make_ref_counted`:
115//
116// Use this when you want to construct a reference counted object of type T and
117// get a `scoped_refptr<>` back. Example:
118//
119// auto p = make_ref_counted<Foo>("bar", 123);
120//
121// For a class that inherits from RefCountInterface, this is equivalent to:
122//
123// auto p = scoped_refptr<Foo>(new RefCountedObject<Foo>("bar", 123));
124//
Niels Möllerbb57de22022-01-11 15:40:22 +0100125// If the class does not inherit from RefCountInterface, but does have
126// AddRef/Release methods (so a T* is convertible to rtc::scoped_refptr), this
127// is equivalent to just
128//
129// auto p = scoped_refptr<Foo>(new Foo("bar", 123));
130//
131// Otherwise, the example is equivalent to:
Tomas Gunnarssond7842002021-04-22 17:41:33 +0200132//
133// auto p = scoped_refptr<FinalRefCountedObject<Foo>>(
134// new FinalRefCountedObject<Foo>("bar", 123));
135//
136// In these cases, `make_ref_counted` reduces the amount of boilerplate code but
137// also helps with the most commonly intended usage of RefCountedObject whereby
138// methods for reference counting, are virtual and designed to satisfy the need
139// of an interface. When such a need does not exist, it is more efficient to use
140// the `FinalRefCountedObject` template, which does not add the vtable overhead.
141//
142// Note that in some cases, using RefCountedObject directly may still be what's
143// needed.
144
145// `make_ref_counted` for classes that are convertible to RefCountInterface.
Niels Möllerbb57de22022-01-11 15:40:22 +0100146template <typename T,
147 typename... Args,
148 typename std::enable_if<std::is_convertible_v<T*, RefCountInterface*>,
149 T>::type* = nullptr>
Tomas Gunnarssond7842002021-04-22 17:41:33 +0200150scoped_refptr<T> make_ref_counted(Args&&... args) {
151 return new RefCountedObject<T>(std::forward<Args>(args)...);
152}
153
154// `make_ref_counted` for complete classes that are not convertible to
Niels Möllerbb57de22022-01-11 15:40:22 +0100155// RefCountInterface and already carry a ref count.
Tomas Gunnarssond7842002021-04-22 17:41:33 +0200156template <
157 typename T,
158 typename... Args,
Niels Möllerbb57de22022-01-11 15:40:22 +0100159 typename std::enable_if<
160 !std::is_convertible_v<T*, RefCountInterface*> &&
161 webrtc_make_ref_counted_internal::HasAddRefAndRelease<T>::value,
162 T>::type* = nullptr>
163scoped_refptr<T> make_ref_counted(Args&&... args) {
164 return scoped_refptr<T>(new T(std::forward<Args>(args)...));
165}
166
167// `make_ref_counted` for complete classes that are not convertible to
168// RefCountInterface and have no ref count of their own.
169template <
170 typename T,
171 typename... Args,
172 typename std::enable_if<
173 !std::is_convertible_v<T*, RefCountInterface*> &&
174 !webrtc_make_ref_counted_internal::HasAddRefAndRelease<T>::value,
175
176 T>::type* = nullptr>
Tomas Gunnarssond7842002021-04-22 17:41:33 +0200177scoped_refptr<FinalRefCountedObject<T>> make_ref_counted(Args&&... args) {
178 return new FinalRefCountedObject<T>(std::forward<Args>(args)...);
179}
180
181// `Ref<>`, `Ref<>::Type` and `Ref<>::Ptr`:
182//
183// `Ref` is a type declaring utility that is compatible with `make_ref_counted`
184// and can be used in classes and methods where it's more convenient (or
185// readable) to have the compiler figure out the fully fleshed out type for a
186// class rather than spell it out verbatim in all places the type occurs (which
187// can mean maintenance work if the class layout changes).
188//
189// Usage examples:
190//
191// If you want to declare the parameter type that's always compatible with
192// this code:
193//
194// Bar(make_ref_counted<Foo>());
195//
196// You can use `Ref<>::Ptr` to declare a compatible scoped_refptr type:
197//
198// void Bar(Ref<Foo>::Ptr p);
199//
200// This might be more practically useful in templates though.
201//
202// In rare cases you might need to be able to declare a parameter that's fully
203// compatible with the reference counted T type - and just using T* is not
204// enough. To give a code example, we can declare a function, `Foo` that is
205// compatible with this code:
206// auto p = make_ref_counted<Foo>();
207// Foo(p.get());
208//
209// void Foo(Ref<Foo>::Type* foo_ptr);
210//
211// Alternatively this would be:
212// void Foo(Foo* foo_ptr);
213// or
214// void Foo(FinalRefCountedObject<Foo>* foo_ptr);
215
216// Declares the approprate reference counted type for T depending on whether
217// T is convertible to RefCountInterface or not.
218// For classes that are convertible, the type will simply be T.
219// For classes that cannot be converted to RefCountInterface, the type will be
220// FinalRefCountedObject<T>.
221// This is most useful for declaring a scoped_refptr<T> instance for a class
222// that may or may not implement a virtual reference counted interface:
223// * scoped_refptr<Ref<Foo>::Type> my_ptr;
224template <typename T>
225struct Ref {
226 typedef typename std::conditional<
Niels Möllerbb57de22022-01-11 15:40:22 +0100227 webrtc_make_ref_counted_internal::HasAddRefAndRelease<T>::value,
Tomas Gunnarssond7842002021-04-22 17:41:33 +0200228 T,
229 FinalRefCountedObject<T>>::type Type;
230
231 typedef scoped_refptr<Type> Ptr;
232};
233
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +0200234} // namespace rtc
perkj0489e492016-10-20 00:24:01 -0700235
Steve Anton10542f22019-01-11 09:11:00 -0800236#endif // RTC_BASE_REF_COUNTED_OBJECT_H_