mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-25 20:48:52 +03:00
Do less work when building completion trie
Convert to lower case only once per string.
This commit is contained in:
parent
6f05cebf25
commit
5e99bace90
2 changed files with 45 additions and 35 deletions
|
@ -22,32 +22,7 @@ CompletionProxyModel::CompletionProxyModel(QAbstractItemModel *model,
|
||||||
{
|
{
|
||||||
setSourceModel(model);
|
setSourceModel(model);
|
||||||
|
|
||||||
// insert all the full texts
|
auto insertParts = [this](const QString &str, int id) {
|
||||||
for (int i = 0; i < sourceModel()->rowCount(); i++) {
|
|
||||||
if (static_cast<size_t>(i) < max_completions_)
|
|
||||||
mapping.push_back(i);
|
|
||||||
|
|
||||||
auto string1 = sourceModel()
|
|
||||||
->data(sourceModel()->index(i, 0), CompletionModel::SearchRole)
|
|
||||||
.toString()
|
|
||||||
.toLower();
|
|
||||||
if (!string1.isEmpty())
|
|
||||||
trie_.insert(string1.toUcs4(), i);
|
|
||||||
|
|
||||||
auto string2 = sourceModel()
|
|
||||||
->data(sourceModel()->index(i, 0), CompletionModel::SearchRole2)
|
|
||||||
.toString()
|
|
||||||
.toLower();
|
|
||||||
if (!string2.isEmpty())
|
|
||||||
trie_.insert(string2.toUcs4(), i);
|
|
||||||
}
|
|
||||||
|
|
||||||
// insert the partial matches
|
|
||||||
for (int i = 0; i < sourceModel()->rowCount(); i++) {
|
|
||||||
auto insertParts = [i, this](const QString &str) {
|
|
||||||
if (str.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
QTextBoundaryFinder finder(QTextBoundaryFinder::BoundaryType::Word, str);
|
QTextBoundaryFinder finder(QTextBoundaryFinder::BoundaryType::Word, str);
|
||||||
finder.toStart();
|
finder.toStart();
|
||||||
do {
|
do {
|
||||||
|
@ -57,19 +32,43 @@ CompletionProxyModel::CompletionProxyModel(QAbstractItemModel *model,
|
||||||
|
|
||||||
auto ref = str.midRef(start, end - start).trimmed();
|
auto ref = str.midRef(start, end - start).trimmed();
|
||||||
if (!ref.isEmpty())
|
if (!ref.isEmpty())
|
||||||
trie_.insert(ref.toUcs4(), i);
|
trie_.insert<ElementRank::second>(ref.toUcs4(), id);
|
||||||
} while (finder.position() < str.size());
|
} while (finder.position() < str.size());
|
||||||
};
|
};
|
||||||
|
|
||||||
insertParts(sourceModel()
|
const auto start_at = std::chrono::steady_clock::now();
|
||||||
|
|
||||||
|
// insert full texts and partial matches
|
||||||
|
for (int i = 0; i < sourceModel()->rowCount(); i++) {
|
||||||
|
// full texts are ranked first and partial matches second
|
||||||
|
// that way when searching full texts will be first in result list
|
||||||
|
|
||||||
|
auto string1 = sourceModel()
|
||||||
->data(sourceModel()->index(i, 0), CompletionModel::SearchRole)
|
->data(sourceModel()->index(i, 0), CompletionModel::SearchRole)
|
||||||
.toString()
|
.toString()
|
||||||
.toLower());
|
.toLower();
|
||||||
insertParts(sourceModel()
|
if (!string1.isEmpty()) {
|
||||||
|
trie_.insert<ElementRank::first>(string1.toUcs4(), i);
|
||||||
|
insertParts(string1, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto string2 = sourceModel()
|
||||||
->data(sourceModel()->index(i, 0), CompletionModel::SearchRole2)
|
->data(sourceModel()->index(i, 0), CompletionModel::SearchRole2)
|
||||||
.toString()
|
.toString()
|
||||||
.toLower());
|
.toLower();
|
||||||
|
if (!string2.isEmpty()) {
|
||||||
|
trie_.insert<ElementRank::first>(string2.toUcs4(), i);
|
||||||
|
insertParts(string2, i);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto end_at = std::chrono::steady_clock::now();
|
||||||
|
const auto build_time = std::chrono::duration<double, std::milli>(end_at - start_at);
|
||||||
|
nhlog::ui()->debug("CompletionProxyModel: build trie: {} ms", build_time.count());
|
||||||
|
|
||||||
|
// initialize default mapping
|
||||||
|
mapping.resize(std::min(max_completions_, static_cast<size_t>(model->rowCount())));
|
||||||
|
std::iota(mapping.begin(), mapping.end(), 0);
|
||||||
|
|
||||||
connect(
|
connect(
|
||||||
this,
|
this,
|
||||||
|
|
|
@ -9,12 +9,19 @@
|
||||||
|
|
||||||
#include <QAbstractProxyModel>
|
#include <QAbstractProxyModel>
|
||||||
|
|
||||||
|
enum class ElementRank
|
||||||
|
{
|
||||||
|
first,
|
||||||
|
second
|
||||||
|
};
|
||||||
|
|
||||||
template<typename Key, typename Value>
|
template<typename Key, typename Value>
|
||||||
struct trie
|
struct trie
|
||||||
{
|
{
|
||||||
std::vector<Value> values;
|
std::vector<Value> values;
|
||||||
std::map<Key, trie> next;
|
std::map<Key, trie> next;
|
||||||
|
|
||||||
|
template<ElementRank r>
|
||||||
void insert(const QVector<Key> &keys, const Value &v)
|
void insert(const QVector<Key> &keys, const Value &v)
|
||||||
{
|
{
|
||||||
auto t = this;
|
auto t = this;
|
||||||
|
@ -22,8 +29,12 @@ struct trie
|
||||||
t = &t->next[k];
|
t = &t->next[k];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if constexpr (r == ElementRank::first) {
|
||||||
|
t->values.insert(t->values.begin(), v);
|
||||||
|
} else if constexpr (r == ElementRank::second) {
|
||||||
t->values.push_back(v);
|
t->values.push_back(v);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<Value> valuesAndSubvalues(size_t limit = -1) const
|
std::vector<Value> valuesAndSubvalues(size_t limit = -1) const
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue