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 | #include "qhashedstring_p.h" |
41 | |
42 | QT_BEGIN_NAMESPACE |
43 | |
44 | // Copy of QString's qMemCompare |
45 | bool QHashedString::compare(const QChar *lhs, const QChar *rhs, int length) |
46 | { |
47 | Q_ASSERT(lhs && rhs); |
48 | const quint16 *a = (const quint16 *)lhs; |
49 | const quint16 *b = (const quint16 *)rhs; |
50 | |
51 | if (a == b || !length) |
52 | return true; |
53 | |
54 | union { |
55 | const quint16 *w; |
56 | const quint32 *d; |
57 | quintptr value; |
58 | } sa, sb; |
59 | sa.w = a; |
60 | sb.w = b; |
61 | |
62 | // check alignment |
63 | if ((sa.value & 2) == (sb.value & 2)) { |
64 | // both addresses have the same alignment |
65 | if (sa.value & 2) { |
66 | // both addresses are not aligned to 4-bytes boundaries |
67 | // compare the first character |
68 | if (*sa.w != *sb.w) |
69 | return false; |
70 | --length; |
71 | ++sa.w; |
72 | ++sb.w; |
73 | |
74 | // now both addresses are 4-bytes aligned |
75 | } |
76 | |
77 | // both addresses are 4-bytes aligned |
78 | // do a fast 32-bit comparison |
79 | const quint32 *e = sa.d + (length >> 1); |
80 | for ( ; sa.d != e; ++sa.d, ++sb.d) { |
81 | if (*sa.d != *sb.d) |
82 | return false; |
83 | } |
84 | |
85 | // do we have a tail? |
86 | return (length & 1) ? *sa.w == *sb.w : true; |
87 | } else { |
88 | // one of the addresses isn't 4-byte aligned but the other is |
89 | const quint16 *e = sa.w + length; |
90 | for ( ; sa.w != e; ++sa.w, ++sb.w) { |
91 | if (*sa.w != *sb.w) |
92 | return false; |
93 | } |
94 | } |
95 | return true; |
96 | } |
97 | |
98 | QHashedStringRef QHashedStringRef::mid(int offset, int length) const |
99 | { |
100 | Q_ASSERT(offset < m_length); |
101 | return QHashedStringRef(m_data + offset, |
102 | (length == -1 || (offset + length) > m_length)?(m_length - offset):length); |
103 | } |
104 | |
105 | QVector<QHashedStringRef> QHashedStringRef::split(const QChar sep) const |
106 | { |
107 | QVector<QHashedStringRef> ret; |
108 | auto curLength = 0; |
109 | auto curOffset = m_data; |
110 | for (int offset = 0; offset < m_length; ++offset) { |
111 | if (*(m_data + offset) == sep) { |
112 | ret.push_back(t: {curOffset, curLength}); |
113 | curOffset = m_data + offset + 1; |
114 | curLength = 0; |
115 | } else { |
116 | ++curLength; |
117 | } |
118 | } |
119 | if (curLength > 0) |
120 | ret.push_back(t: {curOffset, curLength}); |
121 | return ret; |
122 | } |
123 | |
124 | bool QHashedStringRef::endsWith(const QString &s) const |
125 | { |
126 | return s.length() < m_length && |
127 | QHashedString::compare(lhs: s.constData(), rhs: m_data + m_length - s.length(), length: s.length()); |
128 | } |
129 | |
130 | bool QHashedStringRef::startsWith(const QString &s) const |
131 | { |
132 | return s.length() < m_length && |
133 | QHashedString::compare(lhs: s.constData(), rhs: m_data, length: s.length()); |
134 | } |
135 | |
136 | static int findChar(const QChar *str, int len, QChar ch, int from) |
137 | { |
138 | const ushort *s = (const ushort *)str; |
139 | ushort c = ch.unicode(); |
140 | if (from < 0) |
141 | from = qMax(a: from + len, b: 0); |
142 | if (from < len) { |
143 | const ushort *n = s + from - 1; |
144 | const ushort *e = s + len; |
145 | while (++n != e) |
146 | if (*n == c) |
147 | return n - s; |
148 | } |
149 | return -1; |
150 | } |
151 | |
152 | int QHashedStringRef::indexOf(const QChar &c, int from) const |
153 | { |
154 | return findChar(str: m_data, len: m_length, ch: c, from); |
155 | } |
156 | |
157 | QString QHashedStringRef::toString() const |
158 | { |
159 | if (m_length == 0) |
160 | return QString(); |
161 | return QString(m_data, m_length); |
162 | } |
163 | |
164 | QString QHashedCStringRef::toUtf16() const |
165 | { |
166 | if (m_length == 0) |
167 | return QString(); |
168 | |
169 | QString rv; |
170 | rv.resize(size: m_length); |
171 | writeUtf16(output: (quint16*)rv.data()); |
172 | return rv; |
173 | } |
174 | |
175 | QT_END_NAMESPACE |
176 | |