1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef INCLUDE_PERFETTO_TRACE_PROCESSOR_REF_COUNTED_H_ 18 #define INCLUDE_PERFETTO_TRACE_PROCESSOR_REF_COUNTED_H_ 19 20 #include <stddef.h> 21 #include <stdint.h> 22 23 #include <memory> 24 #include <utility> 25 26 #include "perfetto/base/logging.h" 27 28 // A non-thread-safe refcounted implementation. 29 // Unlike std::shared_ptr The target class needs to explicitly derive 30 // RefCounted. 31 32 // Usage: 33 // class MyRefcountedThing : public RefCounted {}; 34 // ... 35 // RefPtr<MyRefcountedThing> shareable_ptr(new MyRefcountedThing()); 36 // auto copy = shareable_ptr; 37 38 namespace perfetto { 39 namespace trace_processor { 40 41 // The base class that refcounted classes should inherit. 42 class RefCounted { 43 public: 44 RefCounted() = default; 45 RefCounted(RefCounted&&) noexcept = default; 46 RefCounted& operator=(RefCounted&&) noexcept = default; 47 RefCounted(const RefCounted&) = delete; 48 RefCounted& operator=(const RefCounted&) = delete; 49 50 private: 51 template <typename T> 52 friend class RefPtr; 53 AddRef()54 void AddRef() const { 55 PERFETTO_DCHECK(refcount_ >= 0); 56 ++refcount_; 57 } Release()58 bool Release() const { 59 PERFETTO_DCHECK(refcount_ > 0); 60 return --refcount_ == 0; 61 } 62 63 mutable intptr_t refcount_ = 0; 64 }; 65 66 // The RAII smart-pointer. 67 template <typename T> 68 class RefPtr { 69 public: 70 static_assert(std::is_base_of<RefCounted, T>::value, 71 "T must be a descendant of RefCounted"); 72 73 // Adopt a newly created object. RefPtr()74 RefPtr() : ptr_(nullptr) {} RefPtr(T * ptr)75 explicit RefPtr(T* ptr) : ptr_(ptr) { 76 if (ptr_) 77 ptr_->AddRef(); 78 } 79 ~RefPtr()80 ~RefPtr() { reset(); } 81 reset()82 void reset() { 83 auto* old_ptr = ptr_; 84 ptr_ = nullptr; 85 if (old_ptr && old_ptr->Release()) 86 delete old_ptr; 87 } 88 89 // This case is really the move-assignment operator=(&&). reset(T * new_obj)90 void reset(T* new_obj) { *this = RefPtr<T>(new_obj); } 91 92 // Releases the pointer owned by this RefPtr *without* decrementing the 93 // refcount. Callers *must* call |FromReleasedUnsafe| at a later date with 94 // this pointer to avoid memory leaks. ReleaseUnsafe()95 T* ReleaseUnsafe() { 96 PERFETTO_DCHECK(ptr_->refcount_ > 0); 97 auto* old_ptr = ptr_; 98 ptr_ = nullptr; 99 return old_ptr; 100 } 101 102 // Creates a RefPtr from a pointer returned by |ReleaseUnsafe|. Passing a 103 // pointer from any other source results in undefined behaviour. FromReleasedUnsafe(T * ptr)104 static RefPtr<T> FromReleasedUnsafe(T* ptr) { 105 PERFETTO_DCHECK(ptr->refcount_ > 0); 106 RefPtr<T> res; 107 res.ptr_ = ptr; 108 return res; 109 } 110 111 // Move operators. RefPtr(RefPtr && move_from)112 RefPtr(RefPtr&& move_from) noexcept { 113 ptr_ = move_from.ptr_; 114 move_from.ptr_ = nullptr; 115 } 116 117 RefPtr& operator=(RefPtr&& move_from) noexcept { 118 this->~RefPtr(); 119 new (this) RefPtr(std::move(move_from)); 120 return *this; 121 } 122 123 // Copy operators. RefPtr(const RefPtr & copy_from)124 RefPtr(const RefPtr& copy_from) { 125 ptr_ = copy_from.ptr_; 126 if (ptr_) 127 ptr_->AddRef(); 128 } 129 130 RefPtr& operator=(const RefPtr& copy_from) { 131 if (this != ©_from) { 132 this->~RefPtr(); 133 new (this) RefPtr(copy_from); 134 } 135 return *this; 136 } 137 138 template <typename U> 139 bool operator==(const RefPtr<U>& rhs) const { 140 return ptr_ == rhs.ptr_; 141 } 142 template <typename U> 143 bool operator!=(const RefPtr<U>& rhs) const { 144 return !(*this == rhs); 145 } 146 get()147 T* get() const { return ptr_; } 148 T* operator->() const { return ptr_; } 149 T& operator*() const { return *ptr_; } 150 explicit operator bool() const { return ptr_ != nullptr; } 151 152 private: 153 T* ptr_ = nullptr; 154 }; 155 156 } // namespace trace_processor 157 } // namespace perfetto 158 159 #endif // INCLUDE_PERFETTO_TRACE_PROCESSOR_REF_COUNTED_H_ 160