mirror of
https://github.com/RPCSX/rpcsx.git
synced 2025-12-06 07:12:14 +01:00
fix blockpool & dmem implementation modernize blockpool & dmem io devices use budgets per allocation add serialization support for MemoryTableWithPayload and AddressRange utils add format support for EnumBitSet util implemented trace formatter per syscall increased allowed reference count for Ref
135 lines
3 KiB
C++
135 lines
3 KiB
C++
#pragma once
|
|
|
|
#include <atomic>
|
|
#include <cassert>
|
|
#include <type_traits>
|
|
#include <utility>
|
|
|
|
namespace rx {
|
|
struct RcBase {
|
|
std::atomic<unsigned> references{0};
|
|
|
|
virtual ~RcBase() = default;
|
|
|
|
void incRef() {
|
|
if (references.fetch_add(1, std::memory_order::relaxed) > 100 * 1024 * 1024) {
|
|
assert(!"too many references");
|
|
}
|
|
}
|
|
|
|
// returns true if object was destroyed
|
|
bool decRef() {
|
|
if (references.fetch_sub(1, std::memory_order::relaxed) == 1) {
|
|
delete this;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
concept WithRc = requires(T t) {
|
|
t.incRef();
|
|
t.decRef();
|
|
};
|
|
|
|
template <typename T> class Ref {
|
|
T *m_ref = nullptr;
|
|
|
|
public:
|
|
Ref() = default;
|
|
Ref(std::nullptr_t) noexcept {}
|
|
|
|
template <typename OT>
|
|
requires(std::is_base_of_v<T, OT>)
|
|
Ref(OT *ref) noexcept : m_ref(ref) {
|
|
if (m_ref != nullptr) {
|
|
ref->incRef();
|
|
}
|
|
}
|
|
|
|
template <typename OT>
|
|
requires(std::is_base_of_v<T, OT>)
|
|
Ref(const Ref<OT> &other) noexcept : m_ref(other.get()) {
|
|
if (m_ref != nullptr) {
|
|
m_ref->incRef();
|
|
}
|
|
}
|
|
|
|
template <typename OT>
|
|
requires(std::is_base_of_v<T, OT>)
|
|
Ref(Ref<OT> &&other) noexcept : m_ref(other.release()) {}
|
|
|
|
Ref(const Ref &other) noexcept : m_ref(other.get()) {
|
|
if (m_ref != nullptr) {
|
|
m_ref->incRef();
|
|
}
|
|
}
|
|
Ref(Ref &&other) noexcept : m_ref(other.release()) {}
|
|
|
|
template <typename OT>
|
|
requires(std::is_base_of_v<T, OT>)
|
|
Ref &operator=(Ref<OT> &&other) noexcept {
|
|
other.template cast<T>().swap(*this);
|
|
return *this;
|
|
}
|
|
|
|
template <typename OT>
|
|
requires(std::is_base_of_v<T, OT>)
|
|
Ref &operator=(OT *other) noexcept {
|
|
*this = Ref(other);
|
|
return *this;
|
|
}
|
|
|
|
template <typename OT>
|
|
requires(std::is_base_of_v<T, OT>)
|
|
Ref &operator=(const Ref<OT> &other) noexcept {
|
|
*this = Ref(other);
|
|
return *this;
|
|
}
|
|
|
|
Ref &operator=(const Ref &other) noexcept {
|
|
*this = Ref(other);
|
|
return *this;
|
|
}
|
|
|
|
Ref &operator=(Ref &&other) noexcept {
|
|
other.swap(*this);
|
|
return *this;
|
|
}
|
|
|
|
~Ref() {
|
|
if (m_ref != nullptr) {
|
|
m_ref->decRef();
|
|
}
|
|
}
|
|
|
|
void swap(Ref<T> &other) noexcept { std::swap(m_ref, other.m_ref); }
|
|
T *get() const { return m_ref; }
|
|
T *release() { return std::exchange(m_ref, nullptr); }
|
|
T *operator->() const { return m_ref; }
|
|
explicit operator bool() const { return m_ref != nullptr; }
|
|
bool operator==(const Ref &) const = default;
|
|
bool operator==(std::nullptr_t) const { return m_ref == nullptr; }
|
|
auto operator<=>(const T *other) const { return m_ref <=> other; }
|
|
auto operator<=>(const Ref &other) const = default;
|
|
|
|
template <typename OtherT> Ref<OtherT> cast() {
|
|
return dynamic_cast<OtherT *>(m_ref);
|
|
}
|
|
template <typename OtherT> Ref<OtherT> staticCast() {
|
|
return static_cast<OtherT *>(m_ref);
|
|
}
|
|
|
|
template <typename OtherT> OtherT *rawCast() {
|
|
return dynamic_cast<OtherT *>(m_ref);
|
|
}
|
|
template <typename OtherT> OtherT *rawStaticCast() {
|
|
return static_cast<OtherT *>(m_ref);
|
|
}
|
|
};
|
|
|
|
template <typename T> Ref(T *) -> Ref<T>;
|
|
} // namespace rx
|