Compare commits

..

6 Commits

Author SHA1 Message Date
mandlm 9a855daabf
feat: reduce word list size 2024-03-20 10:47:38 +01:00
mandlm 2a8b342b91
feat: implement search 2024-03-20 10:47:05 +01:00
mandlm e2f9b630c5
feat: generate word list 2024-03-20 10:16:46 +01:00
mandlm 42b8c8d7e7
feat: implement ostream operator for timer 2024-03-20 10:13:08 +01:00
mandlm 64ae4c62a9
refactor: return numerical value from timer 2024-03-20 09:58:40 +01:00
mandlm f7634bdd95
feat: add ui layout 2024-03-20 09:34:54 +01:00
8 changed files with 224 additions and 22 deletions

View File

@ -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,

View File

@ -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 <thread>
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<Finder> MainWindow::createSelectedFinder() const {
auto selectedFinder = ui->searchAlgorithmSelector->currentIndex();
switch (selectedFinder) {
case 0:
default:
return std::make_unique<LinearFinder>(word_list_);
case 1:
return std::make_unique<ParallelFinder>(
word_list_, std::thread::hardware_concurrency());
}
}
void MainWindow::showResults(const std::vector<const std::string *> &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());
}

View File

@ -1,7 +1,10 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include "finder.h"
#include <QMainWindow>
#include <QStandardItemModel>
#include <QStringListModel>
QT_BEGIN_NAMESPACE
namespace Ui {
@ -12,10 +15,26 @@ QT_END_NAMESPACE
class MainWindow : public QMainWindow {
Q_OBJECT
private:
std::vector<std::string> 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<Finder> createSelectedFinder() const;
void showResults(const std::vector<const std::string *> &results);
private slots:
void on_searchInput_textChanged(const QString &search_term);
void on_searchAlgorithmSelector_currentIndexChanged(int);
private:
Ui::MainWindow *ui;
};

View File

@ -11,11 +11,86 @@
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
<string>QVectorSearch</string>
</property>
<widget class="QWidget" name="centralwidget"/>
<widget class="QMenuBar" name="menubar"/>
<widget class="QStatusBar" name="statusbar"/>
<property name="unifiedTitleAndToolBarOnMac">
<bool>false</bool>
</property>
<widget class="QWidget" name="centralwidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>1920</width>
<height>1200</height>
</size>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QGridLayout" name="gridLayout">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Select search algorithm</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enter a search text&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="searchAlgorithmSelector"/>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="searchInput">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QListView" name="resultView">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="uniformItemSizes">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QStatusBar" name="mainStatusBar"/>
<action name="actionOption">
<property name="text">
<string>Option</string>
</property>
</action>
</widget>
<resources/>
<connections/>

View File

@ -1,16 +1,19 @@
#pragma once
#include <chrono>
#include <string>
class Timer {
private:
std::string name_;
std::chrono::time_point<std::chrono::high_resolution_clock> start_;
std::chrono::time_point<std::chrono::high_resolution_clock> end_;
public:
Timer(std::string_view name);
Timer();
void start();
void stop();
long us() const;
};
std::ostream &operator<<(std::ostream &os, const Timer &timer);

View File

@ -1,17 +1,32 @@
#include "timer.h"
#include <chrono>
#include <iostream>
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<std::chrono::microseconds>(end - start_);
std::cout << name_ << " took " << duration << std::endl;
long Timer::us() const {
return std::chrono::duration_cast<std::chrono::microseconds>(end_ - start_)
.count();
}
std::ostream &operator<<(std::ostream &os, const Timer &timer) {
long time = timer.us();
if (time >= 1e6) {
os << time / static_cast<long>(1e6) << " s ";
time %= static_cast<long>(1e6);
}
if (time >= 1e3) {
os << time / static_cast<long>(1e3) << " ms ";
time %= static_cast<long>(1e3);
}
os << time << " µs";
return os;
}

View File

@ -7,7 +7,7 @@
const std::string WordListGenerator::charset_ = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
std::vector<std::string> WordListGenerator::generate() {
const size_t multiplier = 10;
const size_t multiplier = 1;
std::vector<std::string> result;
result.reserve(multiplier * std::pow(charset_.length(), 4));

View File

@ -13,10 +13,11 @@ using std::string, std::string_view, std::vector, std::thread, std::cout,
vector<string> 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<string> generate_word_list() {
void test_linear_finder(const vector<string> &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<string> &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;
}