| // Copyright 2025 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef REMOTING_HOST_BASE_POINTER_UTILS_H_ |
| #define REMOTING_HOST_BASE_POINTER_UTILS_H_ |
| |
| #include <concepts> |
| #include <cstddef> |
| #include <functional> |
| |
| #include "base/memory/raw_ptr.h" |
| |
| namespace remoting { |
| |
| // Allows specifying a delete function at the type level so it doesn't have |
| // to be specified at each construction of the std::unique_ptr or stored |
| // inline. So instead of saying |
| // |
| // std::unique_ptr<foo, void(*)(foo*)> foo_ptr{make_foo_ptr(), &foo_free}; |
| // |
| // and having foo_ptr have to hold two pointers, one can say |
| // |
| // std::unique_ptr<foo, DeleteFunc<foo_free>> foo_ptr{make_foo_ptr()}; |
| // |
| // and have foo_ptr only hold the object pointer. |
| template <auto kDeleteFunction> |
| struct DeleteFunc { |
| void operator()(auto* ptr) { kDeleteFunction(ptr); } |
| }; |
| |
| // A generic smart pointer for working with reference counted objects exposed by |
| // C APIs. Holds an owned reference to a object of type T, whose reference be |
| // managed with kRefFunc, kUnrefFunc, and optionally kTakeFunc and kRefSinkFunc. |
| // |
| // Typically used via a type alias, e.g., |
| // |
| // using FooPtr = CRefCounted<foo_ref, foo_unref>; |
| template <typename T, |
| // Takes a pointer to T, increases the reference count, and returns |
| // the pointer. |
| auto kRefFunc, |
| // Takes a pointer to T, decreases the reference count, and frees the |
| // object if the reference count is now zero. |
| auto kUnrefFunc, |
| // Takes a pointer to T, performs any action needed to take ownership |
| // of an existing reference (such as sinking a floating reference), |
| // and returns the pointer. |
| auto kTakeFunc = std::identity(), |
| // Takes a pointer to T, and sinks the existing floating reference, if |
| // any, or otherwise increases the reference count. (Only specify for |
| // types supporting floating references.) |
| auto kRefSinkFunc = nullptr> |
| class CRefCounted { |
| public: |
| // Constructs a null reference. |
| CRefCounted() = default; |
| |
| // Creates a new owned reference, increasing the reference count. |
| CRefCounted(const CRefCounted& other) |
| : ptr_(other.ptr_ ? kRefFunc(other.ptr_) : nullptr) {} |
| |
| // Takes ownership of an existing reference, leaving |other| null. |
| CRefCounted(CRefCounted&& other) : ptr_(other.ptr_) { other.ptr_ = nullptr; } |
| |
| // Unrefs the current object, if any, and assigns to reference the same object |
| // as |other|, increasing the reference count. |
| CRefCounted& operator=(const CRefCounted& other) { |
| if (this == &other) { |
| return *this; |
| } |
| reset(); |
| if (other.ptr_) { |
| ptr_ = kRefFunc(other.ptr_); |
| } |
| return *this; |
| } |
| |
| // Unrefs the current object, if any, and takes ownship of the reference in |
| // |other|, leaving |other| null. |
| CRefCounted& operator=(CRefCounted&& other) { |
| if (this == &other) { |
| return *this; |
| } |
| reset(); |
| ptr_ = other.ptr_; |
| other.ptr_ = nullptr; |
| return *this; |
| } |
| |
| // Unrefs the current object. |
| ~CRefCounted() { reset(); } |
| |
| // Unrefs the current object and sets reference to null. |
| void reset() { |
| if (ptr_) { |
| kUnrefFunc(ptr_.ExtractAsDangling()); |
| } |
| } |
| |
| // Gets the pointer to the referenced object. |
| T* get() const { return ptr_; } |
| |
| // Returns the pointer to the referenced object and releases the ownership, |
| // setting this reference to null without decreasing the reference count. |
| [[nodiscard]] T* release() { |
| T* ptr = ptr_; |
| ptr_ = nullptr; |
| return ptr; |
| } |
| |
| // Smart pointer operators |
| T& operator*() const { return *ptr_; } |
| T* operator->() const { return ptr_; } |
| |
| // Checks if |this| and |other| reference the same object. |
| bool operator==(const CRefCounted& other) const { return ptr_ == other.ptr_; } |
| |
| // Takes ownership of an existing raw object pointer without increasing the |
| // reference count. |
| static CRefCounted Take(T* ptr) { return CRefCounted(kTakeFunc(ptr)); } |
| |
| // Creates a new owned reference to |ptr| by increasing the reference count. |
| static CRefCounted Ref(T* ptr) { return CRefCounted(kRefFunc(ptr)); } |
| |
| // If |ptr| is floating, takes ownership and sinks the floating reference. |
| // Otherwise, creates a new owned reference by increasing the reference count. |
| static CRefCounted RefSink(T* ptr) |
| requires(!std::same_as<decltype(kRefSinkFunc), std::nullptr_t>) |
| { |
| return CRefCounted(kRefSinkFunc(ptr)); |
| } |
| |
| private: |
| explicit CRefCounted(T* ptr) : ptr_(ptr) {} |
| raw_ptr<T> ptr_ = nullptr; |
| }; |
| |
| } // namespace remoting |
| |
| #endif // REMOTING_HOST_BASE_POINTER_UTILS_H_ |