Merge pull request #7448 from RolandMunsil/improve-cheat-search

Improve performance of cheat searching & add input validation
This commit is contained in:
Léo Lam 2019-05-26 18:07:49 +02:00 committed by GitHub
commit f819ea687a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 90 additions and 26 deletions

View File

@ -454,46 +454,101 @@ size_t CheatsManager::GetTypeSize() const
} }
} }
bool CheatsManager::MatchesSearch(u32 addr) const std::function<bool(u32)> CheatsManager::CreateMatchFunction()
{ {
const auto text = m_match_value->text(); const QString text = m_match_value->text();
const auto op = static_cast<CompareType>(m_match_operation->currentIndex());
if (text.isEmpty())
{
m_result_label->setText(tr("No search value entered."));
return nullptr;
}
const CompareType op = static_cast<CompareType>(m_match_operation->currentIndex());
const int base = const int base =
(m_match_decimal->isChecked() ? 10 : (m_match_hexadecimal->isChecked() ? 16 : 8)); (m_match_decimal->isChecked() ? 10 : (m_match_hexadecimal->isChecked() ? 16 : 8));
bool conversion_succeeded = false;
std::function<bool(u32)> matches_func;
switch (static_cast<DataType>(m_match_length->currentIndex())) switch (static_cast<DataType>(m_match_length->currentIndex()))
{ {
case DataType::Byte: case DataType::Byte:
return Compare<u8>(PowerPC::HostRead_U8(addr), text.toUShort(nullptr, base) & 0xFF, op); {
u8 comparison_value = text.toUShort(&conversion_succeeded, base) & 0xFF;
matches_func = [=](u32 addr) {
return Compare<u8>(PowerPC::HostRead_U8(addr), comparison_value, op);
};
break;
}
case DataType::Short: case DataType::Short:
return Compare(PowerPC::HostRead_U16(addr), text.toUShort(nullptr, base), op); {
u16 comparison_value = text.toUShort(&conversion_succeeded, base);
matches_func = [=](u32 addr) {
return Compare(PowerPC::HostRead_U16(addr), comparison_value, op);
};
break;
}
case DataType::Int: case DataType::Int:
return Compare(PowerPC::HostRead_U32(addr), text.toUInt(nullptr, base), op); {
u32 comparison_value = text.toUInt(&conversion_succeeded, base);
matches_func = [=](u32 addr) {
return Compare(PowerPC::HostRead_U32(addr), comparison_value, op);
};
break;
}
case DataType::Float: case DataType::Float:
return Compare(PowerPC::HostRead_F32(addr), text.toFloat(), op); {
float comparison_value = text.toFloat(&conversion_succeeded);
matches_func = [=](u32 addr) {
return Compare(PowerPC::HostRead_F32(addr), comparison_value, op);
};
break;
}
case DataType::Double: case DataType::Double:
return Compare(PowerPC::HostRead_F64(addr), text.toDouble(), op); {
double comparison_value = text.toDouble(&conversion_succeeded);
matches_func = [=](u32 addr) {
return Compare(PowerPC::HostRead_F64(addr), comparison_value, op);
};
break;
}
case DataType::String: case DataType::String:
{ {
bool is_equal = std::equal(text.toUtf8().cbegin(), text.toUtf8().cend(), if (op != CompareType::Equal && op != CompareType::NotEqual)
reinterpret_cast<char*>(Memory::m_pRAM + addr - 0x80000000));
// String only supports equals and not equals comparisons because the other ones frankly don't
// make any sense here
switch (op)
{ {
case CompareType::Equal: m_result_label->setText(tr("String values can only be compared using equality."));
return is_equal; return nullptr;
case CompareType::NotEqual:
return !is_equal;
default:
return false;
} }
conversion_succeeded = true;
const QString lambda_text = m_match_value->text();
const QByteArray utf8_bytes = lambda_text.toUtf8();
matches_func = [op, utf8_bytes](u32 addr) {
bool is_equal = std::equal(utf8_bytes.cbegin(), utf8_bytes.cend(),
reinterpret_cast<char*>(Memory::m_pRAM + addr - 0x80000000));
switch (op)
{
case CompareType::Equal:
return is_equal;
case CompareType::NotEqual:
return !is_equal;
default:
// This should never occur since we've already checked the type of op
return false;
}
};
break;
} }
} }
return false; if (conversion_succeeded)
return matches_func;
m_result_label->setText(tr("Cannot interpret the given value.\nHave you chosen the right type?"));
return nullptr;
} }
void CheatsManager::NewSearch() void CheatsManager::NewSearch()
@ -507,10 +562,14 @@ void CheatsManager::NewSearch()
return; return;
} }
std::function<bool(u32)> matches_func = CreateMatchFunction();
if (matches_func == nullptr)
return;
Core::RunAsCPUThread([&] { Core::RunAsCPUThread([&] {
for (u32 i = 0; i < Memory::REALRAM_SIZE - GetTypeSize(); i++) for (u32 i = 0; i < Memory::REALRAM_SIZE - GetTypeSize(); i++)
{ {
if (PowerPC::HostIsRAMAddress(base_address + i) && MatchesSearch(base_address + i)) if (PowerPC::HostIsRAMAddress(base_address + i) && matches_func(base_address + i))
m_results.push_back( m_results.push_back(
{base_address + i, static_cast<DataType>(m_match_length->currentIndex())}); {base_address + i, static_cast<DataType>(m_match_length->currentIndex())});
} }
@ -529,11 +588,15 @@ void CheatsManager::NextSearch()
return; return;
} }
Core::RunAsCPUThread([this] { std::function<bool(u32)> matches_func = CreateMatchFunction();
if (matches_func == nullptr)
return;
Core::RunAsCPUThread([this, matches_func] {
m_results.erase(std::remove_if(m_results.begin(), m_results.end(), m_results.erase(std::remove_if(m_results.begin(), m_results.end(),
[this](Result r) { [matches_func](Result r) {
return !PowerPC::HostIsRAMAddress(r.address) || return !PowerPC::HostIsRAMAddress(r.address) ||
!MatchesSearch(r.address); !matches_func(r.address);
}), }),
m_results.end()); m_results.end());
}); });

View File

@ -4,6 +4,7 @@
#pragma once #pragma once
#include <functional>
#include <memory> #include <memory>
#include <vector> #include <vector>
@ -48,7 +49,7 @@ private:
void OnStateChanged(Core::State state); void OnStateChanged(Core::State state);
size_t GetTypeSize() const; size_t GetTypeSize() const;
bool MatchesSearch(u32 addr) const; std::function<bool(u32)> CreateMatchFunction();
void Reset(); void Reset();
void NewSearch(); void NewSearch();