1
0
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:
Nekotekina 2020-12-24 14:55:25 +03:00
parent c94a98e15a
commit 567d23d856
7 changed files with 204 additions and 7 deletions

View File

@ -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);
}

View File

@ -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;

View File

@ -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" />

View File

@ -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>

View File

@ -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
View 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;

View File

@ -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>;
}
}