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 | #ifndef QBYTEARRAYMATCHER_H |
5 | #define QBYTEARRAYMATCHER_H |
6 | |
7 | #include <QtCore/qbytearray.h> |
8 | |
9 | #include <QtCore/q20algorithm.h> |
10 | #include <iterator> |
11 | #include <limits> |
12 | |
13 | QT_BEGIN_NAMESPACE |
14 | |
15 | |
16 | class QByteArrayMatcherPrivate; |
17 | |
18 | class Q_CORE_EXPORT QByteArrayMatcher |
19 | { |
20 | public: |
21 | QByteArrayMatcher(); |
22 | explicit QByteArrayMatcher(const QByteArray &pattern); |
23 | explicit QByteArrayMatcher(QByteArrayView pattern) |
24 | : QByteArrayMatcher(pattern.data(), pattern.size()) |
25 | {} |
26 | explicit QByteArrayMatcher(const char *pattern, qsizetype length = -1); |
27 | QByteArrayMatcher(const QByteArrayMatcher &other); |
28 | ~QByteArrayMatcher(); |
29 | |
30 | QByteArrayMatcher &operator=(const QByteArrayMatcher &other); |
31 | |
32 | void setPattern(const QByteArray &pattern); |
33 | |
34 | #if QT_CORE_REMOVED_SINCE(6, 3) |
35 | qsizetype indexIn(const QByteArray &ba, qsizetype from = 0) const; |
36 | #else |
37 | Q_WEAK_OVERLOAD |
38 | qsizetype indexIn(const QByteArray &ba, qsizetype from = 0) const |
39 | { return indexIn(data: QByteArrayView{ba}, from); } |
40 | #endif |
41 | qsizetype indexIn(const char *str, qsizetype len, qsizetype from = 0) const; |
42 | qsizetype indexIn(QByteArrayView data, qsizetype from = 0) const; |
43 | inline QByteArray pattern() const |
44 | { |
45 | if (q_pattern.isNull()) |
46 | return QByteArray(reinterpret_cast<const char*>(p.p), p.l); |
47 | return q_pattern; |
48 | } |
49 | |
50 | private: |
51 | QByteArrayMatcherPrivate *d; |
52 | QByteArray q_pattern; |
53 | struct Data { |
54 | uchar q_skiptable[256]; |
55 | const uchar *p; |
56 | qsizetype l; |
57 | }; |
58 | union { |
59 | uint dummy[256]; |
60 | Data p; |
61 | }; |
62 | }; |
63 | |
64 | class QStaticByteArrayMatcherBase |
65 | { |
66 | alignas(16) |
67 | struct Skiptable { |
68 | uchar data[256]; |
69 | } m_skiptable; |
70 | protected: |
71 | explicit constexpr QStaticByteArrayMatcherBase(const char *pattern, size_t n) noexcept |
72 | : m_skiptable(generate(pattern, n)) {} |
73 | // compiler-generated copy/more ctors/assignment operators are ok! |
74 | ~QStaticByteArrayMatcherBase() = default; |
75 | |
76 | #if QT_CORE_REMOVED_SINCE(6, 3) && QT_POINTER_SIZE != 4 |
77 | Q_CORE_EXPORT int indexOfIn(const char *needle, uint nlen, const char *haystack, int hlen, int from) const noexcept; |
78 | #endif |
79 | Q_CORE_EXPORT qsizetype indexOfIn(const char *needle, size_t nlen, |
80 | const char *haystack, qsizetype hlen, |
81 | qsizetype from) const noexcept; |
82 | |
83 | private: |
84 | static constexpr Skiptable generate(const char *pattern, size_t n) noexcept |
85 | { |
86 | const auto uchar_max = (std::numeric_limits<uchar>::max)(); |
87 | uchar max = n > uchar_max ? uchar_max : uchar(n); |
88 | Skiptable table = {}; |
89 | q20::fill(first: std::begin(arr&: table.data), last: std::end(arr&: table.data), value: max); |
90 | pattern += n - max; |
91 | while (max--) |
92 | table.data[uchar(*pattern++)] = max; |
93 | return table; |
94 | } |
95 | }; |
96 | |
97 | template <size_t N> |
98 | class QStaticByteArrayMatcher : QStaticByteArrayMatcherBase |
99 | { |
100 | char m_pattern[N]; |
101 | // N includes the terminating '\0'! |
102 | static_assert(N > 2, "QStaticByteArrayMatcher makes no sense for finding a single-char pattern" ); |
103 | public: |
104 | explicit constexpr QStaticByteArrayMatcher(const char (&patternToMatch)[N]) noexcept |
105 | : QStaticByteArrayMatcherBase(patternToMatch, N - 1), m_pattern() |
106 | { |
107 | for (size_t i = 0; i < N; ++i) |
108 | m_pattern[i] = patternToMatch[i]; |
109 | } |
110 | |
111 | Q_WEAK_OVERLOAD |
112 | qsizetype indexIn(const QByteArray &haystack, qsizetype from = 0) const noexcept |
113 | { return this->indexOfIn(m_pattern, N - 1, haystack.data(), haystack.size(), from); } |
114 | qsizetype indexIn(const char *haystack, qsizetype hlen, qsizetype from = 0) const noexcept |
115 | { return this->indexOfIn(m_pattern, N - 1, haystack, hlen, from); } |
116 | qsizetype indexIn(QByteArrayView haystack, qsizetype from = 0) const noexcept |
117 | { return this->indexOfIn(m_pattern, N - 1, haystack.data(), haystack.size(), from); } |
118 | |
119 | QByteArray pattern() const { return QByteArray(m_pattern, qsizetype(N - 1)); } |
120 | }; |
121 | |
122 | template <size_t N> |
123 | constexpr QStaticByteArrayMatcher<N> qMakeStaticByteArrayMatcher(const char (&pattern)[N]) noexcept |
124 | { return QStaticByteArrayMatcher<N>(pattern); } |
125 | |
126 | QT_END_NAMESPACE |
127 | |
128 | #endif // QBYTEARRAYMATCHER_H |
129 | |