blob: 74ce6c916ebf1e71a2d671798078237f9096da29 [file] [log] [blame]
/*
* Copyright (C) 2018 The Android Open Source Project
*
* 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 INCLUDE_PERFETTO_TRACE_PROCESSOR_REF_COUNTED_H_
#define INCLUDE_PERFETTO_TRACE_PROCESSOR_REF_COUNTED_H_
#include <stddef.h>
#include <stdint.h>
#include <memory>
#include <utility>
#include "perfetto/base/logging.h"
// A non-thread-safe refcounted implementation.
// Unlike std::shared_ptr The target class needs to explicitly derive
// RefCounted.
// Usage:
// class MyRefcountedThing : public RefCounted {};
// ...
// RefPtr<MyRefcountedThing> shareable_ptr(new MyRefcountedThing());
// auto copy = shareable_ptr;
namespace perfetto {
namespace trace_processor {
// The base class that refcounted classes should inherit.
class RefCounted {
public:
RefCounted() = default;
RefCounted(RefCounted&&) noexcept = default;
RefCounted& operator=(RefCounted&&) noexcept = default;
RefCounted(const RefCounted&) = delete;
RefCounted& operator=(const RefCounted&) = delete;
private:
template <typename T>
friend class RefPtr;
void AddRef() const {
PERFETTO_DCHECK(refcount_ >= 0);
++refcount_;
}
bool Release() const {
PERFETTO_DCHECK(refcount_ > 0);
return --refcount_ == 0;
}
mutable intptr_t refcount_ = 0;
};
// The RAII smart-pointer.
template <typename T>
class RefPtr {
public:
static_assert(std::is_base_of<RefCounted, T>::value,
"T must be a descendant of RefCounted");
// Adopt a newly created object.
RefPtr() : ptr_(nullptr) {}
explicit RefPtr(T* ptr) : ptr_(ptr) {
if (ptr_)
ptr_->AddRef();
}
~RefPtr() { reset(); }
void reset() {
auto* old_ptr = ptr_;
ptr_ = nullptr;
if (old_ptr && old_ptr->Release())
delete old_ptr;
}
// This case is really the move-assignment operator=(&&).
void reset(T* new_obj) { *this = RefPtr<T>(new_obj); }
// Releases the pointer owned by this RefPtr *without* decrementing the
// refcount. Callers *must* call |FromReleasedUnsafe| at a later date with
// this pointer to avoid memory leaks.
T* ReleaseUnsafe() {
PERFETTO_DCHECK(ptr_->refcount_ > 0);
auto* old_ptr = ptr_;
ptr_ = nullptr;
return old_ptr;
}
// Creates a RefPtr from a pointer returned by |ReleaseUnsafe|. Passing a
// pointer from any other source results in undefined behaviour.
static RefPtr<T> FromReleasedUnsafe(T* ptr) {
PERFETTO_DCHECK(ptr->refcount_ > 0);
RefPtr<T> res;
res.ptr_ = ptr;
return res;
}
// Move operators.
RefPtr(RefPtr&& move_from) noexcept {
ptr_ = move_from.ptr_;
move_from.ptr_ = nullptr;
}
RefPtr& operator=(RefPtr&& move_from) noexcept {
this->~RefPtr();
new (this) RefPtr(std::move(move_from));
return *this;
}
// Copy operators.
RefPtr(const RefPtr& copy_from) {
ptr_ = copy_from.ptr_;
if (ptr_)
ptr_->AddRef();
}
RefPtr& operator=(const RefPtr& copy_from) {
if (this != &copy_from) {
this->~RefPtr();
new (this) RefPtr(copy_from);
}
return *this;
}
template <typename U>
bool operator==(const RefPtr<U>& rhs) const {
return ptr_ == rhs.ptr_;
}
template <typename U>
bool operator!=(const RefPtr<U>& rhs) const {
return !(*this == rhs);
}
T* get() const { return ptr_; }
T* operator->() const { return ptr_; }
T& operator*() const { return *ptr_; }
explicit operator bool() const { return ptr_ != nullptr; }
private:
T* ptr_ = nullptr;
};
} // namespace trace_processor
} // namespace perfetto
#endif // INCLUDE_PERFETTO_TRACE_PROCESSOR_REF_COUNTED_H_