mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-01-31 12:31:45 +01:00
Implement utils::refptr for typemap (with && syntax)
Ref-counted pointer, object is always allocated on heap. Rvalue reference && in typemap is converted to refptr for convenience.
This commit is contained in:
parent
6c5d9fffaa
commit
7b344b7654
@ -353,6 +353,121 @@ namespace utils
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// An object of type T paired with atomic refcounter
|
||||||
|
template <typename T>
|
||||||
|
class refctr final
|
||||||
|
{
|
||||||
|
atomic_t<std::size_t> m_ref{1};
|
||||||
|
|
||||||
|
public:
|
||||||
|
T object;
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
refctr(Args&&... args)
|
||||||
|
: object(std::forward<Args>(args)...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_ref() noexcept
|
||||||
|
{
|
||||||
|
m_ref++;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t remove_ref() noexcept
|
||||||
|
{
|
||||||
|
return --m_ref;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Simplified "shared" ptr making use of refctr<T> class
|
||||||
|
template <typename T>
|
||||||
|
class refptr final
|
||||||
|
{
|
||||||
|
refctr<T>* m_ptr = nullptr;
|
||||||
|
|
||||||
|
void destroy()
|
||||||
|
{
|
||||||
|
if (m_ptr && !m_ptr->remove_ref())
|
||||||
|
delete m_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
constexpr refptr() = default;
|
||||||
|
|
||||||
|
// Construct directly from refctr<T> pointer
|
||||||
|
explicit refptr(refctr<T>* ptr) noexcept
|
||||||
|
: m_ptr(ptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
refptr(const refptr& rhs) noexcept
|
||||||
|
: m_ptr(rhs.m_ptr)
|
||||||
|
{
|
||||||
|
if (m_ptr)
|
||||||
|
m_ptr->add_ref();
|
||||||
|
}
|
||||||
|
|
||||||
|
refptr(refptr&& rhs) noexcept
|
||||||
|
: m_ptr(rhs.m_ptr)
|
||||||
|
{
|
||||||
|
rhs.m_ptr = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
~refptr()
|
||||||
|
{
|
||||||
|
destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
refptr& operator =(const refptr& rhs) noexcept
|
||||||
|
{
|
||||||
|
destroy();
|
||||||
|
m_ptr = rhs.m_ptr;
|
||||||
|
if (m_ptr)
|
||||||
|
m_ptr->add_ref();
|
||||||
|
}
|
||||||
|
|
||||||
|
refptr& operator =(refptr&& rhs) noexcept
|
||||||
|
{
|
||||||
|
std::swap(m_ptr, rhs.m_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset() noexcept
|
||||||
|
{
|
||||||
|
destroy();
|
||||||
|
m_ptr = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
refctr<T>* release() noexcept
|
||||||
|
{
|
||||||
|
return std::exchange(m_ptr, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void swap(refptr&& rhs) noexcept
|
||||||
|
{
|
||||||
|
std::swap(m_ptr, rhs.m_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
refctr<T>* get() const noexcept
|
||||||
|
{
|
||||||
|
return m_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
T& operator *() const noexcept
|
||||||
|
{
|
||||||
|
return m_ptr->object;
|
||||||
|
}
|
||||||
|
|
||||||
|
T* operator ->() const noexcept
|
||||||
|
{
|
||||||
|
return &m_ptr->object;
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit operator bool() const noexcept
|
||||||
|
{
|
||||||
|
return !!m_ptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Internal, typemap control block for a particular type
|
// Internal, typemap control block for a particular type
|
||||||
struct alignas(64) typemap_head
|
struct alignas(64) typemap_head
|
||||||
{
|
{
|
||||||
@ -1168,44 +1283,48 @@ namespace utils
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Transform T&& into refptr<T>, moving const qualifier from T to refptr<T>
|
||||||
|
template <typename T, typename U = std::remove_reference_t<T>>
|
||||||
|
using decode_t = std::conditional_t<!std::is_rvalue_reference_v<T>, T,
|
||||||
|
std::conditional_t<std::is_const_v<U>, const refptr<std::remove_const_t<U>>, refptr<U>>>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Lock any objects by their identifiers, special tags id_new/id_any/id_always, or search predicates
|
// Lock any objects by their identifiers, special tags id_new/id_any/id_always, or search predicates
|
||||||
template <typename... Types, typename... Args, typename = std::enable_if_t<sizeof...(Types) == sizeof...(Args)>>
|
template <typename... Types, typename... Args, typename = std::enable_if_t<sizeof...(Types) == sizeof...(Args)>>
|
||||||
auto lock(Args&&... ids) const
|
auto lock(Args&&... ids) const
|
||||||
{
|
{
|
||||||
static_assert(((!std::is_lvalue_reference_v<Types> == !typeinfo_poly<Types>::is_poly) && ...));
|
static_assert(((!std::is_lvalue_reference_v<Types> == !typeinfo_poly<Types>::is_poly) && ...));
|
||||||
static_assert(((!std::is_rvalue_reference_v<Types>) && ...));
|
|
||||||
static_assert(((!std::is_array_v<Types>) && ...));
|
static_assert(((!std::is_array_v<Types>) && ...));
|
||||||
static_assert(((!std::is_void_v<Types>) && ...));
|
static_assert(((!std::is_void_v<Types>) && ...));
|
||||||
|
|
||||||
// Initialize pointers
|
// Initialize pointers
|
||||||
std::array<typeptr_base, sizeof...(Types)> result{this->init_ptr<Types>(std::forward<Args>(ids))...};
|
std::array<typeptr_base, sizeof...(Types)> result{this->init_ptr<decode_t<Types>>(std::forward<Args>(ids))...};
|
||||||
|
|
||||||
// Whether requires locking after init_ptr
|
// Whether requires locking after init_ptr
|
||||||
using locks_t = std::integer_sequence<bool, does_need_lock<Types, Args>()...>;
|
using locks_t = std::integer_sequence<bool, does_need_lock<decode_t<Types>, Args>()...>;
|
||||||
|
|
||||||
// Array index helper
|
// Array index helper
|
||||||
using seq_t = std::index_sequence_for<Types...>;
|
using seq_t = std::index_sequence_for<decode_t<Types>...>;
|
||||||
|
|
||||||
// Lock any number of objects in safe manner
|
// Lock any number of objects in safe manner
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
const uint locked = lock_array<Types...>(result, seq_t{}, locks_t{});
|
const uint locked = lock_array<decode_t<Types>...>(result, seq_t{}, locks_t{});
|
||||||
if (LIKELY(try_lock<0, Types...>(result, locked, locks_t{})))
|
if (LIKELY(try_lock<0, decode_t<Types>...>(result, locked, locks_t{})))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify object types
|
// Verify object types
|
||||||
check_array<Types...>(result, seq_t{}, std::forward<Args>(ids)...);
|
check_array<decode_t<Types>...>(result, seq_t{}, std::forward<Args>(ids)...);
|
||||||
|
|
||||||
// Return tuple of possibly locked pointers, or a single pointer
|
// Return tuple of possibly locked pointers, or a single pointer
|
||||||
if constexpr (sizeof...(Types) != 1)
|
if constexpr (sizeof...(Types) != 1)
|
||||||
{
|
{
|
||||||
return array_to_tuple<Types...>(result, seq_t{});
|
return array_to_tuple<decode_t<Types>...>(result, seq_t{});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return typeptr<Types...>(result[0]);
|
return typeptr<decode_t<Types>...>(result[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1214,17 +1333,16 @@ namespace utils
|
|||||||
ullong apply(F&& func)
|
ullong apply(F&& func)
|
||||||
{
|
{
|
||||||
static_assert(!std::is_lvalue_reference_v<Type> == !typeinfo_poly<Type>::is_poly);
|
static_assert(!std::is_lvalue_reference_v<Type> == !typeinfo_poly<Type>::is_poly);
|
||||||
static_assert(!std::is_rvalue_reference_v<Type>);
|
|
||||||
static_assert(!std::is_array_v<Type>);
|
static_assert(!std::is_array_v<Type>);
|
||||||
static_assert(!std::is_void_v<Type>);
|
static_assert(!std::is_void_v<Type>);
|
||||||
|
|
||||||
const uint type_id = g_typeinfo<std::decay_t<Type>>.type;
|
const uint type_id = g_typeinfo<std::decay_t<decode_t<Type>>>.type;
|
||||||
|
|
||||||
typemap_head* head = get_head<Type>();
|
typemap_head* head = get_head<decode_t<Type>>();
|
||||||
|
|
||||||
const ullong ix = head->m_create_count;
|
const ullong ix = head->m_create_count;
|
||||||
|
|
||||||
for (std::size_t j = 0; j < (typeinfo_count<Type>::max_count != 1 ? +head->m_limit : 1); j++)
|
for (std::size_t j = 0; j < (typeinfo_count<decode_t<Type>>::max_count != 1 ? +head->m_limit : 1); j++)
|
||||||
{
|
{
|
||||||
const auto block = reinterpret_cast<typemap_block*>(head->m_ptr + j * head->m_ssize);
|
const auto block = reinterpret_cast<typemap_block*>(head->m_ptr + j * head->m_ssize);
|
||||||
|
|
||||||
@ -1240,7 +1358,7 @@ namespace utils
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::invoke(std::forward<F>(func), *block->get_ptr<Type>());
|
std::invoke(std::forward<F>(func), *block->get_ptr<decode_t<Type>>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user