rpcsx/rx/include/rx/Rc.hpp
DH d7ad77b406 orbis: implement physical memory emulation level & utils improvement
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
2025-11-30 15:46:37 +03:00

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