1 //
2 //
3 // Copyright 2017 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18
19 #ifndef GRPC_SRC_CORE_LIB_GPRPP_ORPHANABLE_H
20 #define GRPC_SRC_CORE_LIB_GPRPP_ORPHANABLE_H
21
22 #include <grpc/support/port_platform.h>
23
24 #include <cinttypes>
25 #include <memory>
26 #include <utility>
27
28 #include "src/core/lib/gprpp/debug_location.h"
29 #include "src/core/lib/gprpp/down_cast.h"
30 #include "src/core/lib/gprpp/ref_counted.h"
31 #include "src/core/lib/gprpp/ref_counted_ptr.h"
32
33 namespace grpc_core {
34
35 // A base class for orphanable objects, which have one external owner
36 // but are not necessarily destroyed immediately when the external owner
37 // gives up ownership. Instead, the owner calls the object's Orphan()
38 // method, and the object then takes responsibility for its own cleanup
39 // and destruction.
40 class Orphanable {
41 public:
42 // Gives up ownership of the object. The implementation must arrange
43 // to eventually destroy the object without further interaction from the
44 // caller.
45 virtual void Orphan() = 0;
46
47 // Not copyable or movable.
48 Orphanable(const Orphanable&) = delete;
49 Orphanable& operator=(const Orphanable&) = delete;
50
51 protected:
Orphanable()52 Orphanable() {}
~Orphanable()53 virtual ~Orphanable() {}
54 };
55
56 class OrphanableDelete {
57 public:
58 template <typename T>
operator()59 void operator()(T* p) {
60 p->Orphan();
61 }
62 };
63
64 template <typename T, typename Deleter = OrphanableDelete>
65 using OrphanablePtr = std::unique_ptr<T, Deleter>;
66
67 template <typename T, typename... Args>
MakeOrphanable(Args &&...args)68 inline OrphanablePtr<T> MakeOrphanable(Args&&... args) {
69 return OrphanablePtr<T>(new T(std::forward<Args>(args)...));
70 }
71
72 // A type of Orphanable with internal ref-counting.
73 template <typename Child, typename UnrefBehavior = UnrefDelete>
74 class InternallyRefCounted : public Orphanable {
75 public:
76 // Not copyable nor movable.
77 InternallyRefCounted(const InternallyRefCounted&) = delete;
78 InternallyRefCounted& operator=(const InternallyRefCounted&) = delete;
79
80 protected:
81 // Allow RefCountedPtr<> to access Unref() and IncrementRefCount().
82 template <typename T>
83 friend class RefCountedPtr;
84
85 // Note: Tracing is a no-op on non-debug builds.
86 explicit InternallyRefCounted(const char* trace = nullptr,
87 intptr_t initial_refcount = 1)
refs_(initial_refcount,trace)88 : refs_(initial_refcount, trace) {}
89 ~InternallyRefCounted() override = default;
90
Ref()91 GRPC_MUST_USE_RESULT RefCountedPtr<Child> Ref() {
92 IncrementRefCount();
93 return RefCountedPtr<Child>(static_cast<Child*>(this));
94 }
Ref(const DebugLocation & location,const char * reason)95 GRPC_MUST_USE_RESULT RefCountedPtr<Child> Ref(const DebugLocation& location,
96 const char* reason) {
97 IncrementRefCount(location, reason);
98 return RefCountedPtr<Child>(static_cast<Child*>(this));
99 }
100
101 template <
102 typename Subclass,
103 std::enable_if_t<std::is_base_of<Child, Subclass>::value, bool> = true>
RefAsSubclass()104 RefCountedPtr<Subclass> RefAsSubclass() {
105 IncrementRefCount();
106 return RefCountedPtr<Subclass>(
107 DownCast<Subclass*>(static_cast<Child*>(this)));
108 }
109 template <
110 typename Subclass,
111 std::enable_if_t<std::is_base_of<Child, Subclass>::value, bool> = true>
RefAsSubclass(const DebugLocation & location,const char * reason)112 RefCountedPtr<Subclass> RefAsSubclass(const DebugLocation& location,
113 const char* reason) {
114 IncrementRefCount(location, reason);
115 return RefCountedPtr<Subclass>(
116 DownCast<Subclass*>(static_cast<Child*>(this)));
117 }
118
RefIfNonZero()119 GRPC_MUST_USE_RESULT RefCountedPtr<Child> RefIfNonZero() {
120 return RefCountedPtr<Child>(refs_.RefIfNonZero() ? static_cast<Child*>(this)
121 : nullptr);
122 }
RefIfNonZero(const DebugLocation & location,const char * reason)123 GRPC_MUST_USE_RESULT RefCountedPtr<Child> RefIfNonZero(
124 const DebugLocation& location, const char* reason) {
125 return RefCountedPtr<Child>(refs_.RefIfNonZero(location, reason)
126 ? static_cast<Child*>(this)
127 : nullptr);
128 }
129
Unref()130 void Unref() {
131 if (GPR_UNLIKELY(refs_.Unref())) {
132 unref_behavior_(static_cast<Child*>(this));
133 }
134 }
Unref(const DebugLocation & location,const char * reason)135 void Unref(const DebugLocation& location, const char* reason) {
136 if (GPR_UNLIKELY(refs_.Unref(location, reason))) {
137 unref_behavior_(static_cast<Child*>(this));
138 }
139 }
140
141 private:
IncrementRefCount()142 void IncrementRefCount() { refs_.Ref(); }
IncrementRefCount(const DebugLocation & location,const char * reason)143 void IncrementRefCount(const DebugLocation& location, const char* reason) {
144 refs_.Ref(location, reason);
145 }
146
147 RefCount refs_;
148 GPR_NO_UNIQUE_ADDRESS UnrefBehavior unref_behavior_;
149 };
150
151 } // namespace grpc_core
152
153 #endif // GRPC_SRC_CORE_LIB_GPRPP_ORPHANABLE_H
154