mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-22 10:42:36 +01:00
Implement util/auto_typemap.hpp
Used in vm::block_t as an example.
This commit is contained in:
parent
c94a98e15a
commit
567d23d856
@ -1058,6 +1058,9 @@ namespace vm
|
||||
}
|
||||
}
|
||||
|
||||
// Mapped regions: addr -> shm handle
|
||||
constexpr auto block_map = &auto_typemap<block_t>::get<std::map<u32, std::pair<u32, std::shared_ptr<utils::shm>>>>;
|
||||
|
||||
bool block_t::try_alloc(u32 addr, u8 flags, u32 size, std::shared_ptr<utils::shm>&& shm)
|
||||
{
|
||||
// Check if memory area is already mapped
|
||||
@ -1082,7 +1085,9 @@ namespace vm
|
||||
// Map "real" memory pages; provide a function to search for mirrors with private member access
|
||||
_page_map(page_addr, flags, page_size, shm.get(), [](vm::block_t* _this, utils::shm* shm)
|
||||
{
|
||||
decltype(m_map)::value_type* result = nullptr;
|
||||
auto& map = (_this->m.*block_map)();
|
||||
|
||||
std::remove_reference_t<decltype(map)>::value_type* result = nullptr;
|
||||
|
||||
// Check eligibility
|
||||
if (!_this || !(SYS_MEMORY_PAGE_SIZE_MASK & _this->flags) || _this->addr < 0x20000000 || _this->addr >= 0xC0000000)
|
||||
@ -1090,7 +1095,7 @@ namespace vm
|
||||
return result;
|
||||
}
|
||||
|
||||
for (auto& pp : _this->m_map)
|
||||
for (auto& pp : map)
|
||||
{
|
||||
if (pp.second.second.get() == shm)
|
||||
{
|
||||
@ -1125,7 +1130,7 @@ namespace vm
|
||||
}
|
||||
|
||||
// Add entry
|
||||
m_map[addr] = std::make_pair(size, std::move(shm));
|
||||
(m.*block_map)()[addr] = std::make_pair(size, std::move(shm));
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -1147,6 +1152,7 @@ namespace vm
|
||||
|
||||
block_t::~block_t()
|
||||
{
|
||||
auto& m_map = (m.*block_map)();
|
||||
{
|
||||
vm::writer_lock lock(0);
|
||||
|
||||
@ -1285,6 +1291,7 @@ namespace vm
|
||||
|
||||
u32 block_t::dealloc(u32 addr, const std::shared_ptr<utils::shm>* src)
|
||||
{
|
||||
auto& m_map = (m.*block_map)();
|
||||
{
|
||||
vm::writer_lock lock(0);
|
||||
|
||||
@ -1334,6 +1341,8 @@ namespace vm
|
||||
return {addr, nullptr};
|
||||
}
|
||||
|
||||
auto& m_map = (m.*block_map)();
|
||||
|
||||
vm::reader_lock lock;
|
||||
|
||||
const auto upper = m_map.upper_bound(addr);
|
||||
@ -1370,7 +1379,7 @@ namespace vm
|
||||
{
|
||||
u32 result = 0;
|
||||
|
||||
for (auto& entry : m_map)
|
||||
for (auto& entry : (m.*block_map)())
|
||||
{
|
||||
result += entry.second.first - (flags & 0x10 ? 0x2000 : 0);
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include "util/types.hpp"
|
||||
#include "util/atomic.hpp"
|
||||
#include "util/auto_typemap.hpp"
|
||||
#include "Utilities/StrFmt.h"
|
||||
|
||||
#include "util/to_endian.hpp"
|
||||
@ -95,8 +95,7 @@ namespace vm
|
||||
// Object that handles memory allocations inside specific constant bounds ("location")
|
||||
class block_t final
|
||||
{
|
||||
// Mapped regions: addr -> shm handle
|
||||
std::map<u32, std::pair<u32, std::shared_ptr<utils::shm>>> m_map;
|
||||
auto_typemap<block_t> m;
|
||||
|
||||
// Common mapped region for special cases
|
||||
std::shared_ptr<utils::shm> m_common;
|
||||
|
@ -495,6 +495,7 @@
|
||||
<ClInclude Include="..\Utilities\sync.h" />
|
||||
<ClInclude Include="util\endian.hpp" />
|
||||
<ClInclude Include="util\fixed_typemap.hpp" />
|
||||
<ClInclude Include="util\auto_typemap.hpp" />
|
||||
<ClInclude Include="util\init_mutex.hpp" />
|
||||
<ClInclude Include="util\logs.hpp" />
|
||||
<ClInclude Include="..\Utilities\dyn_lib.hpp" />
|
||||
|
@ -1822,6 +1822,9 @@
|
||||
<ClInclude Include="util\fixed_typemap.hpp">
|
||||
<Filter>Utilities</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="util\auto_typemap.hpp">
|
||||
<Filter>Utilities</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="util\init_mutex.hpp">
|
||||
<Filter>Utilities</Filter>
|
||||
</ClInclude>
|
||||
|
@ -7,6 +7,9 @@
|
||||
#include "Utilities/File.h"
|
||||
#include "util/logs.hpp"
|
||||
#include "util/shared_ptr.hpp"
|
||||
#include "util/typeindices.hpp"
|
||||
#include "util/fixed_typemap.hpp"
|
||||
#include "util/auto_typemap.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
175
rpcs3/util/auto_typemap.hpp
Normal file
175
rpcs3/util/auto_typemap.hpp
Normal file
@ -0,0 +1,175 @@
|
||||
#pragma once
|
||||
|
||||
#include "util/typeindices.hpp"
|
||||
|
||||
#include <utility>
|
||||
#include <type_traits>
|
||||
|
||||
namespace stx
|
||||
{
|
||||
// Simplified typemap with exactly one object of each used type, non-moveable.
|
||||
template <typename Tag /*Tag should be unique*/>
|
||||
class auto_typemap
|
||||
{
|
||||
// Save default constructor and destructor
|
||||
struct typeinfo
|
||||
{
|
||||
void(*create)(void*& ptr, auto_typemap&) noexcept;
|
||||
void(*destroy)(void* ptr) noexcept;
|
||||
|
||||
template <typename T>
|
||||
static void call_ctor(void*& ptr, auto_typemap& _this) noexcept
|
||||
{
|
||||
// Don't overwrite if already exists
|
||||
if (!ptr)
|
||||
{
|
||||
// Allow passing reference to "this"
|
||||
if constexpr (std::is_constructible_v<T, auto_typemap&>)
|
||||
{
|
||||
ptr = new T(_this);
|
||||
return;
|
||||
}
|
||||
|
||||
// Call default constructor only if available
|
||||
if constexpr (std::is_default_constructible_v<T>)
|
||||
{
|
||||
ptr = new T();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void call_dtor(void* ptr) noexcept
|
||||
{
|
||||
delete static_cast<T*>(ptr);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static typeinfo make_typeinfo()
|
||||
{
|
||||
typeinfo r;
|
||||
r.create = &call_ctor<T>;
|
||||
r.destroy = &call_dtor<T>;
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
||||
// Raw pointers to existing objects (may be nullptr)
|
||||
void** m_list;
|
||||
|
||||
// Creation order for each object (used to reverse destruction order)
|
||||
void** m_order;
|
||||
|
||||
// Helper for destroying in reverse order
|
||||
const typeinfo** m_info;
|
||||
|
||||
public:
|
||||
auto_typemap() noexcept
|
||||
: m_list(new void*[stx::typelist<typeinfo>().count()]{})
|
||||
, m_order(new void*[stx::typelist<typeinfo>().count()])
|
||||
, m_info(new const typeinfo*[stx::typelist<typeinfo>().count()])
|
||||
{
|
||||
for (const auto& type : stx::typelist<typeinfo>())
|
||||
{
|
||||
const unsigned id = type.index();
|
||||
|
||||
type.create(m_list[id], *this);
|
||||
|
||||
// Allocate initialization order id
|
||||
if (m_list[id])
|
||||
{
|
||||
*m_order++ = m_list[id];
|
||||
*m_info++ = &type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto_typemap(const auto_typemap&) = delete;
|
||||
|
||||
auto_typemap& operator=(const auto_typemap&) = delete;
|
||||
|
||||
~auto_typemap()
|
||||
{
|
||||
// Get actual number of created objects
|
||||
unsigned _max = 0;
|
||||
|
||||
for (const auto& type : stx::typelist<typeinfo>())
|
||||
{
|
||||
if (m_list[type.index()])
|
||||
{
|
||||
// Skip object if not created
|
||||
_max++;
|
||||
}
|
||||
}
|
||||
|
||||
// Destroy objects in reverse order
|
||||
for (; _max; _max--)
|
||||
{
|
||||
(*--m_info)->destroy(*--m_order);
|
||||
}
|
||||
|
||||
// Pointers should be restored to their positions
|
||||
delete[] m_info;
|
||||
delete[] m_order;
|
||||
delete[] m_list;
|
||||
}
|
||||
|
||||
// Check if object is not initialized but shall be initialized first (to use in initializing other objects)
|
||||
template <typename T>
|
||||
void need() noexcept
|
||||
{
|
||||
if (!m_list[stx::typeindex<typeinfo, std::decay_t<T>>()])
|
||||
{
|
||||
if constexpr (std::is_constructible_v<T, auto_typemap&>)
|
||||
{
|
||||
init<T>(*this);
|
||||
return;
|
||||
}
|
||||
|
||||
if constexpr (std::is_default_constructible_v<T>)
|
||||
{
|
||||
init<T>();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Explicitly initialize object of type T possibly with dynamic type As and arguments
|
||||
template <typename T, typename As = T, typename... Args>
|
||||
As* init(Args&&... args) noexcept
|
||||
{
|
||||
auto& ptr = m_list[stx::typeindex<typeinfo, std::decay_t<T>>()];
|
||||
|
||||
if (ptr)
|
||||
{
|
||||
// Already exists, recreation is not supported (may be added later)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
As* obj = new std::decay_t<As>(std::forward<Args>(args)...);
|
||||
*m_order++ = obj;
|
||||
*m_info++ = &stx::typedata<typeinfo, std::decay_t<T>>();
|
||||
ptr = static_cast<T*>(obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
// CTAD adaptor for init (see init description), accepts template not type
|
||||
template <template <class...> typename Template, typename... Args>
|
||||
auto init(Args&&... args) noexcept
|
||||
{
|
||||
// Deduce the type from given template and its arguments
|
||||
using T = decltype(Template(std::forward<Args>(args)...));
|
||||
return init<T>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// Obtain object reference
|
||||
template <typename T>
|
||||
T& get() const noexcept
|
||||
{
|
||||
return *static_cast<T*>(m_list[stx::typeindex<typeinfo, std::decay_t<T>>()]);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
using stx::auto_typemap;
|
@ -135,4 +135,11 @@ namespace stx
|
||||
{
|
||||
return type_counter<Info>::template type<T>.index();
|
||||
}
|
||||
|
||||
// Type info accessor
|
||||
template <typename Info, typename T>
|
||||
inline const Info& typedata() noexcept
|
||||
{
|
||||
return type_counter<Info>::template type<T>;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user