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
qbytearraymatcher.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qbytearraymatcher.h"
5
6#include <limits.h>
7
9
10static inline void bm_init_skiptable(const uchar *cc, qsizetype len, uchar *skiptable)
11{
12 int l = int(qMin(len, qsizetype(255)));
13 memset(skiptable, l, 256*sizeof(uchar));
14 cc += len - l;
15 while (l--)
16 skiptable[*cc++] = l;
17}
18
19static inline qsizetype bm_find(const uchar *cc, qsizetype l, qsizetype index, const uchar *puc,
20 qsizetype pl, const uchar *skiptable)
21{
22 if (pl == 0)
23 return index > l ? -1 : index;
24 const qsizetype pl_minus_one = pl - 1;
25
26 const uchar *current = cc + index + pl_minus_one;
27 const uchar *end = cc + l;
28 while (current < end) {
29 qsizetype skip = skiptable[*current];
30 if (!skip) {
31 // possible match
32 while (skip < pl) {
33 if (*(current - skip) != puc[pl_minus_one - skip])
34 break;
35 skip++;
36 }
37 if (skip > pl_minus_one) // we have a match
38 return (current - cc) - skip + 1;
39
40 // in case we don't have a match we are a bit inefficient as we only skip by one
41 // when we have the non matching char in the string.
42 if (skiptable[*(current - skip)] == pl)
43 skip = pl - skip;
44 else
45 skip = 1;
46 }
47 if (current > end - skip)
48 break;
49 current += skip;
50 }
51 return -1; // not found
52}
53
83 : d(nullptr)
84{
85 p.p = nullptr;
86 p.l = 0;
87 memset(p.q_skiptable, 0, sizeof(p.q_skiptable));
88}
89
98{
99 p.p = reinterpret_cast<const uchar *>(pattern);
100 if (length < 0)
101 p.l = qstrlen(pattern);
102 else
103 p.l = length;
104 bm_init_skiptable(p.p, p.l, p.q_skiptable);
105}
106
112 : d(nullptr), q_pattern(pattern)
113{
114 p.p = reinterpret_cast<const uchar *>(pattern.constData());
115 p.l = pattern.size();
116 bm_init_skiptable(p.p, p.l, p.q_skiptable);
117}
118
139
147
152{
153 q_pattern = other.q_pattern;
154 memcpy(&p, &other.p, sizeof(p));
155 return *this;
156}
157
165{
166 q_pattern = pattern;
167 p.p = reinterpret_cast<const uchar *>(pattern.constData());
168 p.l = pattern.size();
169 bm_init_skiptable(p.p, p.l, p.q_skiptable);
170}
171
180{
181 if (from < 0)
182 from = 0;
183 return bm_find(reinterpret_cast<const uchar *>(str), len, from,
184 p.p, p.l, p.q_skiptable);
185}
186
199{
200 if (from < 0)
201 from = 0;
202 return bm_find(reinterpret_cast<const uchar *>(data.data()), data.size(), from,
203 p.p, p.l, p.q_skiptable);
204}
205
216static qsizetype findChar(const char *str, qsizetype len, char ch, qsizetype from)
217{
218 const uchar *s = (const uchar *)str;
219 uchar c = (uchar)ch;
220 if (from < 0)
221 from = qMax(from + len, qsizetype(0));
222 if (from < len) {
223 const uchar *n = s + from - 1;
224 const uchar *e = s + len;
225 while (++n != e)
226 if (*n == c)
227 return n - s;
228 }
229 return -1;
230}
231
236 const char *haystack, qsizetype haystackLen, qsizetype haystackOffset,
237 const char *needle, qsizetype needleLen)
238{
239 uchar skiptable[256];
240 bm_init_skiptable((const uchar *)needle, needleLen, skiptable);
241 if (haystackOffset < 0)
242 haystackOffset = 0;
243 return bm_find((const uchar *)haystack, haystackLen, haystackOffset,
244 (const uchar *)needle, needleLen, skiptable);
245}
246
247#define REHASH(a) \
248 if (sl_minus_1 < sizeof(std::size_t) * CHAR_BIT) \
249 hashHaystack -= std::size_t(a) << sl_minus_1; \
250 hashHaystack <<= 1
251
256 const char *haystack0, qsizetype haystackLen, qsizetype from,
257 const char *needle, qsizetype needleLen)
258{
259 const auto l = haystackLen;
260 const auto sl = needleLen;
261 if (from < 0)
262 from += l;
263 if (std::size_t(sl + from) > std::size_t(l))
264 return -1;
265 if (!sl)
266 return from;
267 if (!l)
268 return -1;
269
270 if (sl == 1)
271 return findChar(haystack0, haystackLen, needle[0], from);
272
273 /*
274 We use the Boyer-Moore algorithm in cases where the overhead
275 for the skip table should pay off, otherwise we use a simple
276 hash function.
277 */
278 if (l > 500 && sl > 5)
279 return qFindByteArrayBoyerMoore(haystack0, haystackLen, from,
280 needle, needleLen);
281
282 /*
283 We use some hashing for efficiency's sake. Instead of
284 comparing strings, we compare the hash value of str with that
285 of a part of this QString. Only if that matches, we call memcmp().
286 */
287 const char *haystack = haystack0 + from;
288 const char *end = haystack0 + (l - sl);
289 const auto sl_minus_1 = std::size_t(sl - 1);
290 std::size_t hashNeedle = 0, hashHaystack = 0;
291 qsizetype idx;
292 for (idx = 0; idx < sl; ++idx) {
293 hashNeedle = ((hashNeedle<<1) + needle[idx]);
294 hashHaystack = ((hashHaystack<<1) + haystack[idx]);
295 }
296 hashHaystack -= *(haystack + sl_minus_1);
297
298 while (haystack <= end) {
299 hashHaystack += *(haystack + sl_minus_1);
300 if (hashHaystack == hashNeedle && *needle == *haystack
301 && memcmp(needle, haystack, sl) == 0)
302 return haystack - haystack0;
303
304 REHASH(*haystack);
305 ++haystack;
306 }
307 return -1;
308}
309
385qsizetype QStaticByteArrayMatcherBase::indexOfIn(const char *needle, size_t nlen, const char *haystack, qsizetype hlen, qsizetype from) const noexcept
386{
387 if (from < 0)
388 from = 0;
389 return bm_find(reinterpret_cast<const uchar *>(haystack), hlen, from,
390 reinterpret_cast<const uchar *>(needle), nlen, m_skiptable.data);
391}
392
414
415#undef REHASH
\inmodule QtCore
QByteArrayMatcher & operator=(const QByteArrayMatcher &other)
Assigns the other byte array matcher to this byte array matcher.
Q_WEAK_OVERLOAD qsizetype indexIn(const QByteArray &ba, qsizetype from=0) const
QByteArrayMatcher()
Constructs an empty byte array matcher that won't match anything.
~QByteArrayMatcher()
Destroys the byte array matcher.
QByteArray pattern() const
Returns the byte array pattern that this byte array matcher will search for.
void setPattern(const QByteArray &pattern)
Sets the byte array that this byte array matcher will search for to pattern.
\inmodule QtCore
Definition qbytearray.h:57
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
Definition qbytearray.h:494
Q_CORE_EXPORT qsizetype indexOfIn(const char *needle, size_t nlen, const char *haystack, qsizetype hlen, qsizetype from) const noexcept
QString str
[2]
Combined button and popup list for selecting options.
size_t qstrlen(const char *str)
static qsizetype findChar(const char *str, qsizetype len, char ch, qsizetype from)
static qsizetype qFindByteArrayBoyerMoore(const char *haystack, qsizetype haystackLen, qsizetype haystackOffset, const char *needle, qsizetype needleLen)
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)
#define REHASH(a)
qsizetype qFindByteArray(const char *haystack0, qsizetype haystackLen, qsizetype from, const char *needle, qsizetype needleLen)
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
GLuint index
[2]
GLuint GLuint end
GLenum GLuint GLenum GLsizei length
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLfloat n
GLdouble s
[6]
Definition qopenglext.h:235
const GLubyte * c
GLfloat GLfloat p
[1]
GLenum GLsizei len
GLubyte * pattern
#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]