QDirIterator: add nextFileInfo()

Before this change, next() was the only way to advance the iterator,
whether the caller was ultimately interested in just the filePath()
(good) or not (bad luck, had to call .fileInfo()).

Add a new function, nextFileInfo(), with returns fileInfo() instead.
Incidentally, the returned object has already been constructed as part
of advance()ing the iterator, so the new function is faster than
next() even if the result is ignored, because we're not calculating a
QString result the caller may not be interested in.

Use the new function around the code.

Fix a couple of cases of next(); fileInfo().filePath() (just use
next()'s return value) as a drive-by.

[ChangeLog][QtCore][QDirIterator] Added nextFileInfo(), which is like
next(), but returns fileInfo() instead of filePath().

Change-Id: I601220575961169b44139fc55b9eae6c3197afb4
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
Marc Mutz 2021-07-11 19:28:35 +02:00
parent 8ccd5d5af2
commit 25fff849e8
20 changed files with 72 additions and 82 deletions

View File

@ -338,8 +338,7 @@ void NmakeMakefileGenerator::writeImplicitRulesPart(QTextStream &t)
for (const QString &sourceDir : qAsConst(fixifiedSourceDirs)) {
QDirIterator dit(sourceDir, sourceFilesFilter, QDir::Files | QDir::NoDotAndDotDot);
while (dit.hasNext()) {
dit.next();
const QFileInfo fi = dit.fileInfo();
const QFileInfo fi = dit.nextFileInfo();
QString &duplicate = fileNames[fi.completeBaseName()];
if (duplicate.isNull()) {
duplicate = fi.filePath();

View File

@ -341,8 +341,7 @@ static int installFileOrDirectory(const QString &source, const QString &target,
QDirIterator it(source, QDir::AllEntries | QDir::NoDotAndDotDot | QDir::Hidden);
while (it.hasNext()) {
it.next();
const QFileInfo &entry = it.fileInfo();
const QFileInfo entry = it.nextFileInfo();
const QString &entryTarget = target + QDir::separator() + entry.fileName();
const int recursionResult = installFileOrDirectory(entry.filePath(), entryTarget, true);

View File

@ -355,10 +355,8 @@ inline void QDirPrivate::initFileLists(const QDir &dir) const
if (!fileListsInitialized) {
QFileInfoList l;
QDirIterator it(dir);
while (it.hasNext()) {
it.next();
l.append(it.fileInfo());
}
while (it.hasNext())
l.append(it.nextFileInfo());
sortFileList(sort, l, &files, &fileInfos);
fileListsInitialized = true;
}
@ -1397,10 +1395,8 @@ QStringList QDir::entryList(const QStringList &nameFilters, Filters filters,
QFileInfoList l;
QDirIterator it(d->dirEntry.filePath(), nameFilters, filters);
while (it.hasNext()) {
it.next();
l.append(it.fileInfo());
}
while (it.hasNext())
l.append(it.nextFileInfo());
QStringList ret;
d->sortFileList(sort, l, &ret, nullptr);
return ret;
@ -1439,10 +1435,8 @@ QFileInfoList QDir::entryInfoList(const QStringList &nameFilters, Filters filter
QFileInfoList l;
QDirIterator it(d->dirEntry.filePath(), nameFilters, filters);
while (it.hasNext()) {
it.next();
l.append(it.fileInfo());
}
while (it.hasNext())
l.append(it.nextFileInfo());
QFileInfoList ret;
d->sortFileList(sort, l, nullptr, &ret);
return ret;
@ -1580,8 +1574,7 @@ bool QDir::removeRecursively()
// not empty -- we must empty it first
QDirIterator di(dirPath, QDir::AllEntries | QDir::Hidden | QDir::System | QDir::NoDotAndDotDot);
while (di.hasNext()) {
di.next();
const QFileInfo& fi = di.fileInfo();
const QFileInfo fi = di.nextFileInfo();
const QString &filePath = di.filePath();
bool ok;
if (fi.isDir() && !fi.isSymLink()) {

View File

@ -60,11 +60,11 @@
\snippet code/src_corelib_io_qdiriterator.cpp 1
The next() function returns the path to the next directory entry and
advances the iterator. You can also call filePath() to get the current
file path without advancing the iterator. The fileName() function returns
only the name of the file, similar to how QDir::entryList() works. You can
also call fileInfo() to get a QFileInfo for the current entry.
The next() and nextFileInfo() functions advance the iterator and return
the path or the QFileInfo of the next directory entry. You can also call
filePath() or fileInfo() to get the current file path or QFileInfo without
first advancing the iterator. The fileName() function returns only the
name of the file, similar to how QDir::entryList() works.
Unlike Qt's container iterators, QDirIterator is uni-directional (i.e.,
you cannot iterate directories in reverse order) and does not allow random
@ -490,10 +490,12 @@ QDirIterator::~QDirIterator()
new entry. If hasNext() returns \c false, this function does nothing, and
returns an empty QString.
You can call fileName() or filePath() to get the current entry file name
You can call fileName() or filePath() to get the current entry's file name
or path, or fileInfo() to get a QFileInfo for the current entry.
\sa hasNext(), fileName(), filePath(), fileInfo()
Call nextFileInfo() instead of next() if you're interested in the QFileInfo.
\sa hasNext(), nextFileInfo(), fileName(), filePath(), fileInfo()
*/
QString QDirIterator::next()
{
@ -501,11 +503,31 @@ QString QDirIterator::next()
return filePath();
}
/*!
\since 6.3
Advances the iterator to the next entry, and returns the file info of this
new entry. If hasNext() returns \c false, this function does nothing, and
returns an empty QFileInfo.
You can call fileName() or filePath() to get the current entry's file name
or path, or fileInfo() to get a QFileInfo for the current entry.
Call next() instead of nextFileInfo() when all you need is the filePath().
\sa hasNext(), fileName(), filePath(), fileInfo()
*/
QFileInfo QDirIterator::nextFileInfo()
{
d->advance();
return fileInfo();
}
/*!
Returns \c true if there is at least one more entry in the directory;
otherwise, false is returned.
\sa next(), fileName(), filePath(), fileInfo()
\sa next(), nextFileInfo(), fileName(), filePath(), fileInfo()
*/
bool QDirIterator::hasNext() const
{

View File

@ -69,6 +69,7 @@ public:
~QDirIterator();
QString next();
QFileInfo nextFileInfo();
bool hasNext() const;
QString fileName() const;

View File

@ -1694,10 +1694,8 @@ QDebug operator<<(QDebug dbg, const QFileInfo &fi)
QDirIterator it(dir);
while (it.hasNext()) {
it.next();
// Extract the QFileInfo from the iterator directly:
QFileInfo fi = it.fileInfo();
QFileInfo fi = it.nextFileInfo();
~~~
}

View File

@ -793,8 +793,7 @@ static inline QString retrieveLabel(const QByteArray &device)
QDirIterator it(QLatin1String(pathDiskByLabel), QDir::NoDotAndDotDot);
while (it.hasNext()) {
it.next();
QFileInfo fileInfo(it.fileInfo());
QFileInfo fileInfo = it.nextFileInfo();
if (fileInfo.isSymLink() && fileInfo.symLinkTarget() == devicePath)
return decodeFsEncString(fileInfo.fileName());
}

View File

@ -401,8 +401,7 @@ void QFileInfoGatherer::getFileInfos(const QString &path, const QStringList &fil
if (files.isEmpty()) {
QDirIterator dirIt(path, QDir::AllEntries | QDir::System | QDir::Hidden);
while (!abort.loadRelaxed() && dirIt.hasNext()) {
dirIt.next();
fileInfo = dirIt.fileInfo();
fileInfo = dirIt.nextFileInfo();
fileInfo.stat();
allFiles.append(fileInfo.fileName());
fetch(fileInfo, base, firstTime, updatedFiles, path);

View File

@ -522,8 +522,8 @@ qint64 QNetworkDiskCache::expire()
QMultiMap<QDateTime, QString> cacheItems;
qint64 totalSize = 0;
while (it.hasNext()) {
QString path = it.next();
QFileInfo info = it.fileInfo();
QFileInfo info = it.nextFileInfo();
QString path = info.filePath();
QString fileName = info.fileName();
if (fileName.endsWith(CACHE_POSTFIX)) {
const QDateTime birthTime = info.fileTime(QFile::FileBirthTime);

View File

@ -413,9 +413,8 @@ QList<QSslCertificate> systemCaCertificates()
currentDir.setPath(QLatin1String(directory));
QDirIterator it(currentDir);
while (it.hasNext()) {
it.next();
// use canonical path here to not load the same certificate twice if symlinked
certFiles.insert(it.fileInfo().canonicalFilePath());
certFiles.insert(it.nextFileInfo().canonicalFilePath());
}
}
for (const QString& file : qAsConst(certFiles))

View File

@ -2158,9 +2158,7 @@ QSharedPointer<QTemporaryDir> QTest::qExtractTestData(const QString &dirName)
}
while (it.hasNext()) {
it.next();
QFileInfo fileInfo = it.fileInfo();
QFileInfo fileInfo = it.nextFileInfo();
if (!fileInfo.isDir()) {
const QString destination = dataPath + QLatin1Char('/') + QStringView{fileInfo.filePath()}.mid(resourcePath.length());

View File

@ -1080,8 +1080,7 @@ bool readInputFile(Options *options)
if (QFileInfo(path).isDir()) {
QDirIterator iterator(path, QDirIterator::Subdirectories);
while (iterator.hasNext()) {
iterator.next();
if (iterator.fileInfo().isFile()) {
if (iterator.nextFileInfo().isFile()) {
QString subPath = iterator.filePath();
auto arch = fileArchitecture(*options, subPath);
if (!arch.isEmpty()) {

View File

@ -242,9 +242,7 @@ tst_QDir::tst_QDir()
QString resourceSourcePath = QStringLiteral(":/android_testdata/");
QDirIterator it(resourceSourcePath, QDirIterator::Subdirectories);
while (it.hasNext()) {
it.next();
QFileInfo fileInfo = it.fileInfo();
QFileInfo fileInfo = it.nextFileInfo();
if (!fileInfo.isDir()) {
QString destination = m_dataPath + QLatin1Char('/') + fileInfo.filePath().mid(resourceSourcePath.length());

View File

@ -127,9 +127,7 @@ void tst_QDirIterator::initTestCase()
QString resourceSourcePath = QStringLiteral(":/testdata");
QDirIterator it(resourceSourcePath, QDirIterator::Subdirectories);
while (it.hasNext()) {
it.next();
QFileInfo fileInfo = it.fileInfo();
QFileInfo fileInfo = it.nextFileInfo();
if (!fileInfo.isDir()) {
QString destination = testdata_dir + QLatin1Char('/') + fileInfo.filePath().mid(resourceSourcePath.length());
@ -467,7 +465,7 @@ void tst_QDirIterator::stopLinkLoop()
QStringList list;
int max = 200;
while (--max && it.hasNext())
it.next();
it.nextFileInfo();
QVERIFY(max);
// The goal of this test is only to ensure that the test above don't malfunction
@ -508,10 +506,8 @@ void tst_QDirIterator::engineWithNoIterator()
void tst_QDirIterator::absoluteFilePathsFromRelativeIteratorPath()
{
QDirIterator it("entrylist/", QDir::NoDotAndDotDot);
while (it.hasNext()) {
it.next();
QVERIFY(QFileInfo(it.filePath()).absoluteFilePath().contains("entrylist"));
}
while (it.hasNext())
QVERIFY(it.nextFileInfo().absoluteFilePath().contains("entrylist"));
}
void tst_QDirIterator::recurseWithFilters() const
@ -528,11 +524,9 @@ void tst_QDirIterator::recurseWithFilters() const
expectedEntries.insert(QString::fromLatin1("recursiveDirs/textFileA.txt"));
QVERIFY(it.hasNext());
it.next();
actualEntries.insert(it.fileInfo().filePath());
actualEntries.insert(it.next());
QVERIFY(it.hasNext());
it.next();
actualEntries.insert(it.fileInfo().filePath());
actualEntries.insert(it.next());
QCOMPARE(actualEntries, expectedEntries);
QVERIFY(!it.hasNext());
@ -555,7 +549,7 @@ void tst_QDirIterator::longPath()
int m = 0;
while (it.hasNext()) {
++m;
it.next();
it.nextFileInfo();
}
QCOMPARE(n, m);
@ -622,8 +616,7 @@ void tst_QDirIterator::hiddenDirs_hiddenFiles()
QDirIterator di("hiddenDirs_hiddenFiles", QDir::Files | QDir::Hidden | QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
while (di.hasNext()) {
++matches;
QString filename = di.next();
if (QFileInfo(filename).isDir())
if (di.nextFileInfo().isDir())
++failures; // search was only supposed to find files
}
QCOMPARE(matches, 6);
@ -636,8 +629,7 @@ void tst_QDirIterator::hiddenDirs_hiddenFiles()
QDirIterator di("hiddenDirs_hiddenFiles", QDir::Dirs | QDir::Hidden | QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
while (di.hasNext()) {
++matches;
QString filename = di.next();
if (!QFileInfo(filename).isDir())
if (!di.nextFileInfo().isDir())
++failures; // search was only supposed to find files
}
QCOMPARE(matches, 6);

View File

@ -77,9 +77,7 @@ void tst_QResourceEngine::initTestCase()
QDirIterator it(sourcePath, QDirIterator::Subdirectories);
while (it.hasNext()) {
it.next();
QFileInfo fileInfo = it.fileInfo();
QFileInfo fileInfo = it.nextFileInfo();
if (!fileInfo.isDir()) {
QString destination(dataPath + QLatin1Char('/') + fileInfo.filePath().mid(sourcePath.length()));
QFileInfo destinationFileInfo(destination);

View File

@ -111,9 +111,7 @@ void tst_QTemporaryFile::initTestCase()
QString sourceDir(":/android_testdata/");
QDirIterator it(sourceDir, QDirIterator::Subdirectories);
while (it.hasNext()) {
it.next();
QFileInfo sourceFileInfo = it.fileInfo();
QFileInfo sourceFileInfo = it.nextFileInfo();
if (!sourceFileInfo.isDir()) {
QFileInfo destinationFileInfo(QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QLatin1Char('/') + sourceFileInfo.filePath().mid(sourceDir.length()));

View File

@ -274,8 +274,7 @@ void tst_rcc::binary_data()
QDirIterator iter(dataPath, QStringList() << QLatin1String("*.qrc"));
while (iter.hasNext())
{
iter.next();
QFileInfo qrcFileInfo = iter.fileInfo();
QFileInfo qrcFileInfo = iter.nextFileInfo();
QString absoluteBaseName = QFileInfo(qrcFileInfo.absolutePath(), qrcFileInfo.baseName()).absoluteFilePath();
QString rccFileName = absoluteBaseName + QLatin1String(".rcc");

View File

@ -83,9 +83,9 @@ private slots:
QBENCHMARK {
QDirIterator dit(testdir.path(), QDir::Files);
while (dit.hasNext()) {
dit.next();
dit.fileInfo().isDir();
dit.fileInfo().size();
const auto fi = dit.nextFileInfo();
(void)fi.isDir();
(void)fi.size();
}
}
}
@ -104,9 +104,9 @@ private slots:
QBENCHMARK {
QDirIterator dit(testdir.path());
while (dit.hasNext()) {
dit.next();
dit.fileInfo().isDir();
dit.fileInfo().size();
const auto fi = dit.nextFileInfo();
(void)fi.isDir();
(void)fi.size();
}
}
}

View File

@ -211,9 +211,8 @@ private slots:
int count = 0;
QDirIterator iter(dirName, QDir::Files, QDirIterator::Subdirectories);
while(iter.hasNext()) {
iter.next();
count++;
totalsize += iter.fileInfo().size();
totalsize += iter.nextFileInfo().size();
}
QCOMPARE(count, 1000);
QCOMPARE(totalsize, expectedSize);

View File

@ -189,13 +189,13 @@ void tst_qdiriterator::diriterator()
QDirIterator::Subdirectories);
while (dir.hasNext()) {
dir.next();
const auto fi = dir.nextFileInfo();
//printf("%s\n", qPrintable(dir.fileName()));
0 && printf("%d %s\n",
dir.fileInfo().isDir(),
//qPrintable(dir.fileInfo().absoluteFilePath()),
fi.isDir(),
//qPrintable(fi.absoluteFilePath()),
//qPrintable(dir.path()),
qPrintable(dir.filePath()));
qPrintable(fi.filePath()));
++c;
}
count = c;