rpcsx/rpcs3/Emu/ARMv7/PSVObjectList.h

125 lines
2.4 KiB
C
Raw Normal View History

2015-01-25 23:38:50 +01:00
#pragma once
2015-01-26 07:13:11 +01:00
union psv_uid_t
2015-01-25 23:38:50 +01:00
{
// true UID format is partially unknown
s32 uid;
struct
{
u32 oddness : 1; // always 1 for UIDs (to not mess it up with addresses)
u32 number : 15; // ID from 0 to 2^15-1
u32 type : 15; // UID class (psv_object_class_t)
u32 sign : 1; // UIDs are positive, error codes are negative
};
2015-01-26 07:13:11 +01:00
static psv_uid_t make(s32 uid)
2015-01-25 23:38:50 +01:00
{
2015-01-26 07:13:11 +01:00
psv_uid_t result;
2015-01-25 23:38:50 +01:00
result.uid = uid;
return result;
}
};
2015-05-25 20:12:53 +02:00
template<typename T, u32 uid_class>
2015-01-25 23:38:50 +01:00
class psv_object_list_t // Class for managing object data
{
2015-05-25 20:12:53 +02:00
std::array<std::shared_ptr<T>, 0x8000> m_data;
std::atomic<u32> m_hint; // guessing next free position
2015-05-25 20:12:53 +02:00
std::mutex m_mutex;
2015-03-03 21:09:23 +01:00
public:
2015-03-03 21:09:23 +01:00
psv_object_list_t()
: m_hint(0)
{
}
2015-03-03 21:09:23 +01:00
// check if UID is potentially valid (will return true even if the object doesn't exist)
2015-05-25 20:12:53 +02:00
inline static bool check(s32 uid)
2015-01-25 23:38:50 +01:00
{
2015-01-26 07:13:11 +01:00
const psv_uid_t id = psv_uid_t::make(uid);
2015-01-25 23:38:50 +01:00
// check sign bit, uid class and ensure that value is odd
return !id.sign && id.type == uid_class && id.oddness == 1;
}
2015-03-03 21:09:23 +01:00
// share object with UID specified
inline std::shared_ptr<T> get(s32 uid)
2015-01-25 23:38:50 +01:00
{
if (!check(uid))
{
2015-05-25 20:12:53 +02:00
return nullptr;
2015-01-25 23:38:50 +01:00
}
2015-05-25 20:12:53 +02:00
std::lock_guard<std::mutex> lock(m_mutex);
return m_data[psv_uid_t::make(uid).number];
2015-01-25 23:38:50 +01:00
}
inline std::shared_ptr<T> operator [](s32 uid)
2015-01-25 23:38:50 +01:00
{
2015-05-25 20:12:53 +02:00
return this->get(uid);
2015-01-25 23:38:50 +01:00
}
2015-05-25 20:12:53 +02:00
// create new object and generate UID for it, or do nothing and return zero (if limit reached)
template<typename... Args> s32 create(Args&&... args)
2015-01-25 23:38:50 +01:00
{
2015-05-25 20:12:53 +02:00
std::lock_guard<std::mutex> lock(m_mutex);
2015-03-03 21:09:23 +01:00
for (u32 i = 0, j = m_hint; i < m_data.size(); i++, j = (j + 1) % m_data.size())
2015-01-25 23:38:50 +01:00
{
// find an empty position and copy the pointer
2015-05-25 20:12:53 +02:00
if (!m_data[j])
2015-01-25 23:38:50 +01:00
{
2015-05-25 20:12:53 +02:00
m_data[j] = std::make_shared<T>(args...); // construct object with specified arguments
2015-03-03 21:09:23 +01:00
m_hint = (j + 1) % m_data.size(); // guess next position
psv_uid_t id = psv_uid_t::make(1); // make UID
id.type = uid_class;
id.number = j;
return id.uid; // return UID
2015-01-25 23:38:50 +01:00
}
}
2015-05-25 20:12:53 +02:00
return 0;
2015-01-25 23:38:50 +01:00
}
2015-03-03 21:09:23 +01:00
// remove object with specified UID
bool remove(s32 uid)
2015-01-25 23:38:50 +01:00
{
if (!check(uid))
{
2015-03-03 21:09:23 +01:00
return false;
2015-01-25 23:38:50 +01:00
}
2015-05-25 20:12:53 +02:00
std::lock_guard<std::mutex> lock(m_mutex);
const u32 pos = psv_uid_t::make(uid).number;
2015-03-03 21:09:23 +01:00
m_hint = std::min<u32>(pos, m_hint);
2015-01-26 13:55:26 +01:00
2015-05-25 20:12:53 +02:00
if (!m_data[pos])
{
return false;
}
m_data[pos].reset();
return true;
2015-01-25 23:38:50 +01:00
}
// remove all objects
void clear()
{
2015-05-25 20:12:53 +02:00
std::lock_guard<std::mutex> lock(m_mutex);
2015-03-03 21:09:23 +01:00
for (auto& v : m_data)
2015-01-25 23:38:50 +01:00
{
2015-05-25 20:12:53 +02:00
v.reset();
2015-01-25 23:38:50 +01:00
}
m_hint = 0;
2015-01-25 23:38:50 +01:00
}
};