From a07e10344fea0002f61631a047a40a9c2c6977ac Mon Sep 17 00:00:00 2001 From: Akash Mozumdar Date: Sat, 9 Feb 2019 00:30:38 -0500 Subject: [PATCH] performance optimizations --- GUI/extenwindow.cpp | 48 +++++++++++++++++-------------------- GUI/extenwindow.h | 8 ++++++- GUI/host/host.cpp | 4 ++-- GUI/host/textthread.cpp | 22 ++++++++--------- GUI/host/textthread.h | 4 ++-- GUI/mainwindow.cpp | 39 +++++++++++++----------------- GUI/mainwindow.h | 4 +++- extensions/extension.h | 7 +++--- extensions/removerepeat.cpp | 2 +- include/common.h | 2 ++ 10 files changed, 70 insertions(+), 70 deletions(-) diff --git a/GUI/extenwindow.cpp b/GUI/extenwindow.cpp index 84b4f11..db7b30b 100644 --- a/GUI/extenwindow.cpp +++ b/GUI/extenwindow.cpp @@ -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 extensions; - QStringList extenNames; + std::vector 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 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 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(); } } diff --git a/GUI/extenwindow.h b/GUI/extenwindow.h index f6fa898..1391623 100644 --- a/GUI/extenwindow.h +++ b/GUI/extenwindow.h @@ -7,7 +7,13 @@ namespace Ui class ExtenWindow; } -bool DispatchSentenceToExtensions(std::wstring& sentence, std::unordered_map miscInfo); +struct InfoForExtension +{ + const char* name; + int64_t value; +}; + +bool DispatchSentenceToExtensions(std::wstring& sentence, const InfoForExtension* miscInfo); class ExtenWindow : public QMainWindow { diff --git a/GUI/host/host.cpp b/GUI/host/host.cpp index 7e52d7e..ad890ef 100644 --- a/GUI/host/host.cpp +++ b/GUI/host/host.cpp @@ -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)); } } diff --git a/GUI/host/textthread.cpp b/GUI/host/textthread.cpp index 65bdce8..80c21e2 100644 --- a/GUI/host/textthread.cpp +++ b/GUI/host/textthread.cpp @@ -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(); } } diff --git a/GUI/host/textthread.h b/GUI/host/textthread.h index de0622b..f93c985 100644 --- a/GUI/host/textthread.h +++ b/GUI/host/textthread.h @@ -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 storage; const int64_t handle; diff --git a/GUI/mainwindow.cpp b/GUI/mainwindow.cpp index f05f5d9..a6a94da 100644 --- a/GUI/mainwindow.cpp +++ b/GUI/mainwindow.cpp @@ -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,22 +145,15 @@ void MainWindow::ThreadRemoved(TextThread& thread) bool MainWindow::SentenceReceived(TextThread& thread, std::wstring& sentence) { - if (DispatchSentenceToExtensions(sentence, GetMiscInfo(thread))) + if (!DispatchSentenceToExtensions(sentence, GetMiscInfo(thread).data())) return false; + sentence += L'\n'; + if (current == &thread) QMetaObject::invokeMethod(this, [this, sentence] { - sentence += L"\n"; - QString ttString = TextThreadString(thread); - QMetaObject::invokeMethod(this, [this, ttString, sentence] - { - if (ui->ttCombo->currentText().startsWith(ttString)) - { - ui->textOutput->moveCursor(QTextCursor::End); - ui->textOutput->insertPlainText(S(sentence)); - ui->textOutput->moveCursor(QTextCursor::End); - } - }); - return true; - } - return false; + ui->textOutput->moveCursor(QTextCursor::End); + ui->textOutput->insertPlainText(S(sentence)); + ui->textOutput->moveCursor(QTextCursor::End); + }); + return true; } QString MainWindow::TextThreadString(TextThread& thread) @@ -184,17 +178,18 @@ DWORD MainWindow::GetSelectedProcessId() return ui->processCombo->currentText().split(":")[0].toULong(nullptr, 16); } -std::unordered_map MainWindow::GetMiscInfo(TextThread& thread) +std::array 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); } diff --git a/GUI/mainwindow.h b/GUI/mainwindow.h index c7b82ed..8112901 100644 --- a/GUI/mainwindow.h +++ b/GUI/mainwindow.h @@ -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 GetMiscInfo(TextThread& thread); + std::array GetMiscInfo(TextThread& thread); void AttachProcess(); void LaunchProcess(); void DetachProcess(); @@ -40,4 +41,5 @@ private: QWidget* extenWindow; std::pair savedThreadCtx; wchar_t savedThreadCode[1000]; + std::atomic current; }; diff --git a/extensions/extension.h b/extensions/extension.h index 7c0129f..f7805e5 100644 --- a/extensions/extension.h +++ b/extensions/extension.h @@ -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; } }; diff --git a/extensions/removerepeat.cpp b/extensions/removerepeat.cpp index 0af7847..3a66393 100644 --- a/extensions/removerepeat.cpp +++ b/extensions/removerepeat.cpp @@ -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 }); diff --git a/include/common.h b/include/common.h index 3f8e5f1..5e92080 100644 --- a/include/common.h +++ b/include/common.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -14,5 +15,6 @@ #include #include #include +#include #include #include