1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the QtQml module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or (at your option) the GNU General |
28 | ** Public license version 3 or any later version approved by the KDE Free |
29 | ** Qt Foundation. The licenses are as published by the Free Software |
30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
31 | ** included in the packaging of this file. Please review the following |
32 | ** information to ensure the GNU General Public License requirements will |
33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
34 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
35 | ** |
36 | ** $QT_END_LICENSE$ |
37 | ** |
38 | ****************************************************************************/ |
39 | |
40 | #ifndef QHASHEDSTRING_P_H |
41 | #define QHASHEDSTRING_P_H |
42 | |
43 | // |
44 | // W A R N I N G |
45 | // ------------- |
46 | // |
47 | // This file is not part of the Qt API. It exists purely as an |
48 | // implementation detail. This header file may change from version to |
49 | // version without notice, or even be removed. |
50 | // |
51 | // We mean it. |
52 | // |
53 | |
54 | #include <QtCore/qglobal.h> |
55 | #include <QtCore/qstring.h> |
56 | #include <private/qv4string_p.h> |
57 | |
58 | #include <private/qflagpointer_p.h> |
59 | |
60 | #if defined(Q_OS_QNX) |
61 | #include <stdlib.h> |
62 | #endif |
63 | |
64 | QT_BEGIN_NAMESPACE |
65 | |
66 | class QHashedStringRef; |
67 | class Q_QML_PRIVATE_EXPORT QHashedString : public QString |
68 | { |
69 | public: |
70 | inline QHashedString(); |
71 | inline QHashedString(const QString &string); |
72 | inline QHashedString(const QString &string, quint32); |
73 | inline QHashedString(const QHashedString &string); |
74 | |
75 | inline QHashedString &operator=(const QHashedString &string); |
76 | inline bool operator==(const QHashedString &string) const; |
77 | inline bool operator==(const QHashedStringRef &string) const; |
78 | |
79 | inline quint32 hash() const; |
80 | inline quint32 existingHash() const; |
81 | |
82 | static bool compare(const QChar *lhs, const QChar *rhs, int length); |
83 | static inline bool compare(const QChar *lhs, const char *rhs, int length); |
84 | static inline bool compare(const char *lhs, const char *rhs, int length); |
85 | |
86 | static inline quint32 stringHash(const QChar* data, int length); |
87 | static inline quint32 stringHash(const char *data, int length); |
88 | |
89 | private: |
90 | friend class QHashedStringRef; |
91 | friend class QStringHashNode; |
92 | |
93 | inline void computeHash() const; |
94 | mutable quint32 m_hash = 0; |
95 | }; |
96 | |
97 | class QHashedCStringRef; |
98 | class Q_QML_PRIVATE_EXPORT QHashedStringRef |
99 | { |
100 | public: |
101 | inline QHashedStringRef(); |
102 | inline QHashedStringRef(const QString &); |
103 | inline QHashedStringRef(const QStringRef &); |
104 | inline QHashedStringRef(const QChar *, int); |
105 | inline QHashedStringRef(const QChar *, int, quint32); |
106 | inline QHashedStringRef(const QHashedString &); |
107 | inline QHashedStringRef(const QHashedStringRef &); |
108 | inline QHashedStringRef &operator=(const QHashedStringRef &); |
109 | |
110 | inline bool operator==(const QString &string) const; |
111 | inline bool operator==(const QHashedString &string) const; |
112 | inline bool operator==(const QHashedStringRef &string) const; |
113 | inline bool operator==(const QHashedCStringRef &string) const; |
114 | inline bool operator!=(const QString &string) const; |
115 | inline bool operator!=(const QHashedString &string) const; |
116 | inline bool operator!=(const QHashedStringRef &string) const; |
117 | inline bool operator!=(const QHashedCStringRef &string) const; |
118 | |
119 | inline quint32 hash() const; |
120 | |
121 | inline QChar *data(); |
122 | inline const QChar &at(int) const; |
123 | inline const QChar *constData() const; |
124 | bool startsWith(const QString &) const; |
125 | bool endsWith(const QString &) const; |
126 | int indexOf(const QChar &, int from=0) const; |
127 | QHashedStringRef mid(int, int) const; |
128 | QVector<QHashedStringRef> split(const QChar sep) const; |
129 | |
130 | inline bool isEmpty() const; |
131 | inline int length() const; |
132 | inline bool startsWithUpper() const; |
133 | |
134 | QString toString() const; |
135 | |
136 | inline bool isLatin1() const; |
137 | |
138 | private: |
139 | friend class QHashedString; |
140 | |
141 | inline void computeHash() const; |
142 | |
143 | const QChar *m_data = nullptr; |
144 | int m_length = 0; |
145 | mutable quint32 m_hash = 0; |
146 | }; |
147 | |
148 | class Q_AUTOTEST_EXPORT QHashedCStringRef |
149 | { |
150 | public: |
151 | inline QHashedCStringRef(); |
152 | inline QHashedCStringRef(const char *, int); |
153 | inline QHashedCStringRef(const char *, int, quint32); |
154 | inline QHashedCStringRef(const QHashedCStringRef &); |
155 | |
156 | inline quint32 hash() const; |
157 | |
158 | inline const char *constData() const; |
159 | inline int length() const; |
160 | |
161 | QString toUtf16() const; |
162 | inline int utf16length() const; |
163 | inline void writeUtf16(QChar *) const; |
164 | inline void writeUtf16(quint16 *) const; |
165 | private: |
166 | friend class QHashedStringRef; |
167 | |
168 | inline void computeHash() const; |
169 | |
170 | const char *m_data = nullptr; |
171 | int m_length = 0; |
172 | mutable quint32 m_hash = 0; |
173 | }; |
174 | |
175 | inline uint qHash(const QHashedString &string) |
176 | { |
177 | return uint(string.hash()); |
178 | } |
179 | |
180 | inline uint qHash(const QHashedStringRef &string) |
181 | { |
182 | return uint(string.hash()); |
183 | } |
184 | |
185 | QHashedString::QHashedString() |
186 | : QString() |
187 | { |
188 | } |
189 | |
190 | QHashedString::QHashedString(const QString &string) |
191 | : QString(string), m_hash(0) |
192 | { |
193 | } |
194 | |
195 | QHashedString::QHashedString(const QString &string, quint32 hash) |
196 | : QString(string), m_hash(hash) |
197 | { |
198 | } |
199 | |
200 | QHashedString::QHashedString(const QHashedString &string) |
201 | : QString(string), m_hash(string.m_hash) |
202 | { |
203 | } |
204 | |
205 | QHashedString &QHashedString::operator=(const QHashedString &string) |
206 | { |
207 | static_cast<QString &>(*this) = string; |
208 | m_hash = string.m_hash; |
209 | return *this; |
210 | } |
211 | |
212 | bool QHashedString::operator==(const QHashedString &string) const |
213 | { |
214 | return (string.m_hash == m_hash || !string.m_hash || !m_hash) && |
215 | static_cast<const QString &>(*this) == static_cast<const QString &>(string); |
216 | } |
217 | |
218 | bool QHashedString::operator==(const QHashedStringRef &string) const |
219 | { |
220 | return length() == string.m_length && |
221 | (string.m_hash == m_hash || !string.m_hash || !m_hash) && |
222 | QHashedString::compare(lhs: constData(), rhs: string.m_data, length: string.m_length); |
223 | } |
224 | |
225 | quint32 QHashedString::hash() const |
226 | { |
227 | if (!m_hash) computeHash(); |
228 | return m_hash; |
229 | } |
230 | |
231 | quint32 QHashedString::existingHash() const |
232 | { |
233 | return m_hash; |
234 | } |
235 | |
236 | QHashedStringRef::QHashedStringRef() |
237 | { |
238 | } |
239 | |
240 | QHashedStringRef::QHashedStringRef(const QString &str) |
241 | : m_data(str.constData()), m_length(str.length()), m_hash(0) |
242 | { |
243 | } |
244 | |
245 | QHashedStringRef::QHashedStringRef(const QStringRef &str) |
246 | : m_data(str.constData()), m_length(str.length()), m_hash(0) |
247 | { |
248 | } |
249 | |
250 | QHashedStringRef::QHashedStringRef(const QChar *data, int length) |
251 | : m_data(data), m_length(length), m_hash(0) |
252 | { |
253 | } |
254 | |
255 | QHashedStringRef::QHashedStringRef(const QChar *data, int length, quint32 hash) |
256 | : m_data(data), m_length(length), m_hash(hash) |
257 | { |
258 | } |
259 | |
260 | QHashedStringRef::QHashedStringRef(const QHashedString &string) |
261 | : m_data(string.constData()), m_length(string.length()), m_hash(string.m_hash) |
262 | { |
263 | } |
264 | |
265 | QHashedStringRef::QHashedStringRef(const QHashedStringRef &string) |
266 | : m_data(string.m_data), m_length(string.m_length), m_hash(string.m_hash) |
267 | { |
268 | } |
269 | |
270 | QHashedStringRef &QHashedStringRef::operator=(const QHashedStringRef &o) |
271 | { |
272 | m_data = o.m_data; |
273 | m_length = o.m_length; |
274 | m_hash = o.m_hash; |
275 | return *this; |
276 | } |
277 | |
278 | bool QHashedStringRef::operator==(const QString &string) const |
279 | { |
280 | return m_length == string.length() && |
281 | QHashedString::compare(lhs: string.constData(), rhs: m_data, length: m_length); |
282 | } |
283 | |
284 | bool QHashedStringRef::operator==(const QHashedString &string) const |
285 | { |
286 | return m_length == string.length() && |
287 | (m_hash == string.m_hash || !m_hash || !string.m_hash) && |
288 | QHashedString::compare(lhs: string.constData(), rhs: m_data, length: m_length); |
289 | } |
290 | |
291 | bool QHashedStringRef::operator==(const QHashedStringRef &string) const |
292 | { |
293 | return m_length == string.m_length && |
294 | (m_hash == string.m_hash || !m_hash || !string.m_hash) && |
295 | QHashedString::compare(lhs: string.m_data, rhs: m_data, length: m_length); |
296 | } |
297 | |
298 | bool QHashedStringRef::operator==(const QHashedCStringRef &string) const |
299 | { |
300 | return m_length == string.m_length && |
301 | (m_hash == string.m_hash || !m_hash || !string.m_hash) && |
302 | QHashedString::compare(lhs: m_data, rhs: string.m_data, length: m_length); |
303 | } |
304 | |
305 | bool QHashedStringRef::operator!=(const QString &string) const |
306 | { |
307 | return m_length != string.length() || |
308 | !QHashedString::compare(lhs: string.constData(), rhs: m_data, length: m_length); |
309 | } |
310 | |
311 | bool QHashedStringRef::operator!=(const QHashedString &string) const |
312 | { |
313 | return m_length != string.length() || |
314 | (m_hash != string.m_hash && m_hash && string.m_hash) || |
315 | !QHashedString::compare(lhs: string.constData(), rhs: m_data, length: m_length); |
316 | } |
317 | |
318 | bool QHashedStringRef::operator!=(const QHashedStringRef &string) const |
319 | { |
320 | return m_length != string.m_length || |
321 | (m_hash != string.m_hash && m_hash && string.m_hash) || |
322 | QHashedString::compare(lhs: string.m_data, rhs: m_data, length: m_length); |
323 | } |
324 | |
325 | bool QHashedStringRef::operator!=(const QHashedCStringRef &string) const |
326 | { |
327 | return m_length != string.m_length || |
328 | (m_hash != string.m_hash && m_hash && string.m_hash) || |
329 | QHashedString::compare(lhs: m_data, rhs: string.m_data, length: m_length); |
330 | } |
331 | |
332 | QChar *QHashedStringRef::data() |
333 | { |
334 | return const_cast<QChar *>(m_data); |
335 | } |
336 | |
337 | const QChar &QHashedStringRef::at(int index) const |
338 | { |
339 | Q_ASSERT(index < m_length); |
340 | return m_data[index]; |
341 | } |
342 | |
343 | const QChar *QHashedStringRef::constData() const |
344 | { |
345 | return m_data; |
346 | } |
347 | |
348 | bool QHashedStringRef::isEmpty() const |
349 | { |
350 | return m_length == 0; |
351 | } |
352 | |
353 | int QHashedStringRef::length() const |
354 | { |
355 | return m_length; |
356 | } |
357 | |
358 | bool QHashedStringRef::isLatin1() const |
359 | { |
360 | for (int ii = 0; ii < m_length; ++ii) |
361 | if (m_data[ii].unicode() > 127) return false; |
362 | return true; |
363 | } |
364 | |
365 | void QHashedStringRef::computeHash() const |
366 | { |
367 | m_hash = QHashedString::stringHash(data: m_data, length: m_length); |
368 | } |
369 | |
370 | bool QHashedStringRef::startsWithUpper() const |
371 | { |
372 | if (m_length < 1) return false; |
373 | return m_data[0].isUpper(); |
374 | } |
375 | |
376 | quint32 QHashedStringRef::hash() const |
377 | { |
378 | if (!m_hash) computeHash(); |
379 | return m_hash; |
380 | } |
381 | |
382 | QHashedCStringRef::QHashedCStringRef() |
383 | { |
384 | } |
385 | |
386 | QHashedCStringRef::QHashedCStringRef(const char *data, int length) |
387 | : m_data(data), m_length(length), m_hash(0) |
388 | { |
389 | } |
390 | |
391 | QHashedCStringRef::QHashedCStringRef(const char *data, int length, quint32 hash) |
392 | : m_data(data), m_length(length), m_hash(hash) |
393 | { |
394 | } |
395 | |
396 | QHashedCStringRef::QHashedCStringRef(const QHashedCStringRef &o) |
397 | : m_data(o.m_data), m_length(o.m_length), m_hash(o.m_hash) |
398 | { |
399 | } |
400 | |
401 | quint32 QHashedCStringRef::hash() const |
402 | { |
403 | if (!m_hash) computeHash(); |
404 | return m_hash; |
405 | } |
406 | |
407 | const char *QHashedCStringRef::constData() const |
408 | { |
409 | return m_data; |
410 | } |
411 | |
412 | int QHashedCStringRef::length() const |
413 | { |
414 | return m_length; |
415 | } |
416 | |
417 | int QHashedCStringRef::utf16length() const |
418 | { |
419 | return m_length; |
420 | } |
421 | |
422 | void QHashedCStringRef::writeUtf16(QChar *output) const |
423 | { |
424 | writeUtf16((quint16 *)output); |
425 | } |
426 | |
427 | void QHashedCStringRef::writeUtf16(quint16 *output) const |
428 | { |
429 | int l = m_length; |
430 | const char *d = m_data; |
431 | while (l--) |
432 | *output++ = *d++; |
433 | } |
434 | |
435 | void QHashedCStringRef::computeHash() const |
436 | { |
437 | m_hash = QHashedString::stringHash(data: m_data, length: m_length); |
438 | } |
439 | |
440 | bool QHashedString::compare(const QChar *lhs, const char *rhs, int length) |
441 | { |
442 | Q_ASSERT(lhs && rhs); |
443 | const quint16 *l = (const quint16*)lhs; |
444 | while (length--) |
445 | if (*l++ != *rhs++) return false; |
446 | return true; |
447 | } |
448 | |
449 | bool QHashedString::compare(const char *lhs, const char *rhs, int length) |
450 | { |
451 | Q_ASSERT(lhs && rhs); |
452 | return 0 == ::memcmp(s1: lhs, s2: rhs, n: length); |
453 | } |
454 | |
455 | quint32 QHashedString::stringHash(const QChar *data, int length) |
456 | { |
457 | return QV4::String::createHashValue(ch: data, length, subtype: nullptr); |
458 | } |
459 | |
460 | quint32 QHashedString::stringHash(const char *data, int length) |
461 | { |
462 | return QV4::String::createHashValue(ch: data, length, subtype: nullptr); |
463 | } |
464 | |
465 | void QHashedString::computeHash() const |
466 | { |
467 | m_hash = stringHash(data: constData(), length: length()); |
468 | } |
469 | |
470 | QT_END_NAMESPACE |
471 | |
472 | #endif // QHASHEDSTRING_P_H |
473 | |