performance optimizations

This commit is contained in:
Akash Mozumdar 2019-02-09 00:30:38 -05:00
parent d6b39eb2c3
commit a07e10344f
10 changed files with 70 additions and 70 deletions

View File

@ -12,57 +12,53 @@
namespace
{
struct InfoForExtension
struct Extension
{
const char* name;
int64_t value;
InfoForExtension* next;
~InfoForExtension() { if (next) delete next; };
std::wstring name;
wchar_t*(*callback)(wchar_t*, const InfoForExtension*);
};
QHash<QString, wchar_t*(*)(wchar_t*, const InfoForExtension*)> extensions;
QStringList extenNames;
std::vector<Extension> extensions;
std::shared_mutex extenMutex;
void Load(QString extenName)
{
if (extenName == ITH_DLL) return;
// Extension is dll and exports "OnNewSentence"
if (FARPROC callback = GetProcAddress(LoadLibraryOnce(S(extenName)), "OnNewSentence"))
if (auto callback = (decltype(Extension::callback))GetProcAddress(LoadLibraryOnce(S(extenName)), "OnNewSentence"))
{
std::scoped_lock writeLock(extenMutex);
extensions[extenName] = (wchar_t*(*)(wchar_t*, const InfoForExtension*))callback;
extenNames.push_back(extenName);
extensions.push_back({ S(extenName), callback });
}
}
void Unload(QString extenName)
void Unload(int index)
{
std::scoped_lock writeLock(extenMutex);
extenNames.erase(std::remove(extenNames.begin(), extenNames.end(), extenName), extenNames.end());
FreeLibrary(GetModuleHandleW(S(extenName).c_str()));
FreeLibrary(GetModuleHandleW(extensions.at(index).name.c_str()));
extensions.erase(extensions.begin() + index);
}
void Reorder(QStringList extenNames)
{
std::scoped_lock writeLock(extenMutex);
::extenNames = extenNames;
std::vector<Extension> extensions;
for (auto extenName : extenNames)
extensions.push_back(*std::find_if(::extensions.begin(), ::extensions.end(), [&](auto extension) { return extension.name == S(extenName); }));
::extensions = extensions;
}
}
bool DispatchSentenceToExtensions(std::wstring& sentence, std::unordered_map<const char*, int64_t> miscInfo)
bool DispatchSentenceToExtensions(std::wstring& sentence, const InfoForExtension* miscInfo)
{
wchar_t* sentenceBuffer = (wchar_t*)HeapAlloc(GetProcessHeap(), 0, (sentence.size() + 1) * sizeof(wchar_t));
wcscpy_s(sentenceBuffer, sentence.size() + 1, sentence.c_str());
InfoForExtension miscInfoLinkedList{ "", 0, nullptr };
InfoForExtension* miscInfoTraverser = &miscInfoLinkedList;
for (auto[name, value] : miscInfo) miscInfoTraverser = miscInfoTraverser->next = new InfoForExtension{ name, value, nullptr };
std::shared_lock readLock(extenMutex);
for (auto extenName : extenNames)
for (const auto& extension : extensions)
{
wchar_t* nextBuffer = extensions[extenName](sentenceBuffer, &miscInfoLinkedList);
wchar_t* nextBuffer = extension.callback(sentenceBuffer, miscInfo);
if (nextBuffer != sentenceBuffer) HeapFree(GetProcessHeap(), 0, sentenceBuffer);
if (nextBuffer == nullptr) return false;
sentenceBuffer = nextBuffer;
@ -99,10 +95,10 @@ void ExtenWindow::Sync()
ui->extenList->clear();
QTextFile extenSaveFile(EXTEN_SAVE_FILE, QIODevice::WriteOnly | QIODevice::Truncate);
std::shared_lock readLock(extenMutex);
for (auto extenName : extenNames)
for (auto extension : extensions)
{
ui->extenList->addItem(extenName);
extenSaveFile.write((extenName + ">").toUtf8());
ui->extenList->addItem(S(extension.name));
extenSaveFile.write((S(extension.name) + ">").toUtf8());
}
}
@ -129,9 +125,9 @@ bool ExtenWindow::eventFilter(QObject* target, QEvent* event)
void ExtenWindow::keyPressEvent(QKeyEvent* event)
{
if (event->key() == Qt::Key_Delete) if (auto extenName = ui->extenList->currentItem())
if (event->key() == Qt::Key_Delete && ui->extenList->currentItem() != nullptr)
{
Unload(extenName->text());
Unload(ui->extenList->currentIndex().row());
Sync();
}
}

View File

@ -7,7 +7,13 @@ namespace Ui
class ExtenWindow;
}
bool DispatchSentenceToExtensions(std::wstring& sentence, std::unordered_map<const char*, int64_t> miscInfo);
struct InfoForExtension
{
const char* name;
int64_t value;
};
bool DispatchSentenceToExtensions(std::wstring& sentence, const InfoForExtension* miscInfo);
class ExtenWindow : public QMainWindow
{

View File

@ -151,7 +151,7 @@ namespace Host
SetWindowsHookExW(WH_GETMESSAGE, [](int statusCode, WPARAM wParam, LPARAM lParam)
{
if (statusCode == HC_ACTION && wParam == PM_REMOVE && ((MSG*)lParam)->message == WM_CLIPBOARDUPDATE)
if (auto text = Util::GetClipboardText()) GetThread(clipboard).AddSentence(text.value());
if (auto text = Util::GetClipboardText()) GetThread(clipboard).AddSentence(std::move(text.value()));
return CallNextHookEx(NULL, statusCode, wParam, lParam);
}, NULL, GetCurrentThreadId());
}
@ -219,6 +219,6 @@ namespace Host
void AddConsoleOutput(std::wstring text)
{
GetThread(console).AddSentence(text);
GetThread(console).AddSentence(std::move(text));
}
}

View File

@ -21,23 +21,23 @@ void TextThread::Stop()
timer = NULL;
}
void TextThread::AddSentence(const std::wstring& sentence)
void TextThread::AddSentence(std::wstring&& sentence)
{
queuedSentences->push_back(sentence);
queuedSentences->emplace_back(std::move(sentence));
}
void TextThread::Push(const BYTE* data, int len)
void TextThread::Push(const BYTE* data, int length)
{
if (len < 0) return;
if (length < 0) return;
std::scoped_lock lock(bufferMutex);
BYTE doubleByteChar[2];
if (len == 1) // doublebyte characters must be processed as pairs
if (leadByte) std::tie(doubleByteChar[0], doubleByteChar[1], data, len, leadByte) = std::tuple(leadByte, data[0], doubleByteChar, 2, 0 );
else if (IsDBCSLeadByteEx(hp.codepage ? hp.codepage : Host::defaultCodepage, data[0])) std::tie(leadByte, len) = std::tuple(data[0], 0);
if (length == 1) // doublebyte characters must be processed as pairs
if (leadByte) std::tie(doubleByteChar[0], doubleByteChar[1], data, length, leadByte) = std::tuple(leadByte, data[0], doubleByteChar, 2, 0 );
else if (IsDBCSLeadByteEx(hp.codepage ? hp.codepage : Host::defaultCodepage, data[0])) std::tie(leadByte, length) = std::tuple(data[0], 0);
if (hp.type & USING_UNICODE) buffer += std::wstring((wchar_t*)data, len / 2);
else if (auto converted = Util::StringToWideString(std::string((char*)data, len), hp.codepage ? hp.codepage : Host::defaultCodepage)) buffer += converted.value();
if (hp.type & USING_UNICODE) buffer += std::wstring((wchar_t*)data, length / sizeof(wchar_t));
else if (auto converted = Util::StringToWideString(std::string((char*)data, length), hp.codepage ? hp.codepage : Host::defaultCodepage)) buffer += converted.value();
else Host::AddConsoleOutput(INVALID_CODEPAGE);
lastPushTime = GetTickCount();
@ -47,7 +47,7 @@ void TextThread::Push(const BYTE* data, int len)
if (Util::RemoveRepetition(buffer)) // sentence repetition detected, which means the entire sentence has already been received
{
repeatingChars = std::unordered_set(buffer.begin(), buffer.end());
AddSentence(buffer);
AddSentence(std::move(buffer));
buffer.clear();
}
}
@ -64,7 +64,7 @@ void TextThread::Flush()
if (buffer.empty()) return;
if (buffer.size() > maxBufferSize || GetTickCount() - lastPushTime > flushDelay)
{
AddSentence(buffer);
AddSentence(std::move(buffer));
buffer.clear();
}
}

View File

@ -17,8 +17,8 @@ public:
void Start();
void Stop();
void AddSentence(const std::wstring& sentence);
void Push(const BYTE* data, int len);
void AddSentence(std::wstring&& sentence);
void Push(const BYTE* data, int length);
ThreadSafe<std::wstring> storage;
const int64_t handle;

View File

@ -55,6 +55,7 @@ MainWindow::MainWindow(QWidget *parent) :
[this](TextThread& thread) { ThreadRemoved(thread); },
[this](TextThread& thread, std::wstring& output) { return SentenceReceived(thread, output); }
);
current = &Host::GetThread(Host::console);
Host::AddConsoleOutput(ABOUT);
std::thread([]
@ -144,23 +145,16 @@ void MainWindow::ThreadRemoved(TextThread& thread)
bool MainWindow::SentenceReceived(TextThread& thread, std::wstring& sentence)
{
if (DispatchSentenceToExtensions(sentence, GetMiscInfo(thread)))
{
sentence += L"\n";
QString ttString = TextThreadString(thread);
QMetaObject::invokeMethod(this, [this, ttString, sentence]
{
if (ui->ttCombo->currentText().startsWith(ttString))
if (!DispatchSentenceToExtensions(sentence, GetMiscInfo(thread).data())) return false;
sentence += L'\n';
if (current == &thread) QMetaObject::invokeMethod(this, [this, sentence]
{
ui->textOutput->moveCursor(QTextCursor::End);
ui->textOutput->insertPlainText(S(sentence));
ui->textOutput->moveCursor(QTextCursor::End);
}
});
return true;
}
return false;
}
QString MainWindow::TextThreadString(TextThread& thread)
{
@ -184,17 +178,18 @@ DWORD MainWindow::GetSelectedProcessId()
return ui->processCombo->currentText().split(":")[0].toULong(nullptr, 16);
}
std::unordered_map<const char*, int64_t> MainWindow::GetMiscInfo(TextThread& thread)
std::array<InfoForExtension, 10> MainWindow::GetMiscInfo(TextThread& thread)
{
return
{
{ "current select", ui->ttCombo->currentText().startsWith(TextThreadString(thread)) },
{ {
{ "current select", &thread == current },
{ "text number", thread.handle },
{ "process id", thread.tp.processId },
{ "hook address", thread.tp.addr },
{ "hook address", (int64_t)thread.tp.addr },
{ "text handle", thread.handle },
{ "text name", (int64_t)thread.name.c_str() }
};
{ "text name", (int64_t)thread.name.c_str() },
{ nullptr, 0 } // nullptr marks end of info array
} };
}
void MainWindow::AttachProcess()
@ -339,6 +334,6 @@ void MainWindow::Extensions()
void MainWindow::ViewThread(int index)
{
ui->ttCombo->setCurrentIndex(index);
ui->textOutput->setPlainText(S(Host::GetThread(ParseTextThreadString(ui->ttCombo->itemText(index))).storage->c_str()));
ui->textOutput->setPlainText(S((current = &Host::GetThread(ParseTextThreadString(ui->ttCombo->itemText(index))))->storage->c_str()));
ui->textOutput->moveCursor(QTextCursor::End);
}

View File

@ -1,6 +1,7 @@
#pragma once
#include "qtcommon.h"
#include "extenwindow.h"
#include "host/host.h"
namespace Ui
@ -26,7 +27,7 @@ private:
QString TextThreadString(TextThread& thread);
ThreadParam ParseTextThreadString(QString ttString);
DWORD GetSelectedProcessId();
std::unordered_map<const char*, int64_t> GetMiscInfo(TextThread& thread);
std::array<InfoForExtension, 10> GetMiscInfo(TextThread& thread);
void AttachProcess();
void LaunchProcess();
void DetachProcess();
@ -40,4 +41,5 @@ private:
QWidget* extenWindow;
std::pair<uint64_t, uint64_t> savedThreadCtx;
wchar_t savedThreadCode[1000];
std::atomic<TextThread*> current;
};

View File

@ -6,16 +6,15 @@ struct InfoForExtension
{
const char* name;
int64_t value;
InfoForExtension* next;
};
struct SentenceInfo
{
const InfoForExtension* list;
// Traverse linked list to find info.
const InfoForExtension* infoArray;
// nullptr marks end of info array
int64_t operator[](std::string propertyName)
{
for (auto i = list; i != nullptr; i = i->next) if (propertyName == i->name) return i->value;
for (auto info = infoArray; info->name != nullptr; ++info) if (propertyName == info->name) return info->value;
throw;
}
};

View File

@ -61,7 +61,7 @@ TEST(
RemoveCyclicRepeats(cyclicRepeats);
assert(cyclicRepeats == L"abcdefg");
InfoForExtension tester{ "hook address", 0, nullptr };
InfoForExtension tester{ "hook address", 0 };
std::wstring empty = L"", one = L" ", normal = L"This is a normal sentence. はい";
ProcessSentence(empty, { &tester });
ProcessSentence(one, { &tester });

View File

@ -4,6 +4,7 @@
#include <Windows.h>
#include <string>
#include <vector>
#include <array>
#include <unordered_map>
#include <unordered_set>
#include <functional>
@ -14,5 +15,6 @@
#include <thread>
#include <mutex>
#include <shared_mutex>
#include <atomic>
#include <cstdint>
#include <cassert>