1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
|
// 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_
|