diff options
author | Marc Mutz <marc.mutz@kdab.com> | 2015-12-29 21:51:39 +0100 |
---|---|---|
committer | Marc Mutz <marc.mutz@kdab.com> | 2016-01-01 23:32:13 +0000 |
commit | be94e009ae5d89d97456f5d1389d2a017dd2e69e (patch) | |
tree | 179e13c32668bad6db0983a2a8cdb0d71f65b60a | |
parent | 024a52d0d12aaceffd67d0a1423408fb1f377d11 (diff) |
QFileDialog: optimize string handling in qt_tildeExpansion
- Instead of QString::split()-ing the path, just to inspect the
first item in the list returned, simply find the location of
the first separator and work with that.
-> saves creating a QList, and its QString elements
-> saves attempted detaches of that list when calling
first()
- When extracting the user name, don't do it in a QString, do
it in a QStringRef.
- When constructing the result, don't use QString::replace(),
use QStringBuilder with a QStringRef into the original string.
- Eradicate the out parameter, it is easily calculated from the
return value.
- Don't calculate userName on VXWORKS and INTEGRITY, where it
is not used. Requires a different #ifdef sequence. Fixed
preprocessor directives' indention as a drive-by.
Costs 84b in text size on optimized GCC 4.9 Linux AMD64 builds.
Change-Id: I61f1e8d558db7fb0c5c1170bdfd6f5ac1f1a9e62
Reviewed-by: Olivier Goffart (Woboq GmbH) <ogoffart@woboq.com>
-rw-r--r-- | src/widgets/dialogs/qfiledialog.cpp | 63 | ||||
-rw-r--r-- | tests/auto/widgets/dialogs/qfiledialog/tst_qfiledialog.cpp | 21 |
2 files changed, 43 insertions, 41 deletions
diff --git a/src/widgets/dialogs/qfiledialog.cpp b/src/widgets/dialogs/qfiledialog.cpp index 62022e6ef2..efab847c77 100644 --- a/src/widgets/dialogs/qfiledialog.cpp +++ b/src/widgets/dialogs/qfiledialog.cpp @@ -1091,46 +1091,43 @@ void QFileDialog::selectUrl(const QUrl &url) } #ifdef Q_OS_UNIX -Q_AUTOTEST_EXPORT QString qt_tildeExpansion(const QString &path, bool *expanded = 0) +Q_AUTOTEST_EXPORT QString qt_tildeExpansion(const QString &path) { - if (expanded != 0) - *expanded = false; if (!path.startsWith(QLatin1Char('~'))) return path; - QString ret = path; - QStringList tokens = ret.split(QDir::separator()); - if (tokens.first() == QLatin1String("~")) { - ret.replace(0, 1, QDir::homePath()); + int separatorPosition = path.indexOf(QDir::separator()); + if (separatorPosition < 0) + separatorPosition = path.size(); + if (separatorPosition == 1) { + return QDir::homePath() + path.midRef(1); } else { - QString userName = tokens.first(); - userName.remove(0, 1); #if defined(Q_OS_VXWORKS) || defined(Q_OS_INTEGRITY) const QString homePath = QDir::homePath(); -#elif defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD) +#else + const QByteArray userName = path.midRef(1, separatorPosition - 1).toLocal8Bit(); +# if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD) passwd pw; passwd *tmpPw; char buf[200]; const int bufSize = sizeof(buf); int err = 0; -#if defined(Q_OS_SOLARIS) && (_POSIX_C_SOURCE - 0 < 199506L) - tmpPw = getpwnam_r(userName.toLocal8Bit().constData(), &pw, buf, bufSize); -#else - err = getpwnam_r(userName.toLocal8Bit().constData(), &pw, buf, bufSize, &tmpPw); -#endif +# if defined(Q_OS_SOLARIS) && (_POSIX_C_SOURCE - 0 < 199506L) + tmpPw = getpwnam_r(userName.constData(), &pw, buf, bufSize); +# else + err = getpwnam_r(userName.constData(), &pw, buf, bufSize, &tmpPw); +# endif if (err || !tmpPw) - return ret; + return path; const QString homePath = QString::fromLocal8Bit(pw.pw_dir); -#else - passwd *pw = getpwnam(userName.toLocal8Bit().constData()); +# else + passwd *pw = getpwnam(userName.constData()); if (!pw) - return ret; + return path; const QString homePath = QString::fromLocal8Bit(pw->pw_dir); +# endif #endif - ret.replace(0, tokens.first().length(), homePath); + return homePath + path.midRef(separatorPosition); } - if (expanded != 0) - *expanded = true; - return ret; } #endif @@ -4044,15 +4041,17 @@ QStringList QFSCompleter::splitPath(const QString &path) const else doubleSlash.clear(); #elif defined(Q_OS_UNIX) - bool expanded; - pathCopy = qt_tildeExpansion(pathCopy, &expanded); - if (expanded) { - QFileSystemModel *dirModel; - if (proxyModel) - dirModel = qobject_cast<QFileSystemModel *>(proxyModel->sourceModel()); - else - dirModel = sourceModel; - dirModel->fetchMore(dirModel->index(pathCopy)); + { + QString tildeExpanded = qt_tildeExpansion(pathCopy); + if (tildeExpanded != pathCopy) { + QFileSystemModel *dirModel; + if (proxyModel) + dirModel = qobject_cast<QFileSystemModel *>(proxyModel->sourceModel()); + else + dirModel = sourceModel; + dirModel->fetchMore(dirModel->index(tildeExpanded)); + } + pathCopy = std::move(tildeExpanded); } #endif diff --git a/tests/auto/widgets/dialogs/qfiledialog/tst_qfiledialog.cpp b/tests/auto/widgets/dialogs/qfiledialog/tst_qfiledialog.cpp index 2ab9ca330f..c9de1c54c0 100644 --- a/tests/auto/widgets/dialogs/qfiledialog/tst_qfiledialog.cpp +++ b/tests/auto/widgets/dialogs/qfiledialog/tst_qfiledialog.cpp @@ -68,7 +68,7 @@ #include <unistd.h> // for pathconf() on OS X #ifdef QT_BUILD_INTERNAL QT_BEGIN_NAMESPACE -extern Q_GUI_EXPORT QString qt_tildeExpansion(const QString &path, bool *expanded = 0); +extern Q_GUI_EXPORT QString qt_tildeExpansion(const QString &path); QT_END_NAMESPACE #endif #endif @@ -1395,15 +1395,18 @@ void tst_QFiledialog::tildeExpansion_data() QTest::addColumn<QString>("tildePath"); QTest::addColumn<QString>("expandedPath"); + const QString tilde = QStringLiteral("~"); + const QString tildeUser = tilde + QString(qgetenv("USER")); + const QLatin1String someSubDir("/some/sub/dir"); + const QString homePath = QDir::homePath(); + const QString invalid = QStringLiteral("~thisIsNotAValidUserName"); + QTest::newRow("empty path") << QString() << QString(); - QTest::newRow("~") << QString::fromLatin1("~") << QDir::homePath(); - QTest::newRow("~/some/sub/dir/") << QString::fromLatin1("~/some/sub/dir") << QDir::homePath() - + QString::fromLatin1("/some/sub/dir"); - QString userHome = QString(qgetenv("USER")); - userHome.prepend('~'); - QTest::newRow("current user (~<user> syntax)") << userHome << QDir::homePath(); - QString invalid = QString::fromLatin1("~thisIsNotAValidUserName"); - QTest::newRow("invalid user name") << invalid << invalid; + QTest::newRow("~") << tilde << homePath; + QTest::newRow("~/some/sub/dir/") << tilde + someSubDir << homePath + someSubDir; + QTest::newRow("~<user>") << tildeUser << homePath; + QTest::newRow("~<user>/some/sub/dir") << tildeUser + someSubDir << homePath + someSubDir; + QTest::newRow("invalid user name") << invalid << invalid; } #endif // QT_BUILD_INTERNAL |