Skip to content

Commit 67b5d27

Browse files
committed
src/dict/databasemanager: allocate half-width to full-width map once
Previously in very early versions of Memento there was a terrible bug that caused memory usage to increase forever until Memento simply became unresponsive. It was due to accessing a QMap from multiple threads for reads. There appears to be a thread about this here. https://forum.qt.io/topic/164019/iterating-shared-qmap-on-multiple-threads/11 If I had to guess, early versions didn't mark the QMap as const, which led to operator[] using the non-const version which would modify the map. Since the map itself is const and the function is const as well, I suppose this won't be an issue anymore. This should be a nice speedup.
1 parent 7f3091b commit 67b5d27

2 files changed

Lines changed: 101 additions & 112 deletions

File tree

src/dict/databasemanager.cpp

Lines changed: 10 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -1130,113 +1130,12 @@ QString DatabaseManager::errorCodeToString(const int code) const
11301130
}
11311131
}
11321132

1133-
QString DatabaseManager::halfToFull(const QString &query)
1133+
QString DatabaseManager::halfToFull(const QString &query) const
11341134
{
1135-
static const QChar HALFWIDTH_LOW(0xFF61);
1136-
static const QChar HALFWIDTH_HIGH(0xFF9F);
1137-
static const QChar HALFWIDTH_VOICED(0xFF9E);
1138-
static const QChar HALFWIDTH_SEMI_VOICED(0xFF9F);
1139-
1140-
/* While initializing a new map every time this conversion is done seems and
1141-
* is stupid, QMap is not thread safe. An older version of Memento used to
1142-
* disregarded this and it led to a horrible bug that caused CPU usage to
1143-
* spike to 100% until Memento was closed.
1144-
*
1145-
* While it might seem obvious that half-width should be easily mappable to
1146-
* full-width with offsets, this is not the case. Unicode in their infinite
1147-
* wisdom decided the ordering for half-width characters should be different
1148-
* from their full width counter parts and that half width characters should
1149-
* use two characters to represent something like ガ using two characters
1150-
* (ガ).
1151-
*/
1152-
QMap<QString, QString> charMap{
1153-
{"", ""},
1154-
{"", ""},
1155-
{"", ""},
1156-
{"", ""},
1157-
{"", ""},
1158-
{"", ""},
1159-
{"", ""},
1160-
{"", ""},
1161-
{"", ""},
1162-
{"", ""},
1163-
{"", ""},
1164-
{"", ""},
1165-
{"", ""},
1166-
{"", ""},
1167-
{"", ""},
1168-
{"", ""},
1169-
{"", ""},
1170-
{"", ""},
1171-
{"", ""},
1172-
{"", ""},
1173-
{"", ""},
1174-
{"", ""},
1175-
{"ガ", ""},
1176-
{"", ""},
1177-
{"ギ", ""},
1178-
{"", ""},
1179-
{"グ", ""},
1180-
{"", ""},
1181-
{"ゲ", ""},
1182-
{"", ""},
1183-
{"ゴ", ""},
1184-
{"", ""},
1185-
{"ザ", ""},
1186-
{"", ""},
1187-
{"ジ", ""},
1188-
{"", ""},
1189-
{"ズ", ""},
1190-
{"", ""},
1191-
{"ゼ", ""},
1192-
{"ソ", ""},
1193-
{"ゾ", ""},
1194-
{"", ""},
1195-
{"ダ", ""},
1196-
{"", ""},
1197-
{"ヂ", ""},
1198-
{"", ""},
1199-
{"ヅ", ""},
1200-
{"", ""},
1201-
{"デ", ""},
1202-
{"", ""},
1203-
{"ド", ""},
1204-
{"", ""},
1205-
{"", ""},
1206-
{"", ""},
1207-
{"", ""},
1208-
{"", ""},
1209-
{"", ""},
1210-
{"バ", ""},
1211-
{"パ", ""},
1212-
{"", ""},
1213-
{"ビ", ""},
1214-
{"ピ", ""},
1215-
{"", ""},
1216-
{"ブ", ""},
1217-
{"プ", ""},
1218-
{"", ""},
1219-
{"ベ", ""},
1220-
{"ペ", ""},
1221-
{"", ""},
1222-
{"ボ", ""},
1223-
{"ポ", ""},
1224-
{"", ""},
1225-
{"", ""},
1226-
{"", ""},
1227-
{"", ""},
1228-
{"", ""},
1229-
{"", ""},
1230-
{"", ""},
1231-
{"", ""},
1232-
{"", ""},
1233-
{"", ""},
1234-
{"", ""},
1235-
{"", ""},
1236-
{"", ""},
1237-
{"", ""},
1238-
{"", ""},
1239-
};
1135+
static constexpr QChar HALFWIDTH_LOW(0xFF61);
1136+
static constexpr QChar HALFWIDTH_HIGH(0xFF9F);
1137+
static constexpr QChar HALFWIDTH_VOICED(0xFF9E);
1138+
static constexpr QChar HALFWIDTH_SEMI_VOICED(0xFF9F);
12401139

12411140
QString res;
12421141
qsizetype i{0};
@@ -1246,14 +1145,14 @@ QString DatabaseManager::halfToFull(const QString &query)
12461145
{
12471146
if ((query[i + 1] == HALFWIDTH_VOICED ||
12481147
query[i + 1] == HALFWIDTH_SEMI_VOICED) &&
1249-
charMap.contains(query.mid(i, 2)))
1148+
m_halfToFullMap.contains(query.mid(i, 2)))
12501149
{
1251-
res += charMap[query.mid(i, 2)];
1150+
res += m_halfToFullMap[query.mid(i, 2)];
12521151
++i;
12531152
}
12541153
else
12551154
{
1256-
res += charMap[query[i]];
1155+
res += m_halfToFullMap[query[i]];
12571156
}
12581157
}
12591158
else
@@ -1264,9 +1163,9 @@ QString DatabaseManager::halfToFull(const QString &query)
12641163
if (i < query.size())
12651164
{
12661165
if (HALFWIDTH_LOW <= query[i] && query[i] <= HALFWIDTH_HIGH &&
1267-
charMap.contains(query[i]))
1166+
m_halfToFullMap.contains(query[i]))
12681167
{
1269-
res += charMap[query[i]];
1168+
res += m_halfToFullMap[query[i]];
12701169
}
12711170
else
12721171
{

src/dict/databasemanager.h

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ class DatabaseManager : public QObject
281281
* @param query The query string to convert.
282282
*/
283283
[[nodiscard]]
284-
static QString halfToFull(const QString &query);
284+
QString halfToFull(const QString &query) const;
285285

286286
/**
287287
* @brief Converts all the katakana in a string to their equivalent
@@ -336,4 +336,94 @@ class DatabaseManager : public QObject
336336

337337
/* true if the database is being modified, false otherwise */
338338
std::atomic_bool m_modifyingDatabase{false};
339+
340+
/* Maps half-width characters to full-width characters */
341+
const QMap<QString, QString> m_halfToFullMap{
342+
{"", ""},
343+
{"", ""},
344+
{"", ""},
345+
{"", ""},
346+
{"", ""},
347+
{"", ""},
348+
{"", ""},
349+
{"", ""},
350+
{"", ""},
351+
{"", ""},
352+
{"", ""},
353+
{"", ""},
354+
{"", ""},
355+
{"", ""},
356+
{"", ""},
357+
{"", ""},
358+
{"", ""},
359+
{"", ""},
360+
{"", ""},
361+
{"", ""},
362+
{"", ""},
363+
{"", ""},
364+
{"ガ", ""},
365+
{"", ""},
366+
{"ギ", ""},
367+
{"", ""},
368+
{"グ", ""},
369+
{"", ""},
370+
{"ゲ", ""},
371+
{"", ""},
372+
{"ゴ", ""},
373+
{"", ""},
374+
{"ザ", ""},
375+
{"", ""},
376+
{"ジ", ""},
377+
{"", ""},
378+
{"ズ", ""},
379+
{"", ""},
380+
{"ゼ", ""},
381+
{"ソ", ""},
382+
{"ゾ", ""},
383+
{"", ""},
384+
{"ダ", ""},
385+
{"", ""},
386+
{"ヂ", ""},
387+
{"", ""},
388+
{"ヅ", ""},
389+
{"", ""},
390+
{"デ", ""},
391+
{"", ""},
392+
{"ド", ""},
393+
{"", ""},
394+
{"", ""},
395+
{"", ""},
396+
{"", ""},
397+
{"", ""},
398+
{"", ""},
399+
{"バ", ""},
400+
{"パ", ""},
401+
{"", ""},
402+
{"ビ", ""},
403+
{"ピ", ""},
404+
{"", ""},
405+
{"ブ", ""},
406+
{"プ", ""},
407+
{"", ""},
408+
{"ベ", ""},
409+
{"ペ", ""},
410+
{"", ""},
411+
{"ボ", ""},
412+
{"ポ", ""},
413+
{"", ""},
414+
{"", ""},
415+
{"", ""},
416+
{"", ""},
417+
{"", ""},
418+
{"", ""},
419+
{"", ""},
420+
{"", ""},
421+
{"", ""},
422+
{"", ""},
423+
{"", ""},
424+
{"", ""},
425+
{"", ""},
426+
{"", ""},
427+
{"", ""},
428+
};
339429
};

0 commit comments

Comments
 (0)