diff --git a/QVectorSearch/CMakeLists.txt b/QVectorSearch/CMakeLists.txt index 3193977..6b4aaac 100644 --- a/QVectorSearch/CMakeLists.txt +++ b/QVectorSearch/CMakeLists.txt @@ -33,7 +33,8 @@ else() endif() endif() -target_link_libraries(QVectorSearch PRIVATE Qt${QT_VERSION_MAJOR}::Widgets) +target_link_libraries(QVectorSearch PRIVATE Qt${QT_VERSION_MAJOR}::Widgets + vector_search) # Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1. If # you are developing for iOS or macOS you should consider setting an explicit, diff --git a/QVectorSearch/mainwindow.cpp b/QVectorSearch/mainwindow.cpp index df8aa76..81bd7fd 100644 --- a/QVectorSearch/mainwindow.cpp +++ b/QVectorSearch/mainwindow.cpp @@ -1,9 +1,95 @@ #include "mainwindow.h" #include "./ui_mainwindow.h" +#include "finder.h" +#include "linear_finder.h" +#include "parallel_finder.h" +#include "timer.h" +#include "word_list_generator.h" + +#include + MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); + + ui->resultView->setModel(&result_model_); + ui->searchAlgorithmSelector->setModel(&search_algorithms_); + + setupAlgorithmSelector(); + generateWordList(); } MainWindow::~MainWindow() { delete ui; } + +void MainWindow::setupAlgorithmSelector() { + search_algorithms_.appendRow(new QStandardItem("Linear search")); + search_algorithms_.appendRow(new QStandardItem("Parallel search")); +} + +void MainWindow::generateWordList() { + Timer timer; + word_list_ = WordListGenerator().generate(); + timer.stop(); + + std::stringstream status_message; + status_message << "generated " << word_list_.size() << " words in " << timer; + ui->mainStatusBar->showMessage(QString::fromStdString(status_message.str())); + + QStringList words; + for (auto word : word_list_) { + words.append(QString::fromStdString(word)); + } + + result_model_.setStringList(words); +} + +void MainWindow::search(const QString &search_term) { + if (search_term.isEmpty()) { + result_model_.setStringList(QStringList()); + ui->mainStatusBar->clearMessage(); + return; + } + + Timer timer; + const auto finder = createSelectedFinder(); + const auto results = finder->find_prefix(search_term.toStdString()); + timer.stop(); + + std::stringstream status_message; + status_message << "search took " << timer << ", found " << results.size() + << " results"; + ui->mainStatusBar->showMessage(QString::fromStdString(status_message.str())); + + showResults(results); +} + +std::unique_ptr MainWindow::createSelectedFinder() const { + auto selectedFinder = ui->searchAlgorithmSelector->currentIndex(); + + switch (selectedFinder) { + case 0: + default: + return std::make_unique(word_list_); + case 1: + return std::make_unique( + word_list_, std::thread::hardware_concurrency()); + } +} + +void MainWindow::showResults(const std::vector &results) { + QStringList ui_results; + for (auto word : results) { + ui_results.append(QString::fromStdString(*word)); + } + + result_model_.setStringList(ui_results); +} + +void MainWindow::on_searchInput_textChanged(const QString &search_term) { + search(search_term); +} + +void MainWindow::on_searchAlgorithmSelector_currentIndexChanged(int) { + search(ui->searchInput->displayText()); +} diff --git a/QVectorSearch/mainwindow.h b/QVectorSearch/mainwindow.h index 94cd27c..15ea3f8 100644 --- a/QVectorSearch/mainwindow.h +++ b/QVectorSearch/mainwindow.h @@ -1,7 +1,10 @@ #ifndef MAINWINDOW_H #define MAINWINDOW_H +#include "finder.h" #include +#include +#include QT_BEGIN_NAMESPACE namespace Ui { @@ -12,10 +15,26 @@ QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT +private: + std::vector word_list_; + QStringListModel result_model_; + QStandardItemModel search_algorithms_; + public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); +private: + void setupAlgorithmSelector(); + void generateWordList(); + void search(const QString &search_term); + std::unique_ptr createSelectedFinder() const; + void showResults(const std::vector &results); + +private slots: + void on_searchInput_textChanged(const QString &search_term); + void on_searchAlgorithmSelector_currentIndexChanged(int); + private: Ui::MainWindow *ui; }; diff --git a/QVectorSearch/mainwindow.ui b/QVectorSearch/mainwindow.ui index b232854..64e65ed 100644 --- a/QVectorSearch/mainwindow.ui +++ b/QVectorSearch/mainwindow.ui @@ -11,11 +11,86 @@ - MainWindow + QVectorSearch - - - + + false + + + + + 0 + 0 + + + + + 1920 + 1200 + + + + + + + QLayout::SetDefaultConstraint + + + + + Select search algorithm + + + + + + + + 0 + 0 + + + + <html><head/><body><p>Enter a search text</p></body></html> + + + + + + + + + + + 0 + 0 + + + + + + + + + + + 0 + 0 + + + + true + + + + + + + + + Option + + diff --git a/lib_vector_search/include/timer.h b/lib_vector_search/include/timer.h index 45226e4..e7fc1d6 100644 --- a/lib_vector_search/include/timer.h +++ b/lib_vector_search/include/timer.h @@ -1,16 +1,19 @@ #pragma once #include -#include class Timer { private: - std::string name_; std::chrono::time_point start_; + std::chrono::time_point end_; public: - Timer(std::string_view name); + Timer(); void start(); void stop(); + + long us() const; }; + +std::ostream &operator<<(std::ostream &os, const Timer &timer); diff --git a/lib_vector_search/src/timer.cpp b/lib_vector_search/src/timer.cpp index 43987b5..a663e3e 100644 --- a/lib_vector_search/src/timer.cpp +++ b/lib_vector_search/src/timer.cpp @@ -1,17 +1,32 @@ #include "timer.h" #include -#include -Timer::Timer(std::string_view name) : name_(name) { start(); }; +Timer::Timer() { start(); }; void Timer::start() { start_ = std::chrono::high_resolution_clock::now(); } -void Timer::stop() { - auto end = std::chrono::high_resolution_clock::now(); +void Timer::stop() { end_ = std::chrono::high_resolution_clock::now(); } - auto duration = - std::chrono::duration_cast(end - start_); - - std::cout << name_ << " took " << duration << std::endl; +long Timer::us() const { + return std::chrono::duration_cast(end_ - start_) + .count(); +} + +std::ostream &operator<<(std::ostream &os, const Timer &timer) { + long time = timer.us(); + + if (time >= 1e6) { + os << time / static_cast(1e6) << " s "; + time %= static_cast(1e6); + } + + if (time >= 1e3) { + os << time / static_cast(1e3) << " ms "; + time %= static_cast(1e3); + } + + os << time << " µs"; + + return os; } diff --git a/lib_vector_search/src/word_list_generator.cpp b/lib_vector_search/src/word_list_generator.cpp index 5863567..e4bdf52 100644 --- a/lib_vector_search/src/word_list_generator.cpp +++ b/lib_vector_search/src/word_list_generator.cpp @@ -7,7 +7,7 @@ const std::string WordListGenerator::charset_ = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; std::vector WordListGenerator::generate() { - const size_t multiplier = 10; + const size_t multiplier = 1; std::vector result; result.reserve(multiplier * std::pow(charset_.length(), 4)); diff --git a/vector_search_cli/main.cpp b/vector_search_cli/main.cpp index f9c356e..ace12f7 100644 --- a/vector_search_cli/main.cpp +++ b/vector_search_cli/main.cpp @@ -13,10 +13,11 @@ using std::string, std::string_view, std::vector, std::thread, std::cout, vector generate_word_list() { cout << "\ngenerating word list" << endl; - Timer generator_timer("word list generator"); + Timer generator_timer; auto word_list = WordListGenerator().generate(); generator_timer.stop(); + cout << "word list generator took " << generator_timer << endl; cout << "word list is " << word_list.size() << " element(s) long" << endl; return word_list; @@ -25,14 +26,15 @@ vector generate_word_list() { void test_linear_finder(const vector &word_list) { cout << "\nrunning linear finder" << endl; - Timer constructor_timer("linear finder constructor"); + Timer constructor_timer; LinearFinder linear_finder(word_list); constructor_timer.stop(); - Timer find_timer("linear finder find"); + Timer find_timer; auto result = linear_finder.find_prefix("ABCD"); find_timer.stop(); + cout << "linear finder took " << find_timer << endl; cout << "result list is " << result.size() << " element(s) long" << endl; } @@ -43,14 +45,15 @@ void test_parallel_finder(const vector &word_list) { cout << "using " << thread_count << " threads" << endl; - Timer constructor_timer("parallel finder constructor"); + Timer constructor_timer; ParallelFinder parallel_finder(word_list, thread_count); constructor_timer.stop(); - Timer find_timer("parallel finder find"); + Timer find_timer; auto result = parallel_finder.find_prefix("ABCD"); find_timer.stop(); + cout << "parallel finder took " << find_timer << endl; cout << "result list is " << result.size() << " element(s) long" << endl; }