Skip to content

Commit 4c39fea

Browse files
lievenheymilianw
authored andcommitted
replace search implementation with a more readable one
this replaces the current implementation that uses a lot of if cases with a simpler one based on iterators and a wrapper for ease of usage
1 parent 14938d9 commit 4c39fea

File tree

8 files changed

+161
-40
lines changed

8 files changed

+161
-40
lines changed

src/models/disassemblymodel.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -224,14 +224,15 @@ QModelIndex DisassemblyModel::indexForFileLine(const Data::FileLine& fileLine) c
224224
return index(bestMatch, 0);
225225
}
226226

227-
void DisassemblyModel::find(const QString& search, Direction direction, int offset)
227+
void DisassemblyModel::find(const QString& search, Direction direction, int current)
228228
{
229229
auto searchFunc = [&search](const DisassemblyOutput::DisassemblyLine& line) {
230230
return line.disassembly.indexOf(search, 0, Qt::CaseInsensitive) != -1;
231231
};
232232

233-
const auto resultIndex = ::search(
234-
m_data.disassemblyLines, searchFunc, [this] { emit resultFound({}); }, direction, offset);
233+
auto endReached = [this] { emit searchEndReached(); };
234+
235+
const int resultIndex = ::search(m_data.disassemblyLines, current, direction, searchFunc, endReached);
235236

236237
if (resultIndex >= 0) {
237238
emit resultFound(createIndex(resultIndex, DisassemblyColumn));

src/models/search.h

Lines changed: 40 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
#pragma once
99

10+
#include <algorithm>
11+
#include <iterator>
1012
#include <QVector>
1113

1214
enum class Direction
@@ -15,36 +17,51 @@ enum class Direction
1517
Backward
1618
};
1719

18-
template<typename entry, typename SearchFunc, typename EndReached>
19-
int search(QVector<entry> source, SearchFunc&& searchFunc, EndReached&& endReached, Direction direction, int offset)
20+
/** a search function that wrap around at the end
21+
* this function evaluates searchFunc starting from current and returns the offset from begin. In case end is reached,
22+
* it calls endReached and starts again at begin
23+
*
24+
* return: offset from begin
25+
* */
26+
template<typename iter, typename SearchFunc, typename EndReached>
27+
int search_impl(iter begin, iter end, iter current, SearchFunc searchFunc, EndReached endReached)
2028
{
21-
if (offset > source.size() || offset < 0) {
22-
offset = 0;
23-
}
24-
25-
auto start = direction == Direction::Forward
26-
? (source.begin() + offset)
27-
: (source.end() - (source.size() - offset - 1)); // 1 one due to offset of the reverse iterator
29+
if (begin == end)
30+
return -1;
2831

29-
auto it = direction == Direction::Forward
30-
? std::find_if(start, source.end(), searchFunc)
31-
: (std::find_if(std::make_reverse_iterator(start), source.rend(), searchFunc) + 1).base();
32+
auto start = current + 1;
33+
auto found = std::find_if(start, end, searchFunc);
3234

33-
// it is less than source.begin() if the backward search ends at source.rend()
34-
if (it >= source.begin() && it < source.end()) {
35-
auto distance = std::distance(source.begin(), it);
36-
return distance;
35+
if (found != end) {
36+
return std::distance(begin, found);
3737
}
3838

39-
it = direction == Direction::Forward
40-
? std::find_if(source.begin(), start, searchFunc)
41-
: (std::find_if(source.rbegin(), std::make_reverse_iterator(start), searchFunc) + 1).base();
39+
endReached();
4240

43-
if (it != source.end()) {
44-
auto distance = std::distance(source.begin(), it);
45-
endReached();
46-
return distance;
41+
found = std::find_if(begin, start, searchFunc);
42+
43+
if (found != end) {
44+
return std::distance(begin, found);
4745
}
4846

4947
return -1;
5048
}
49+
50+
// a wrapper around search_impl that returns the result index from begin
51+
template<typename Array, typename SearchFunc, typename EndReached>
52+
int search(const Array& array, int current, Direction direction, SearchFunc searchFunc, EndReached endReached)
53+
{
54+
current = std::clamp(0, static_cast<int>(array.size()), current);
55+
int resultIndex = 0;
56+
57+
if (direction == Direction::Forward) {
58+
resultIndex = ::search_impl(array.begin(), array.end(), array.begin() + current, searchFunc, endReached);
59+
} else {
60+
resultIndex = ::search_impl(array.rbegin(), array.rend(),
61+
std::make_reverse_iterator(array.begin() + current) - 1, searchFunc, endReached);
62+
if (resultIndex != -1) {
63+
resultIndex = array.size() - resultIndex - 1;
64+
}
65+
}
66+
return resultIndex;
67+
}

src/models/sourcecodemodel.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <QTextDocument>
1616

1717
#include <algorithm>
18+
#include <iterator>
1819
#include <limits>
1920

2021
#include "highlighter.hpp"
@@ -261,14 +262,15 @@ void SourceCodeModel::setSysroot(const QString& sysroot)
261262
m_sysroot = sysroot;
262263
}
263264

264-
void SourceCodeModel::find(const QString& search, Direction direction, int offset)
265+
void SourceCodeModel::find(const QString& search, Direction direction, int current)
265266
{
266267
auto searchFunc = [&search](const SourceCodeLine& line) {
267268
return line.text.indexOf(search, 0, Qt::CaseInsensitive) != -1;
268269
};
269270

270-
const auto resultIndex = ::search(
271-
m_sourceCodeLines, searchFunc, [this] { emit resultFound({}); }, direction, offset);
271+
auto endReached = [this] { emit searchEndReached(); };
272+
273+
const int resultIndex = ::search(m_sourceCodeLines, current, direction, searchFunc, endReached);
272274

273275
if (resultIndex >= 0) {
274276
emit resultFound(createIndex(resultIndex + 1, SourceCodeColumn));

src/models/sourcecodemodel.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ public slots:
8383
void updateHighlighting(int line);
8484
void setSysroot(const QString& sysroot);
8585

86-
void find(const QString& search, Direction direction, int offset);
86+
void find(const QString& search, Direction direction, int current);
8787

8888
private:
8989
QString m_sysroot;

src/resultsdisassemblypage.cpp

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,8 @@ ResultsDisassemblyPage::ResultsDisassemblyPage(CostContextMenu* costContextMenu,
190190

191191
auto setupSearchShortcuts = [this](QPushButton* search, QPushButton* next, QPushButton* prev, QPushButton* close,
192192
QWidget* searchWidget, QLineEdit* edit, QAbstractItemView* view,
193-
KMessageWidget* endReached, auto* model, int additionalRows) {
193+
KMessageWidget* endReached, auto* model, QModelIndex* searchResultIndex,
194+
int additionalRows) {
194195
searchWidget->hide();
195196

196197
auto actions = new QActionGroup(view);
@@ -205,13 +206,13 @@ ResultsDisassemblyPage::ResultsDisassemblyPage(CostContextMenu* costContextMenu,
205206
findAction->setShortcutContext(Qt::ShortcutContext::WidgetWithChildrenShortcut);
206207
view->addAction(findAction);
207208

208-
auto searchNext = [this, model, edit, additionalRows] {
209-
const auto offset = m_currentSearchIndex.isValid() ? m_currentSearchIndex.row() - additionalRows + 1 : 0;
209+
auto searchNext = [model, edit, additionalRows, searchResultIndex] {
210+
const auto offset = searchResultIndex->isValid() ? searchResultIndex->row() - additionalRows : 0;
210211
model->find(edit->text(), Direction::Forward, offset);
211212
};
212213

213-
auto searchPrev = [this, model, edit, additionalRows] {
214-
const auto offset = m_currentSearchIndex.isValid() ? m_currentSearchIndex.row() - additionalRows - 1 : 0;
214+
auto searchPrev = [model, edit, additionalRows, searchResultIndex] {
215+
const auto offset = searchResultIndex->isValid() ? searchResultIndex->row() - additionalRows : 0;
215216

216217
model->find(edit->text(), Direction::Backward, offset);
217218
};
@@ -234,9 +235,9 @@ ResultsDisassemblyPage::ResultsDisassemblyPage(CostContextMenu* costContextMenu,
234235

235236
connectModel(
236237
model,
237-
[this, edit, view, colorScheme](const QModelIndex& index) {
238+
[edit, view, colorScheme, searchResultIndex](const QModelIndex& index) {
238239
auto palette = edit->palette();
239-
m_currentSearchIndex = index;
240+
*searchResultIndex = index;
240241
palette.setBrush(QPalette::Text,
241242
index.isValid() ? colorScheme.foreground()
242243
: colorScheme.foreground(KColorScheme::NegativeText));
@@ -250,10 +251,11 @@ ResultsDisassemblyPage::ResultsDisassemblyPage(CostContextMenu* costContextMenu,
250251
};
251252

252253
setupSearchShortcuts(ui->searchButton, ui->nextResult, ui->prevResult, ui->closeButton, ui->searchWidget,
253-
ui->searchEdit, ui->sourceCodeView, ui->searchEndWidget, m_sourceCodeModel, 1);
254+
ui->searchEdit, ui->sourceCodeView, ui->searchEndWidget, m_sourceCodeModel,
255+
&m_currentSourceSearchIndex, 1);
254256
setupSearchShortcuts(ui->disasmSearchButton, ui->disasmNextButton, ui->disasmPrevButton, ui->disasmCloseButton,
255257
ui->disasmSearchWidget, ui->disasmSearchEdit, ui->assemblyView, ui->disasmEndReachedWidget,
256-
m_disassemblyModel, 0);
258+
m_disassemblyModel, &m_currentDisasmSearchIndex, 0);
257259

258260
#if KFSyntaxHighlighting_FOUND
259261
QStringList schemes;

src/resultsdisassemblypage.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ class ResultsDisassemblyPage : public QWidget
7373
// Model
7474
DisassemblyModel* m_disassemblyModel;
7575
SourceCodeModel* m_sourceCodeModel;
76-
QModelIndex m_currentSearchIndex;
76+
QModelIndex m_currentSourceSearchIndex;
77+
QModelIndex m_currentDisasmSearchIndex;
7778
// Architecture
7879
QString m_arch;
7980
// Objdump binary name

tests/modeltests/CMakeLists.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,12 @@ endif()
7171
set_target_properties(
7272
tst_callgraphgenerator PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${KDE_INSTALL_BINDIR}"
7373
)
74+
75+
ecm_add_test(
76+
tst_search.cpp
77+
LINK_LIBRARIES
78+
Qt::Test
79+
TEST_NAME
80+
tst_search
81+
)
82+
set_target_properties(tst_search PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${KDE_INSTALL_BINDIR}")

tests/modeltests/tst_search.cpp

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
SPDX-FileCopyrightText: Lieven Hey <lieven.hey@kdab.com>
3+
SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com
4+
5+
SPDX-License-Identifier: GPL-2.0-or-later
6+
*/
7+
8+
#include <array>
9+
#include <QObject>
10+
#include <QTest>
11+
#include <qtest.h>
12+
#include <qtestcase.h>
13+
14+
#include <iterator>
15+
#include <models/search.h>
16+
17+
class TestSearch : public QObject
18+
{
19+
Q_OBJECT
20+
private slots:
21+
void testSearchEmpty()
22+
{
23+
const std::array<int, 0> testArray = {};
24+
25+
QCOMPARE(search_impl(
26+
testArray.begin(), testArray.end(), testArray.begin(), [](int) { return false; }, [] {}),
27+
-1);
28+
QCOMPARE(search_impl(
29+
testArray.rbegin(), testArray.rend(), testArray.rbegin(), [](int) { return false; }, [] {}),
30+
-1);
31+
}
32+
void testSearch()
33+
{
34+
const std::array<int, 5> testArray = {1, 2, 3, 4, 5};
35+
36+
int maxOffset = testArray.size() - 1;
37+
for (int offset = 0; offset < maxOffset; offset++) {
38+
QCOMPARE(search_impl(
39+
testArray.begin(), testArray.end(), testArray.begin() + offset,
40+
[](int num) { return num == 2; }, [] {}),
41+
1);
42+
QCOMPARE(search_impl(
43+
testArray.rbegin(), testArray.rend(), testArray.rbegin() + offset,
44+
[](int num) { return num == 2; }, [] {}),
45+
3);
46+
}
47+
}
48+
49+
void testEndReached()
50+
{
51+
const std::array<int, 5> testArray = {1, 2, 3, 4, 5};
52+
{
53+
bool endReached = false;
54+
QCOMPARE(search_impl(
55+
testArray.begin(), testArray.end(), testArray.begin() + 1, [](int i) { return i == 1; },
56+
[&endReached] { endReached = true; }),
57+
0);
58+
QCOMPARE(endReached, true);
59+
}
60+
61+
{
62+
bool endReached = false;
63+
QCOMPARE(search_impl(
64+
testArray.rbegin(), testArray.rend(), std::make_reverse_iterator(testArray.begin() + 4 - 1),
65+
[](int i) { return i == 4; }, [&endReached] { endReached = true; }),
66+
1);
67+
QCOMPARE(endReached, true);
68+
}
69+
}
70+
71+
void testWrapper()
72+
{
73+
const std::array<int, 5> testArray = {1, 2, 3, 4, 5};
74+
75+
int maxOffset = testArray.size() - 1;
76+
for (int i = 0; i < maxOffset; i++) {
77+
QCOMPARE(search(
78+
testArray, i, Direction::Forward, [](int i) { return i == 4; }, [] {}),
79+
3);
80+
QCOMPARE(search(
81+
testArray, i, Direction::Backward, [](int i) { return i == 4; }, [] {}),
82+
3);
83+
}
84+
}
85+
};
86+
87+
QTEST_GUILESS_MAIN(TestSearch)
88+
89+
#include "tst_search.moc"

0 commit comments

Comments
 (0)