Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qstringmatcher.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
2// Copyright (C) 2019 Mail.ru Group.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#include "qstringmatcher.h"
6
8
9static constexpr qsizetype FoldBufferCapacity = 256;
10
11static void bm_init_skiptable(QStringView needle, uchar *skiptable, Qt::CaseSensitivity cs)
12{
13 const char16_t *uc = needle.utf16();
14 const qsizetype len =
15 cs == Qt::CaseSensitive ? needle.size() : qMin(needle.size(), FoldBufferCapacity);
16 int l = qMin(int(len), 255);
17 memset(skiptable, l, 256 * sizeof(uchar));
18 uc += len - l;
19 if (cs == Qt::CaseSensitive) {
20 while (l--) {
21 skiptable[*uc & 0xff] = l;
22 ++uc;
23 }
24 } else {
25 const char16_t *start = uc;
26 while (l--) {
27 skiptable[foldCase(uc, start) & 0xff] = l;
28 ++uc;
29 }
30 }
31}
32
33static inline qsizetype bm_find(QStringView haystack, qsizetype index, QStringView needle,
34 const uchar *skiptable, Qt::CaseSensitivity cs)
35{
36 const char16_t *uc = haystack.utf16();
37 const qsizetype l = haystack.size();
38 const char16_t *puc = needle.utf16();
39 const qsizetype pl = needle.size();
40
41 if (pl == 0)
42 return index > l ? -1 : index;
43
44 if (cs == Qt::CaseSensitive) {
45 const qsizetype pl_minus_one = pl - 1;
46 const char16_t *current = uc + index + pl_minus_one;
47 const char16_t *end = uc + l;
48
49 while (current < end) {
50 qsizetype skip = skiptable[*current & 0xff];
51 if (!skip) {
52 // possible match
53 while (skip < pl) {
54 if (*(current - skip) != puc[pl_minus_one-skip])
55 break;
56 ++skip;
57 }
58 if (skip > pl_minus_one) // we have a match
59 return (current - uc) - pl_minus_one;
60
61 // in case we don't have a match we are a bit inefficient as we only skip by one
62 // when we have the non matching char in the string.
63 if (skiptable[*(current - skip) & 0xff] == pl)
64 skip = pl - skip;
65 else
66 skip = 1;
67 }
68 if (current > end - skip)
69 break;
70 current += skip;
71 }
72 } else {
73 char16_t foldBuffer[FoldBufferCapacity];
74 const qsizetype foldBufferLength = qMin(FoldBufferCapacity, pl);
75 const char16_t *start = puc;
76 for (qsizetype i = 0; i < foldBufferLength; ++i)
77 foldBuffer[i] = foldCase(&puc[i], start);
78 QStringView restNeedle = needle.sliced(foldBufferLength);
79 const qsizetype foldBufferEnd = foldBufferLength - 1;
80 const char16_t *current = uc + index + foldBufferEnd;
81 const char16_t *end = uc + l;
82
83 while (current < end) {
84 qsizetype skip = skiptable[foldCase(current, uc) & 0xff];
85 if (!skip) {
86 // possible match
87 while (skip < foldBufferLength) {
88 if (foldCase(current - skip, uc) != foldBuffer[foldBufferEnd - skip])
89 break;
90 ++skip;
91 }
92 if (skip > foldBufferEnd) { // Matching foldBuffer
93 qsizetype candidatePos = (current - uc) - foldBufferEnd;
94 QStringView restHaystack =
95 haystack.sliced(qMin(haystack.size(), candidatePos + foldBufferLength));
96 if (restNeedle.size() == 0
97 || restHaystack.startsWith(
98 restNeedle, Qt::CaseInsensitive)) // Check the rest of the string
99 return candidatePos;
100 }
101 // in case we don't have a match we are a bit inefficient as we only skip by one
102 // when we have the non matching char in the string.
103 if (skiptable[foldCase(current - skip, uc) & 0xff] == foldBufferLength)
104 skip = foldBufferLength - skip;
105 else
106 skip = 1;
107 }
108 if (current > end - skip)
109 break;
110 current += skip;
111 }
112 }
113 return -1; // not found
114}
115
116void QStringMatcher::updateSkipTable()
117{
118 bm_init_skiptable(q_sv, q_skiptable, q_cs);
119}
120
157 : d_ptr(nullptr), q_cs(cs), q_pattern(pattern)
158{
159 q_sv = q_pattern;
160 updateSkipTable();
161}
162
181 : d_ptr(nullptr), q_cs(cs), q_sv(str)
182{
183 updateSkipTable();
184}
193
201
206{
207 if (this != &other) {
208 q_pattern = other.q_pattern;
209 q_cs = other.q_cs;
210 q_sv = other.q_sv;
211 memcpy(q_skiptable, other.q_skiptable, sizeof(q_skiptable));
212 }
213 return *this;
214}
215
223{
224 q_pattern = pattern;
225 q_sv = q_pattern;
226 updateSkipTable();
227}
228
239{
240 if (!q_pattern.isEmpty())
241 return q_pattern;
242 return q_sv.toString();
243}
244
261{
262 if (cs == q_cs)
263 return;
264 q_cs = cs;
265 updateSkipTable();
266}
267
304{
305 if (from < 0)
306 from = 0;
307 return bm_find(str, from, q_sv, q_skiptable, q_cs);
308}
309
323 QStringView haystack, qsizetype haystackOffset,
325{
326 uchar skiptable[256];
327 bm_init_skiptable(needle, skiptable, cs);
328 if (haystackOffset < 0)
329 haystackOffset = 0;
330 return bm_find(haystack, haystackOffset, needle, skiptable, cs);
331}
332
\inmodule QtCore
QStringMatcher & operator=(const QStringMatcher &other)
Assigns the other string matcher to this string matcher.
~QStringMatcher()
Destroys the string matcher.
void setPattern(const QString &pattern)
Sets the string that this string matcher will search for to pattern.
void setCaseSensitivity(Qt::CaseSensitivity cs)
Sets the case sensitivity setting of this string matcher to cs.
QString pattern() const
Returns the string pattern that this string matcher will search for.
QStringMatcher()=default
Constructs an empty string matcher that won't match anything.
qsizetype indexIn(const QString &str, qsizetype from=0) const
Searches the string str from character position from (default 0, i.e.
\inmodule QtCore
Definition qstringview.h:78
QString toString() const
Returns a deep copy of this string view's data as a QString.
Definition qstring.h:1121
constexpr QStringView sliced(qsizetype pos) const noexcept
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
QString str
[2]
Combined button and popup list for selecting options.
CaseSensitivity
@ CaseInsensitive
@ CaseSensitive
static QT_BEGIN_NAMESPACE void bm_init_skiptable(const uchar *cc, qsizetype len, uchar *skiptable)
static qsizetype bm_find(const uchar *cc, qsizetype l, qsizetype index, const uchar *puc, qsizetype pl, const uchar *skiptable)
static char32_t foldCase(const char16_t *ch, const char16_t *start)
Definition qchar.cpp:1632
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
GLuint index
[2]
GLuint GLuint end
GLuint start
GLenum GLsizei len
GLubyte * pattern
static qsizetype bm_find(QStringView haystack, qsizetype index, QStringView needle, const uchar *skiptable, Qt::CaseSensitivity cs)
static void bm_init_skiptable(QStringView needle, uchar *skiptable, Qt::CaseSensitivity cs)
qsizetype qFindStringBoyerMoore(QStringView haystack, qsizetype haystackOffset, QStringView needle, Qt::CaseSensitivity cs)
static QT_BEGIN_NAMESPACE constexpr qsizetype FoldBufferCapacity
#define Q_UNUSED(x)
unsigned char uchar
Definition qtypes.h:32
ptrdiff_t qsizetype
Definition qtypes.h:165
QObject::connect nullptr
QSharedPointer< T > other(t)
[5]