1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
4#include "proitems.h"
5
6#include <qfileinfo.h>
7#include <qset.h>
8#include <qstringlist.h>
9#include <qtextstream.h>
10#include <private/qduplicatetracker_p.h>
11
12QT_BEGIN_NAMESPACE
13
14// from qhash.cpp
15size_t ProString::hash(const QChar *p, int n)
16{
17 size_t h = 0;
18
19 while (n--) {
20 h = (h << 4) + (*p++).unicode();
21 h ^= (h & 0xf0000000) >> 23;
22 h &= 0x0fffffff;
23 }
24 return h;
25}
26
27ProString::ProString() :
28 m_offset(0), m_length(0), m_file(0), m_hash(0x80000000)
29{
30}
31
32ProString::ProString(const ProString &other) :
33 m_string(other.m_string), m_offset(other.m_offset), m_length(other.m_length), m_file(other.m_file), m_hash(other.m_hash)
34{
35}
36
37ProString::ProString(const ProString &other, OmitPreHashing) :
38 m_string(other.m_string), m_offset(other.m_offset), m_length(other.m_length), m_file(other.m_file), m_hash(0x80000000)
39{
40}
41
42ProString::ProString(const QString &str, DoPreHashing) :
43 m_string(str), m_offset(0), m_length(str.size()), m_file(0)
44{
45 updatedHash();
46}
47
48ProString::ProString(const QString &str) :
49 m_string(str), m_offset(0), m_length(str.size()), m_file(0), m_hash(0x80000000)
50{
51}
52
53ProString::ProString(QStringView str) :
54 m_string(str.toString()), m_offset(0), m_length(str.size()), m_file(0), m_hash(0x80000000)
55{
56}
57
58ProString::ProString(const char *str, DoPreHashing) :
59 m_string(QString::fromLatin1(ba: str)), m_offset(0), m_length(int(qstrlen(str))), m_file(0)
60{
61 updatedHash();
62}
63
64ProString::ProString(const char *str) :
65 m_string(QString::fromLatin1(ba: str)), m_offset(0), m_length(int(qstrlen(str))), m_file(0), m_hash(0x80000000)
66{
67}
68
69ProString::ProString(const QString &str, int offset, int length, DoPreHashing) :
70 m_string(str), m_offset(offset), m_length(length), m_file(0)
71{
72 updatedHash();
73}
74
75ProString::ProString(const QString &str, int offset, int length, uint hash) :
76 m_string(str), m_offset(offset), m_length(length), m_file(0), m_hash(hash)
77{
78}
79
80ProString::ProString(const QString &str, int offset, int length) :
81 m_string(str), m_offset(offset), m_length(length), m_file(0), m_hash(0x80000000)
82{
83}
84
85void ProString::setValue(const QString &str)
86{
87 m_string = str, m_offset = 0, m_length = str.size(), m_hash = 0x80000000;
88}
89
90size_t ProString::updatedHash() const
91{
92 return (m_hash = hash(p: m_string.constData() + m_offset, n: m_length));
93}
94
95size_t qHash(const ProString &str)
96{
97 if (!(str.m_hash & 0x80000000))
98 return str.m_hash;
99 return str.updatedHash();
100}
101
102ProKey::ProKey(const QString &str) :
103 ProString(str, DoHash)
104{
105}
106
107ProKey::ProKey(const char *str) :
108 ProString(str, DoHash)
109{
110}
111
112ProKey::ProKey(const QString &str, int off, int len) :
113 ProString(str, off, len, DoHash)
114{
115}
116
117ProKey::ProKey(const QString &str, int off, int len, uint hash) :
118 ProString(str, off, len, hash)
119{
120}
121
122void ProKey::setValue(const QString &str)
123{
124 m_string = str, m_offset = 0, m_length = str.size();
125 updatedHash();
126}
127
128QString ProString::toQString() const
129{
130 return m_string.mid(position: m_offset, n: m_length);
131}
132
133QString &ProString::toQString(QString &tmp) const
134{
135 tmp = m_string.mid(position: m_offset, n: m_length);
136 return tmp;
137}
138
139ProString &ProString::prepend(const ProString &other)
140{
141 if (other.m_length) {
142 if (!m_length) {
143 *this = other;
144 } else {
145 m_string = other.toQStringView() + toQStringView();
146 m_offset = 0;
147 m_length = m_string.size();
148 if (!m_file)
149 m_file = other.m_file;
150 m_hash = 0x80000000;
151 }
152 }
153 return *this;
154}
155
156ProString &ProString::append(const QLatin1String other)
157{
158 if (other.size()) {
159 if (m_length != m_string.size()) {
160 m_string = toQStringView() + other;
161 m_offset = 0;
162 m_length = m_string.size();
163 } else {
164 Q_ASSERT(m_offset == 0);
165 m_string.append(s: other);
166 m_length += other.size();
167 }
168 m_hash = 0x80000000;
169 }
170 return *this;
171}
172
173ProString &ProString::append(QChar other)
174{
175 if (m_length != m_string.size()) {
176 m_string = toQStringView() + other;
177 m_offset = 0;
178 m_length = m_string.size();
179 } else {
180 Q_ASSERT(m_offset == 0);
181 m_string.append(c: other);
182 ++m_length;
183 }
184 m_hash = 0x80000000;
185 return *this;
186}
187
188// If pending != 0, prefix with space if appending to non-empty non-pending
189ProString &ProString::append(const ProString &other, bool *pending)
190{
191 if (other.m_length) {
192 if (!m_length) {
193 *this = other;
194 } else {
195 if (m_length != m_string.size())
196 m_string = toQString();
197 if (pending && !*pending) {
198 m_string += QLatin1Char(' ') + other.toQStringView();
199 } else {
200 m_string += other.toQStringView();
201 }
202 m_length = m_string.size();
203 m_offset = 0;
204 if (other.m_file)
205 m_file = other.m_file;
206 m_hash = 0x80000000;
207 }
208 if (pending)
209 *pending = true;
210 }
211 return *this;
212}
213
214ProString &ProString::append(const ProStringList &other, bool *pending, bool skipEmpty1st)
215{
216 if (const int sz = other.size()) {
217 int startIdx = 0;
218 if (pending && !*pending && skipEmpty1st && other.at(i: 0).isEmpty()) {
219 if (sz == 1)
220 return *this;
221 startIdx = 1;
222 }
223 if (!m_length && sz == startIdx + 1) {
224 *this = other.at(i: startIdx);
225 } else {
226 bool putSpace = false;
227 if (pending && !*pending && m_length)
228 putSpace = true;
229
230 m_string = toQString();
231 m_offset = 0;
232 for (int i = startIdx; i < sz; ++i) {
233 if (putSpace)
234 m_string += QLatin1Char(' ');
235 else
236 putSpace = true;
237 const ProString &str = other.at(i);
238 m_string += str.toQStringView();
239 }
240 m_length = m_string.size();
241 if (other.last().m_file)
242 m_file = other.last().m_file;
243 m_hash = 0x80000000;
244 }
245 if (pending)
246 *pending = true;
247 }
248 return *this;
249}
250
251QString operator+(const ProString &one, const ProString &two)
252{
253 if (two.m_length) {
254 if (!one.m_length) {
255 return two.toQString();
256 } else {
257 QString neu(one.m_length + two.m_length, Qt::Uninitialized);
258 ushort *ptr = (ushort *)neu.constData();
259 memcpy(dest: ptr, src: one.m_string.constData() + one.m_offset, n: one.m_length * 2);
260 memcpy(dest: ptr + one.m_length, src: two.m_string.constData() + two.m_offset, n: two.m_length * 2);
261 return neu;
262 }
263 }
264 return one.toQString();
265}
266
267
268ProString ProString::mid(int off, int len) const
269{
270 ProString ret(*this, NoHash);
271 if (off > m_length)
272 off = m_length;
273 ret.m_offset += off;
274 ret.m_length -= off;
275 if ((uint)ret.m_length > (uint)len) // Unsigned comparison to interpret < 0 as infinite
276 ret.m_length = len;
277 return ret;
278}
279
280ProString ProString::trimmed() const
281{
282 ProString ret(*this, NoHash);
283 int cur = m_offset;
284 int end = cur + m_length;
285 const QChar *data = m_string.constData();
286 for (; cur < end; cur++)
287 if (!data[cur].isSpace()) {
288 // No underrun check - we know there is at least one non-whitespace
289 while (data[end - 1].isSpace())
290 end--;
291 break;
292 }
293 ret.m_offset = cur;
294 ret.m_length = end - cur;
295 return ret;
296}
297
298QTextStream &operator<<(QTextStream &t, const ProString &str)
299{
300 t << str.toQStringView();
301 return t;
302}
303
304static QString ProStringList_join(const ProStringList &this_, const QChar *sep, const int sepSize)
305{
306 int totalLength = 0;
307 const int sz = this_.size();
308
309 for (int i = 0; i < sz; ++i)
310 totalLength += this_.at(i).size();
311
312 if (sz)
313 totalLength += sepSize * (sz - 1);
314
315 QString res(totalLength, Qt::Uninitialized);
316 QChar *ptr = (QChar *)res.constData();
317 for (int i = 0; i < sz; ++i) {
318 if (i) {
319 memcpy(dest: ptr, src: sep, n: sepSize * sizeof(QChar));
320 ptr += sepSize;
321 }
322 const ProString &str = this_.at(i);
323 memcpy(dest: ptr, src: str.constData(), n: str.size() * sizeof(QChar));
324 ptr += str.size();
325 }
326 return res;
327}
328
329QString ProStringList::join(const ProString &sep) const
330{
331 return ProStringList_join(this_: *this, sep: sep.constData(), sepSize: sep.size());
332}
333
334QString ProStringList::join(const QString &sep) const
335{
336 return ProStringList_join(this_: *this, sep: sep.constData(), sepSize: sep.size());
337}
338
339QString ProStringList::join(QChar sep) const
340{
341 return ProStringList_join(this_: *this, sep: &sep, sepSize: 1);
342}
343
344void ProStringList::removeAll(const ProString &str)
345{
346 for (int i = size(); --i >= 0; )
347 if (at(i) == str)
348 remove(i);
349}
350
351void ProStringList::removeAll(const char *str)
352{
353 for (int i = size(); --i >= 0; )
354 if (at(i) == str)
355 remove(i);
356}
357
358void ProStringList::removeEach(const ProStringList &value)
359{
360 for (const ProString &str : value) {
361 if (isEmpty())
362 break;
363 if (!str.isEmpty())
364 removeAll(str);
365 }
366}
367
368void ProStringList::removeEmpty()
369{
370 for (int i = size(); --i >= 0;)
371 if (at(i).isEmpty())
372 remove(i);
373}
374
375void ProStringList::removeDuplicates()
376{
377 QDuplicateTracker<ProString> seen(size());
378 removeIf(pred: [&](const ProString &s) { return seen.hasSeen(s); });
379}
380
381void ProStringList::insertUnique(const ProStringList &value)
382{
383 for (const ProString &str : value)
384 if (!str.isEmpty() && !contains(str))
385 append(t: str);
386}
387
388ProStringList::ProStringList(const QStringList &list)
389{
390 reserve(asize: list.size());
391 for (const QString &str : list)
392 *this << ProString(str);
393}
394
395QStringList ProStringList::toQStringList() const
396{
397 QStringList ret;
398 ret.reserve(asize: size());
399 for (const auto &e : *this)
400 ret.append(t: e.toQString());
401 return ret;
402}
403
404bool ProStringList::contains(const ProString &str, Qt::CaseSensitivity cs) const
405{
406 for (int i = 0; i < size(); i++)
407 if (!at(i).compare(sub: str, cs))
408 return true;
409 return false;
410}
411
412bool ProStringList::contains(QStringView str, Qt::CaseSensitivity cs) const
413{
414 for (int i = 0; i < size(); i++)
415 if (!at(i).toQStringView().compare(other: str, cs))
416 return true;
417 return false;
418}
419
420bool ProStringList::contains(const char *str, Qt::CaseSensitivity cs) const
421{
422 for (int i = 0; i < size(); i++)
423 if (!at(i).compare(sub: str, cs))
424 return true;
425 return false;
426}
427
428ProFile::ProFile(int id, const QString &fileName)
429 : m_refCount(1),
430 m_fileName(fileName),
431 m_id(id),
432 m_ok(true),
433 m_hostBuild(false)
434{
435 if (!fileName.startsWith(c: QLatin1Char('(')))
436 m_directoryName = QFileInfo( // qmake sickness: canonicalize only the directory!
437 fileName.left(n: fileName.lastIndexOf(c: QLatin1Char('/')))).canonicalFilePath();
438}
439
440ProFile::~ProFile()
441{
442}
443
444ProString ProFile::getStr(const ushort *&tPtr)
445{
446 uint len = *tPtr++;
447 ProString ret(items(), tPtr - tokPtr(), len);
448 ret.setSource(m_id);
449 tPtr += len;
450 return ret;
451}
452
453ProKey ProFile::getHashStr(const ushort *&tPtr)
454{
455 uint hash = *tPtr++;
456 hash |= (uint)*tPtr++ << 16;
457 uint len = *tPtr++;
458 ProKey ret(items(), tPtr - tokPtr(), len, hash);
459 tPtr += len;
460 return ret;
461}
462
463QDebug operator<<(QDebug debug, const ProString &str)
464{
465 return debug << str.toQString();
466}
467
468QT_END_NAMESPACE
469

source code of qtbase/qmake/library/proitems.cpp