// // // Copyright 2017 gRPC authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // #ifndef GRPC_SRC_CORE_LIB_GPRPP_ORPHANABLE_H #define GRPC_SRC_CORE_LIB_GPRPP_ORPHANABLE_H #include #include #include #include #include "src/core/lib/gprpp/debug_location.h" #include "src/core/lib/gprpp/down_cast.h" #include "src/core/lib/gprpp/ref_counted.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" namespace grpc_core { // A base class for orphanable objects, which have one external owner // but are not necessarily destroyed immediately when the external owner // gives up ownership. Instead, the owner calls the object's Orphan() // method, and the object then takes responsibility for its own cleanup // and destruction. class Orphanable { public: // Gives up ownership of the object. The implementation must arrange // to eventually destroy the object without further interaction from the // caller. virtual void Orphan() = 0; // Not copyable or movable. Orphanable(const Orphanable&) = delete; Orphanable& operator=(const Orphanable&) = delete; protected: Orphanable() {} virtual ~Orphanable() {} }; class OrphanableDelete { public: template void operator()(T* p) { p->Orphan(); } }; template using OrphanablePtr = std::unique_ptr; template inline OrphanablePtr MakeOrphanable(Args&&... args) { return OrphanablePtr(new T(std::forward(args)...)); } // A type of Orphanable with internal ref-counting. template class InternallyRefCounted : public Orphanable { public: // Not copyable nor movable. InternallyRefCounted(const InternallyRefCounted&) = delete; InternallyRefCounted& operator=(const InternallyRefCounted&) = delete; protected: // Allow RefCountedPtr<> to access Unref() and IncrementRefCount(). template friend class RefCountedPtr; // Note: Tracing is a no-op on non-debug builds. explicit InternallyRefCounted(const char* trace = nullptr, intptr_t initial_refcount = 1) : refs_(initial_refcount, trace) {} ~InternallyRefCounted() override = default; GRPC_MUST_USE_RESULT RefCountedPtr Ref() { IncrementRefCount(); return RefCountedPtr(static_cast(this)); } GRPC_MUST_USE_RESULT RefCountedPtr Ref(const DebugLocation& location, const char* reason) { IncrementRefCount(location, reason); return RefCountedPtr(static_cast(this)); } template < typename Subclass, std::enable_if_t::value, bool> = true> RefCountedPtr RefAsSubclass() { IncrementRefCount(); return RefCountedPtr( DownCast(static_cast(this))); } template < typename Subclass, std::enable_if_t::value, bool> = true> RefCountedPtr RefAsSubclass(const DebugLocation& location, const char* reason) { IncrementRefCount(location, reason); return RefCountedPtr( DownCast(static_cast(this))); } GRPC_MUST_USE_RESULT RefCountedPtr RefIfNonZero() { return RefCountedPtr(refs_.RefIfNonZero() ? static_cast(this) : nullptr); } GRPC_MUST_USE_RESULT RefCountedPtr RefIfNonZero( const DebugLocation& location, const char* reason) { return RefCountedPtr(refs_.RefIfNonZero(location, reason) ? static_cast(this) : nullptr); } void Unref() { if (GPR_UNLIKELY(refs_.Unref())) { unref_behavior_(static_cast(this)); } } void Unref(const DebugLocation& location, const char* reason) { if (GPR_UNLIKELY(refs_.Unref(location, reason))) { unref_behavior_(static_cast(this)); } } private: void IncrementRefCount() { refs_.Ref(); } void IncrementRefCount(const DebugLocation& location, const char* reason) { refs_.Ref(location, reason); } RefCount refs_; GPR_NO_UNIQUE_ADDRESS UnrefBehavior unref_behavior_; }; } // namespace grpc_core #endif // GRPC_SRC_CORE_LIB_GPRPP_ORPHANABLE_H