forked from qt-creator/qt-creator
Utils: Use a single QString as data store for FilePath
Plus a few integers to get access to the pieces. This reduces sizeof(FilePath) from 72 to 32. Change-Id: I65eb856ad47b6a250c705d8d01893781a21d8e02 Reviewed-by: Christian Stenger <christian.stenger@qt.io> Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
@@ -198,14 +198,8 @@ def qdump__CPlusPlus__Internal__Value(d, value):
|
||||
|
||||
|
||||
def qdump__Utils__FilePath(d, value):
|
||||
try:
|
||||
# support FilePath before 4.15 as well
|
||||
if not d.extractPointer(value["m_url"]): # there is no valid URL
|
||||
d.putStringValue(value["m_data"])
|
||||
else:
|
||||
d.putItem(value["m_url"])
|
||||
except:
|
||||
scheme, host, path = d.split("{@QString}{@QString}{@QString}", value)
|
||||
data, path_len, scheme_len, host_len = d.split("{@QString}IHH", value)
|
||||
if False:
|
||||
scheme_enc = d.encodeString(scheme)
|
||||
host_enc = d.encodeString(host)
|
||||
elided, path_enc = d.encodeStringHelper(path, d.displayStringLimit)
|
||||
@@ -218,7 +212,10 @@ def qdump__Utils__FilePath(d, value):
|
||||
if not path_enc.startswith(slash):
|
||||
val += slash + dot + slash
|
||||
val += path_enc
|
||||
d.putValue(val, "utf16", elided=elided)
|
||||
else:
|
||||
elided, data_enc = d.encodeStringHelper(data, d.displayStringLimit)
|
||||
val = data_enc
|
||||
d.putValue(val, "utf16", elided=elided)
|
||||
d.putPlainChildren(value)
|
||||
|
||||
|
||||
|
@@ -176,39 +176,39 @@ bool FilePath::isRootPath() const
|
||||
|
||||
QString FilePath::encodedHost() const
|
||||
{
|
||||
QString host = m_host;
|
||||
host.replace('%', "%25");
|
||||
host.replace('/', "%2f");
|
||||
return host;
|
||||
QString result = host().toString();
|
||||
result.replace('%', "%25");
|
||||
result.replace('/', "%2f");
|
||||
return result;
|
||||
}
|
||||
|
||||
/// \returns a QString for passing on to QString based APIs
|
||||
QString FilePath::toString() const
|
||||
{
|
||||
if (m_scheme.isEmpty())
|
||||
return m_path;
|
||||
if (!needsDevice())
|
||||
return path();
|
||||
|
||||
if (isRelativePath())
|
||||
return m_scheme + "://" + encodedHost() + "/./" + m_path;
|
||||
return m_scheme + "://" + encodedHost() + m_path;
|
||||
return scheme() + "://" + encodedHost() + "/./" + path();
|
||||
return scheme() + "://" + encodedHost() + path();
|
||||
}
|
||||
|
||||
QString FilePath::toFSPathString() const
|
||||
{
|
||||
if (m_scheme.isEmpty())
|
||||
return m_path;
|
||||
if (scheme().isEmpty())
|
||||
return path();
|
||||
|
||||
if (isRelativePath())
|
||||
return specialPath(SpecialPathComponent::RootPath) + "/" + m_scheme + "/" + encodedHost() + "/./" + m_path;
|
||||
return specialPath(SpecialPathComponent::RootPath) + "/" + m_scheme + "/" + encodedHost() + m_path;
|
||||
return specialPath(SpecialPathComponent::RootPath) + "/" + scheme() + "/" + encodedHost() + "/./" + path();
|
||||
return specialPath(SpecialPathComponent::RootPath) + "/" + scheme() + "/" + encodedHost() + path();
|
||||
}
|
||||
|
||||
QUrl FilePath::toUrl() const
|
||||
{
|
||||
QUrl url;
|
||||
url.setScheme(m_scheme);
|
||||
url.setHost(m_host);
|
||||
url.setPath(m_path);
|
||||
url.setScheme(scheme().toString());
|
||||
url.setHost(host().toString());
|
||||
url.setPath(path());
|
||||
return url;
|
||||
}
|
||||
|
||||
@@ -217,13 +217,10 @@ QUrl FilePath::toUrl() const
|
||||
/// this path belongs to.
|
||||
QString FilePath::toUserOutput() const
|
||||
{
|
||||
if (needsDevice()) {
|
||||
if (isRelativePath())
|
||||
return m_scheme + "://" + encodedHost() + "/./" + m_path;
|
||||
return m_scheme + "://" + encodedHost() + m_path;
|
||||
}
|
||||
|
||||
QString tmp = toString();
|
||||
if (needsDevice())
|
||||
return tmp;
|
||||
|
||||
if (osType() == OsTypeWindows)
|
||||
tmp.replace('/', '\\');
|
||||
return tmp;
|
||||
@@ -333,25 +330,29 @@ QString FilePath::completeSuffix() const
|
||||
|
||||
QStringView FilePath::scheme() const
|
||||
{
|
||||
return m_scheme;
|
||||
return QStringView{m_data}.mid(m_pathLen, m_schemeLen);
|
||||
}
|
||||
|
||||
QStringView FilePath::host() const
|
||||
{
|
||||
return m_host;
|
||||
return QStringView{m_data}.mid(m_pathLen + m_schemeLen, m_hostLen);
|
||||
}
|
||||
|
||||
QString FilePath::path() const
|
||||
{
|
||||
return m_path;
|
||||
if (m_data.startsWith("/./"))
|
||||
return m_data.mid(3, m_pathLen - 3);
|
||||
return m_data.left(m_pathLen);
|
||||
}
|
||||
|
||||
void FilePath::setParts(const QStringView scheme, const QStringView host, const QStringView path)
|
||||
{
|
||||
QTC_CHECK(!m_scheme.contains('/'));
|
||||
m_scheme = scheme.toString();
|
||||
m_host = host.toString();
|
||||
setPath(path);
|
||||
QTC_CHECK(!scheme.contains('/'));
|
||||
|
||||
m_data = path.toString() + scheme.toString() + host.toString();
|
||||
m_schemeLen = scheme.size();
|
||||
m_hostLen = host.size();
|
||||
m_pathLen = path.size();
|
||||
}
|
||||
|
||||
/// \returns a bool indicating whether a file with this
|
||||
@@ -611,7 +612,7 @@ void FilePath::asyncWriteFileContents(const Continuation<bool> &cont, const QByt
|
||||
|
||||
bool FilePath::needsDevice() const
|
||||
{
|
||||
return !m_scheme.isEmpty();
|
||||
return m_schemeLen != 0;
|
||||
}
|
||||
|
||||
bool FilePath::isSameDevice(const FilePath &other) const
|
||||
@@ -764,7 +765,7 @@ FilePath FilePath::normalizedPathName() const
|
||||
{
|
||||
FilePath result = *this;
|
||||
if (!needsDevice()) // FIXME: Assumes no remote Windows and Mac for now.
|
||||
result.m_path = FileUtils::normalizedPathName(result.m_path);
|
||||
result.setParts(scheme(), host(), FileUtils::normalizedPathName(path()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -833,15 +834,13 @@ bool isWindowsDriveLetter(QChar ch)
|
||||
|
||||
void FilePath::setPath(QStringView path)
|
||||
{
|
||||
if (path.startsWith(QStringLiteral("/./")))
|
||||
path = path.mid(3);
|
||||
m_path = path.toString();
|
||||
setParts(scheme(), host(), path);
|
||||
}
|
||||
|
||||
void FilePath::setFromString(const QString &unnormalizedFileName)
|
||||
{
|
||||
static const QLatin1String qtcDevSlash("__qtc_devices__/");
|
||||
static const QLatin1String colonSlashSlash("://");
|
||||
static const QStringView qtcDevSlash(u"__qtc_devices__/");
|
||||
static const QStringView colonSlashSlash(u"://");
|
||||
|
||||
QString fileName = unnormalizedFileName;
|
||||
if (fileName.contains('\\'))
|
||||
@@ -865,23 +864,21 @@ void FilePath::setFromString(const QString &unnormalizedFileName)
|
||||
const int firstSlash = withoutQtcDeviceRoot.indexOf(slash);
|
||||
|
||||
if (firstSlash != -1) {
|
||||
m_scheme = withoutQtcDeviceRoot.left(firstSlash).toString();
|
||||
QString scheme = withoutQtcDeviceRoot.left(firstSlash).toString();
|
||||
const int secondSlash = withoutQtcDeviceRoot.indexOf(slash, firstSlash + 1);
|
||||
m_host = withoutQtcDeviceRoot.mid(firstSlash + 1, secondSlash - firstSlash - 1)
|
||||
QString host = withoutQtcDeviceRoot.mid(firstSlash + 1, secondSlash - firstSlash - 1)
|
||||
.toString();
|
||||
if (secondSlash != -1) {
|
||||
QStringView path = withoutQtcDeviceRoot.mid(secondSlash);
|
||||
setPath(path);
|
||||
setParts(scheme, host, path);
|
||||
return;
|
||||
}
|
||||
|
||||
m_path = slash;
|
||||
setParts(scheme, host, u"/");
|
||||
return;
|
||||
}
|
||||
|
||||
m_scheme.clear();
|
||||
m_host.clear();
|
||||
m_path = fileName;
|
||||
setParts({}, {}, fileName);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -889,16 +886,14 @@ void FilePath::setFromString(const QString &unnormalizedFileName)
|
||||
const int schemeEnd = fileName.indexOf(colonSlashSlash);
|
||||
if (schemeEnd != -1 && schemeEnd < firstSlash) {
|
||||
// This is a pseudo Url, we can't use QUrl here sadly.
|
||||
m_scheme = fileName.left(schemeEnd);
|
||||
QString scheme = fileName.left(schemeEnd);
|
||||
const int hostEnd = fileName.indexOf(slash, schemeEnd + 3);
|
||||
m_host = fileName.mid(schemeEnd + 3, hostEnd - schemeEnd - 3);
|
||||
if (hostEnd != -1)
|
||||
setPath(QStringView(fileName).mid(hostEnd));
|
||||
QString host = fileName.mid(schemeEnd + 3, hostEnd - schemeEnd - 3);
|
||||
setParts(scheme, host, hostEnd != -1 ? QStringView(fileName).mid(hostEnd) : QStringView());
|
||||
return;
|
||||
}
|
||||
|
||||
setPath(fileName);
|
||||
return;
|
||||
setParts({}, {}, fileName);
|
||||
}
|
||||
|
||||
/// Constructs a FilePath from \a filePath. The \a defaultExtension is appended
|
||||
@@ -951,9 +946,9 @@ QVariant FilePath::toVariant() const
|
||||
|
||||
bool FilePath::operator==(const FilePath &other) const
|
||||
{
|
||||
return QString::compare(m_path, other.m_path, caseSensitivity()) == 0
|
||||
&& m_host == other.m_host
|
||||
&& m_scheme == other.m_scheme;
|
||||
return QString::compare(path(), other.path(), caseSensitivity()) == 0
|
||||
&& host() == other.host()
|
||||
&& scheme() == other.scheme();
|
||||
}
|
||||
|
||||
bool FilePath::operator!=(const FilePath &other) const
|
||||
@@ -963,12 +958,12 @@ bool FilePath::operator!=(const FilePath &other) const
|
||||
|
||||
bool FilePath::operator<(const FilePath &other) const
|
||||
{
|
||||
const int cmp = QString::compare(m_path, other.m_path, caseSensitivity());
|
||||
const int cmp = QString::compare(path(), other.path(), caseSensitivity());
|
||||
if (cmp != 0)
|
||||
return cmp < 0;
|
||||
if (m_host != other.m_host)
|
||||
return m_host < other.m_host;
|
||||
return m_scheme < other.m_scheme;
|
||||
if (host() != other.host())
|
||||
return host() < other.host();
|
||||
return scheme() < other.scheme();
|
||||
}
|
||||
|
||||
bool FilePath::operator<=(const FilePath &other) const
|
||||
@@ -996,15 +991,15 @@ bool FilePath::isChildOf(const FilePath &s) const
|
||||
{
|
||||
if (s.isEmpty())
|
||||
return false;
|
||||
if (!m_path.startsWith(s.m_path, caseSensitivity()))
|
||||
if (!path().startsWith(s.path(), caseSensitivity()))
|
||||
return false;
|
||||
if (m_path.size() <= s.m_path.size())
|
||||
if (path().size() <= s.path().size())
|
||||
return false;
|
||||
// s is root, '/' was already tested in startsWith
|
||||
if (s.m_path.endsWith(QLatin1Char('/')))
|
||||
if (s.path().endsWith(QLatin1Char('/')))
|
||||
return true;
|
||||
// s is a directory, next character should be '/' (/tmpdir is NOT a child of /tmp)
|
||||
return s.m_path.isEmpty() || m_path.at(s.m_path.size()) == QLatin1Char('/');
|
||||
return s.path().isEmpty() || path().at(s.path().size()) == QLatin1Char('/');
|
||||
}
|
||||
|
||||
/// \returns whether path() startsWith \a s
|
||||
@@ -1029,7 +1024,7 @@ bool FilePath::endsWith(const QString &s) const
|
||||
*/
|
||||
bool FilePath::startsWithDriveLetter() const
|
||||
{
|
||||
return !needsDevice() && m_path.size() >= 2 && isWindowsDriveLetter(m_path[0]) && m_path.at(1) == ':';
|
||||
return !needsDevice() && path().size() >= 2 && isWindowsDriveLetter(path()[0]) && path().at(1) == ':';
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -1043,11 +1038,10 @@ FilePath FilePath::relativeChildPath(const FilePath &parent) const
|
||||
{
|
||||
FilePath res;
|
||||
if (isChildOf(parent)) {
|
||||
res.m_scheme = m_scheme;
|
||||
res.m_host = m_host;
|
||||
res.m_path = m_path.mid(parent.m_path.size());
|
||||
if (res.m_path.startsWith('/'))
|
||||
res.m_path = res.m_path.mid(1);
|
||||
QString p = path().mid(parent.path().size());
|
||||
if (p.startsWith('/'))
|
||||
p = p.mid(1);
|
||||
res.setParts(scheme(), host(), p);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -1164,15 +1158,13 @@ QString FilePath::calcRelativePath(const QString &absolutePath, const QString &a
|
||||
*/
|
||||
FilePath FilePath::onDevice(const FilePath &deviceTemplate) const
|
||||
{
|
||||
const bool sameDevice = m_scheme == deviceTemplate.m_scheme && m_host == deviceTemplate.m_host;
|
||||
const bool sameDevice = scheme() == deviceTemplate.scheme() && host() == deviceTemplate.host();
|
||||
if (sameDevice)
|
||||
return *this;
|
||||
// TODO: converting paths between different non local devices is still unsupported
|
||||
QTC_CHECK(!needsDevice());
|
||||
FilePath res;
|
||||
res.m_scheme = deviceTemplate.m_scheme;
|
||||
res.m_host = deviceTemplate.m_host;
|
||||
res.m_path = m_path;
|
||||
res.setParts(deviceTemplate.scheme(), deviceTemplate.host(), path());
|
||||
res.setPath(res.mapToDevicePath());
|
||||
return res;
|
||||
}
|
||||
@@ -1191,9 +1183,7 @@ FilePath FilePath::onDevice(const FilePath &deviceTemplate) const
|
||||
FilePath FilePath::withNewPath(const QString &newPath) const
|
||||
{
|
||||
FilePath res;
|
||||
res.setPath(newPath);
|
||||
res.m_host = m_host;
|
||||
res.m_scheme = m_scheme;
|
||||
res.setParts(scheme(), host(), newPath);
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -1286,9 +1276,11 @@ FilePath FilePath::pathAppended(const QString &path) const
|
||||
if (isEmpty()) {
|
||||
return other;
|
||||
}
|
||||
FilePath fn = *this;
|
||||
join(fn.m_path, other.path());
|
||||
return fn;
|
||||
|
||||
QString p = this->path();
|
||||
join(p, other.path());
|
||||
|
||||
return withNewPath(p);
|
||||
}
|
||||
|
||||
FilePath FilePath::stringAppended(const QString &str) const
|
||||
@@ -1506,7 +1498,7 @@ bool FilePath::isNewerThan(const QDateTime &timeStamp) const
|
||||
*/
|
||||
Qt::CaseSensitivity FilePath::caseSensitivity() const
|
||||
{
|
||||
if (m_scheme.isEmpty())
|
||||
if (scheme().isEmpty())
|
||||
return HostOsInfo::fileNameCaseSensitivity();
|
||||
|
||||
// FIXME: This could or possibly should the target device's file name case sensitivity
|
||||
@@ -1606,7 +1598,7 @@ void FilePath::clear()
|
||||
*/
|
||||
bool FilePath::isEmpty() const
|
||||
{
|
||||
return m_path.isEmpty();
|
||||
return m_pathLen == 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -1634,9 +1626,9 @@ QString FilePath::shortNativePath() const
|
||||
*/
|
||||
bool FilePath::isRelativePath() const
|
||||
{
|
||||
if (m_path.startsWith('/'))
|
||||
if (path().startsWith('/'))
|
||||
return false;
|
||||
if (m_path.size() > 1 && isWindowsDriveLetter(m_path[0]) && m_path.at(1) == ':')
|
||||
if (path().size() > 1 && isWindowsDriveLetter(path()[0]) && path().at(1) == ':')
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
@@ -219,9 +219,10 @@ private:
|
||||
[[nodiscard]] QString mapToDevicePath() const;
|
||||
[[nodiscard]] QString encodedHost() const;
|
||||
|
||||
QString m_scheme;
|
||||
QString m_host; // May contain raw slashes.
|
||||
QString m_path; // Includes the root bits
|
||||
QString m_data; // Concatenated m_path, m_scheme, m_host
|
||||
unsigned int m_pathLen = 0;
|
||||
unsigned short m_schemeLen = 0;
|
||||
unsigned short m_hostLen = 0;
|
||||
};
|
||||
|
||||
inline size_t qHash(const Utils::FilePath &a, uint seed = 0)
|
||||
|
@@ -498,6 +498,7 @@ void tst_fileutils::fromString_data()
|
||||
QTest::newRow("single-colon") << D(":", "", "", ":");
|
||||
QTest::newRow("single-slash") << D("/", "", "", "/");
|
||||
QTest::newRow("single-char") << D("a", "", "", "a");
|
||||
QTest::newRow("relative") << D("./rel", "", "", "./rel");
|
||||
QTest::newRow("qrc") << D(":/test.txt", "", "", ":/test.txt");
|
||||
QTest::newRow("qrc-no-slash") << D(":test.txt", "", "", ":test.txt");
|
||||
|
||||
@@ -520,6 +521,7 @@ void tst_fileutils::fromString_data()
|
||||
QTest::newRow("docker-root-url") << D("docker://1234/", "docker", "1234", "/");
|
||||
QTest::newRow("docker-root-url-special-linux") << D("/__qtc_devices__/docker/1234/", "docker", "1234", "/");
|
||||
QTest::newRow("docker-root-url-special-win") << D("c:/__qtc_devices__/docker/1234/", "docker", "1234", "/");
|
||||
QTest::newRow("docker-relative-path") << D("docker://1234/./rel", "docker", "1234", "rel");
|
||||
|
||||
QTest::newRow("qtc-dev-linux") << D("/__qtc_devices__", "", "", "/__qtc_devices__");
|
||||
QTest::newRow("qtc-dev-win") << D("c:/__qtc_devices__", "", "", "c:/__qtc_devices__");
|
||||
|
Reference in New Issue
Block a user