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
64QT_BEGIN_NAMESPACE
65
66class QHashedStringRef;
67class Q_QML_PRIVATE_EXPORT QHashedString : public QString
68{
69public:
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
89private:
90 friend class QHashedStringRef;
91 friend class QStringHashNode;
92
93 inline void computeHash() const;
94 mutable quint32 m_hash = 0;
95};
96
97class QHashedCStringRef;
98class Q_QML_PRIVATE_EXPORT QHashedStringRef
99{
100public:
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
129 inline bool isEmpty() const;
130 inline int length() const;
131 inline bool startsWithUpper() const;
132
133 QString toString() const;
134
135 inline bool isLatin1() const;
136
137private:
138 friend class QHashedString;
139
140 inline void computeHash() const;
141
142 const QChar *m_data = nullptr;
143 int m_length = 0;
144 mutable quint32 m_hash = 0;
145};
146
147class Q_AUTOTEST_EXPORT QHashedCStringRef
148{
149public:
150 inline QHashedCStringRef();
151 inline QHashedCStringRef(const char *, int);
152 inline QHashedCStringRef(const char *, int, quint32);
153 inline QHashedCStringRef(const QHashedCStringRef &);
154
155 inline quint32 hash() const;
156
157 inline const char *constData() const;
158 inline int length() const;
159
160 QString toUtf16() const;
161 inline int utf16length() const;
162 inline void writeUtf16(QChar *) const;
163 inline void writeUtf16(quint16 *) const;
164private:
165 friend class QHashedStringRef;
166
167 inline void computeHash() const;
168
169 const char *m_data = nullptr;
170 int m_length = 0;
171 mutable quint32 m_hash = 0;
172};
173
174inline uint qHash(const QHashedString &string)
175{
176 return uint(string.hash());
177}
178
179inline uint qHash(const QHashedStringRef &string)
180{
181 return uint(string.hash());
182}
183
184QHashedString::QHashedString()
185: QString()
186{
187}
188
189QHashedString::QHashedString(const QString &string)
190: QString(string), m_hash(0)
191{
192}
193
194QHashedString::QHashedString(const QString &string, quint32 hash)
195: QString(string), m_hash(hash)
196{
197}
198
199QHashedString::QHashedString(const QHashedString &string)
200: QString(string), m_hash(string.m_hash)
201{
202}
203
204QHashedString &QHashedString::operator=(const QHashedString &string)
205{
206 static_cast<QString &>(*this) = string;
207 m_hash = string.m_hash;
208 return *this;
209}
210
211bool QHashedString::operator==(const QHashedString &string) const
212{
213 return (string.m_hash == m_hash || !string.m_hash || !m_hash) &&
214 static_cast<const QString &>(*this) == static_cast<const QString &>(string);
215}
216
217bool QHashedString::operator==(const QHashedStringRef &string) const
218{
219 return length() == string.m_length &&
220 (string.m_hash == m_hash || !string.m_hash || !m_hash) &&
221 QHashedString::compare(constData(), string.m_data, string.m_length);
222}
223
224quint32 QHashedString::hash() const
225{
226 if (!m_hash) computeHash();
227 return m_hash;
228}
229
230quint32 QHashedString::existingHash() const
231{
232 return m_hash;
233}
234
235QHashedStringRef::QHashedStringRef()
236{
237}
238
239QHashedStringRef::QHashedStringRef(const QString &str)
240: m_data(str.constData()), m_length(str.length()), m_hash(0)
241{
242}
243
244QHashedStringRef::QHashedStringRef(const QStringRef &str)
245: m_data(str.constData()), m_length(str.length()), m_hash(0)
246{
247}
248
249QHashedStringRef::QHashedStringRef(const QChar *data, int length)
250: m_data(data), m_length(length), m_hash(0)
251{
252}
253
254QHashedStringRef::QHashedStringRef(const QChar *data, int length, quint32 hash)
255: m_data(data), m_length(length), m_hash(hash)
256{
257}
258
259QHashedStringRef::QHashedStringRef(const QHashedString &string)
260: m_data(string.constData()), m_length(string.length()), m_hash(string.m_hash)
261{
262}
263
264QHashedStringRef::QHashedStringRef(const QHashedStringRef &string)
265: m_data(string.m_data), m_length(string.m_length), m_hash(string.m_hash)
266{
267}
268
269QHashedStringRef &QHashedStringRef::operator=(const QHashedStringRef &o)
270{
271 m_data = o.m_data;
272 m_length = o.m_length;
273 m_hash = o.m_hash;
274 return *this;
275}
276
277bool QHashedStringRef::operator==(const QString &string) const
278{
279 return m_length == string.length() &&
280 QHashedString::compare(string.constData(), m_data, m_length);
281}
282
283bool QHashedStringRef::operator==(const QHashedString &string) const
284{
285 return m_length == string.length() &&
286 (m_hash == string.m_hash || !m_hash || !string.m_hash) &&
287 QHashedString::compare(string.constData(), m_data, m_length);
288}
289
290bool QHashedStringRef::operator==(const QHashedStringRef &string) const
291{
292 return m_length == string.m_length &&
293 (m_hash == string.m_hash || !m_hash || !string.m_hash) &&
294 QHashedString::compare(string.m_data, m_data, m_length);
295}
296
297bool QHashedStringRef::operator==(const QHashedCStringRef &string) const
298{
299 return m_length == string.m_length &&
300 (m_hash == string.m_hash || !m_hash || !string.m_hash) &&
301 QHashedString::compare(m_data, string.m_data, m_length);
302}
303
304bool QHashedStringRef::operator!=(const QString &string) const
305{
306 return m_length != string.length() ||
307 !QHashedString::compare(string.constData(), m_data, m_length);
308}
309
310bool QHashedStringRef::operator!=(const QHashedString &string) const
311{
312 return m_length != string.length() ||
313 (m_hash != string.m_hash && m_hash && string.m_hash) ||
314 !QHashedString::compare(string.constData(), m_data, m_length);
315}
316
317bool QHashedStringRef::operator!=(const QHashedStringRef &string) const
318{
319 return m_length != string.m_length ||
320 (m_hash != string.m_hash && m_hash && string.m_hash) ||
321 QHashedString::compare(string.m_data, m_data, m_length);
322}
323
324bool QHashedStringRef::operator!=(const QHashedCStringRef &string) const
325{
326 return m_length != string.m_length ||
327 (m_hash != string.m_hash && m_hash && string.m_hash) ||
328 QHashedString::compare(m_data, string.m_data, m_length);
329}
330
331QChar *QHashedStringRef::data()
332{
333 return const_cast<QChar *>(m_data);
334}
335
336const QChar &QHashedStringRef::at(int index) const
337{
338 Q_ASSERT(index < m_length);
339 return m_data[index];
340}
341
342const QChar *QHashedStringRef::constData() const
343{
344 return m_data;
345}
346
347bool QHashedStringRef::isEmpty() const
348{
349 return m_length == 0;
350}
351
352int QHashedStringRef::length() const
353{
354 return m_length;
355}
356
357bool QHashedStringRef::isLatin1() const
358{
359 for (int ii = 0; ii < m_length; ++ii)
360 if (m_data[ii].unicode() > 127) return false;
361 return true;
362}
363
364void QHashedStringRef::computeHash() const
365{
366 m_hash = QHashedString::stringHash(m_data, m_length);
367}
368
369bool QHashedStringRef::startsWithUpper() const
370{
371 if (m_length < 1) return false;
372 return m_data[0].isUpper();
373}
374
375quint32 QHashedStringRef::hash() const
376{
377 if (!m_hash) computeHash();
378 return m_hash;
379}
380
381QHashedCStringRef::QHashedCStringRef()
382{
383}
384
385QHashedCStringRef::QHashedCStringRef(const char *data, int length)
386: m_data(data), m_length(length), m_hash(0)
387{
388}
389
390QHashedCStringRef::QHashedCStringRef(const char *data, int length, quint32 hash)
391: m_data(data), m_length(length), m_hash(hash)
392{
393}
394
395QHashedCStringRef::QHashedCStringRef(const QHashedCStringRef &o)
396: m_data(o.m_data), m_length(o.m_length), m_hash(o.m_hash)
397{
398}
399
400quint32 QHashedCStringRef::hash() const
401{
402 if (!m_hash) computeHash();
403 return m_hash;
404}
405
406const char *QHashedCStringRef::constData() const
407{
408 return m_data;
409}
410
411int QHashedCStringRef::length() const
412{
413 return m_length;
414}
415
416int QHashedCStringRef::utf16length() const
417{
418 return m_length;
419}
420
421void QHashedCStringRef::writeUtf16(QChar *output) const
422{
423 writeUtf16((quint16 *)output);
424}
425
426void QHashedCStringRef::writeUtf16(quint16 *output) const
427{
428 int l = m_length;
429 const char *d = m_data;
430 while (l--)
431 *output++ = *d++;
432}
433
434void QHashedCStringRef::computeHash() const
435{
436 m_hash = QHashedString::stringHash(m_data, m_length);
437}
438
439bool QHashedString::compare(const QChar *lhs, const char *rhs, int length)
440{
441 Q_ASSERT(lhs && rhs);
442 const quint16 *l = (const quint16*)lhs;
443 while (length--)
444 if (*l++ != *rhs++) return false;
445 return true;
446}
447
448bool QHashedString::compare(const char *lhs, const char *rhs, int length)
449{
450 Q_ASSERT(lhs && rhs);
451 return 0 == ::memcmp(lhs, rhs, length);
452}
453
454quint32 QHashedString::stringHash(const QChar *data, int length)
455{
456 return QV4::String::createHashValue(data, length, nullptr);
457}
458
459quint32 QHashedString::stringHash(const char *data, int length)
460{
461 return QV4::String::createHashValue(data, length, nullptr);
462}
463
464void QHashedString::computeHash() const
465{
466 m_hash = stringHash(constData(), length());
467}
468
469QT_END_NAMESPACE
470
471#endif // QHASHEDSTRING_P_H
472