summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAhmad Samir <a.samirh78@gmail.com>2024-01-30 15:22:30 +0200
committerAhmad Samir <a.samirh78@gmail.com>2024-02-29 16:35:57 +0200
commitc39a0d1e8956e042139ce3065681e4c5d07412f3 (patch)
treeee38f631e5bd345cdbd634bd31a1a575bf461159
parent78c33a77414585b39c2c3fa14d1c88d6af7c03f1 (diff)
Add QDirListing, an STL-style iterator for directory entries
This class offers a forward-only const_iterator, that matches the system low-level functions' logic (e.g. readdir()/dirstream logic). This iterator is a std::input_iterator_tag. QDirIterator uses Java-style iterators that have a couple of issues: - They don't fit the logic of the underlying native system functions (readdir()/__dirstream and co.), there is no way to know if there is a next entry except by advancing the iterator (calling readdir()) first - As a consequence of the above, two QFileInfo objects, current and next, had to be used to fit that paradigm; and the code always iterated/stat'ed an extra entry past the one we want, e.g. when filtering The next step is porting QAbstractFileEngineIterator and its subclasses to be like QFileSystemIterator, i.e. replace hasNext()/next() with a `bool advance()` virtual method. This is easier to reason about than the Java-style iterators, and is more in-line with the new class. Discussed-on: https://lists.qt-project.org/pipermail/development/2023-December/044745.html Change-Id: I8e696cefdca18d8c78f803efdb83a73dd43eb720 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
-rw-r--r--src/corelib/CMakeLists.txt1
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_io_qdirlisting.cpp58
-rw-r--r--src/corelib/io/qabstractfileengine_p.h1
-rw-r--r--src/corelib/io/qdir.h1
-rw-r--r--src/corelib/io/qdirentryinfo_p.h156
-rw-r--r--src/corelib/io/qdirlisting.cpp515
-rw-r--r--src/corelib/io/qdirlisting.h122
-rw-r--r--src/corelib/io/qfileinfo.h1
-rw-r--r--tests/auto/corelib/io/CMakeLists.txt1
-rw-r--r--tests/auto/corelib/io/qdirlisting/.gitignore1
-rw-r--r--tests/auto/corelib/io/qdirlisting/CMakeLists.txt17
-rw-r--r--tests/auto/corelib/io/qdirlisting/tst_qdirlisting.cpp216
12 files changed, 715 insertions, 375 deletions
diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt
index 10c21a6e77..b2b80e1fca 100644
--- a/src/corelib/CMakeLists.txt
+++ b/src/corelib/CMakeLists.txt
@@ -116,6 +116,7 @@ qt_internal_add_module(Core
io/qdataurl.cpp io/qdataurl_p.h
io/qdebug.cpp io/qdebug.h io/qdebug_p.h
io/qdir.cpp io/qdir.h io/qdir_p.h
+ io/qdirlisting.cpp io/qdirlisting.h io/qdirentryinfo_p.h
io/qdiriterator.cpp io/qdiriterator.h
io/qfile.cpp io/qfile.h io/qfile_p.h
io/qfiledevice.cpp io/qfiledevice.h io/qfiledevice_p.h
diff --git a/src/corelib/doc/snippets/code/src_corelib_io_qdirlisting.cpp b/src/corelib/doc/snippets/code/src_corelib_io_qdirlisting.cpp
index ec3f3adc50..231bf48d26 100644
--- a/src/corelib/doc/snippets/code/src_corelib_io_qdirlisting.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_io_qdirlisting.cpp
@@ -1,11 +1,16 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+#include <QDirListing>
+
+using namespace Qt::StringLiterals;
+
+[[maybe_unused]] static void func() {
+{
//! [0]
-QDirIterator it("/etc", QDirIterator::Subdirectories);
-while (it.hasNext()) {
- QString dir = it.next();
- qDebug() << dir;
+using ItFlag = QDirListing::IteratorFlag;
+for (const auto &dirEntry : QDirListing(u"/etc"_s, ItFlag::Recursive)) {
+ qDebug() << dirEntry.filePath();
// /etc/.
// /etc/..
// /etc/X11
@@ -13,16 +18,53 @@ while (it.hasNext()) {
// ...
}
//! [0]
+}
+{
//! [1]
-QDirIterator it("/sys", QStringList() << "scaling_cur_freq", QDir::NoFilter, QDirIterator::Subdirectories);
-while (it.hasNext()) {
- QFile f(it.next());
+using ItFlag = QDirListing::IteratorFlag;
+QDirListing dirList(u"/sys"_s, QStringList{u"scaling_cur_freq"_s},
+ QDir::NoFilter, ItFlag::Recursive);
+for (const auto &dirEntry : dirList) {
+ QFile f(dirEntry.filePath());
f.open(QIODevice::ReadOnly);
qDebug() << f.fileName() << f.readAll().trimmed().toDouble() / 1000 << "MHz";
}
//! [1]
+}
+{
//! [2]
-QDirIterator audioFileIt(audioPath, {"*.mp3", "*.wav"}, QDir::Files);
+QDirListing audioFileIt(u"/home/johndoe/"_s, {"*.mp3", "*.wav"}, QDir::Files);
//! [2]
+}
+
+{
+//! [3]
+using ItFlag = QDirListing::IteratorFlag;
+for (const auto &dirEntry : QDirListing(u"/etc"_s, ItFlag::Recursive)) {
+ // Faster
+ if (dirEntry.fileName().endsWith(u".conf")) { /* ... */ }
+
+ // This works, but might be potentially slower, since it has to construct a
+ // QFileInfo, whereas (depending on the implemnetation) the fileName could
+ // be known already
+ if (dirEntry.fileInfo().fileName().endsWith(u".conf")) { /* ... */ }
+}
+//! [3]
+}
+
+{
+//! [4]
+using ItFlag = QDirListing::IteratorFlag;
+for (const auto &dirEntry : QDirListing(u"/etc"_s, ItFlag::Recursive)) {
+ // Both approaches are the same, because DirEntry will have to construct
+ // a QFileInfo to get this info (for example, by calling system stat())
+
+ if (dirEntry.size() >= 4'000 /* 4KB */) { /* ...*/ }
+ if (dirEntry.fileInfo().size() >= 4'000 /* 4KB */) { /* ... */ }
+}
+//! [4]
+}
+
+}
diff --git a/src/corelib/io/qabstractfileengine_p.h b/src/corelib/io/qabstractfileengine_p.h
index 28f07bf8f9..9b4d9eab63 100644
--- a/src/corelib/io/qabstractfileengine_p.h
+++ b/src/corelib/io/qabstractfileengine_p.h
@@ -218,6 +218,7 @@ private:
Q_DISABLE_COPY_MOVE(QAbstractFileEngineIterator)
friend class QDirIterator;
friend class QDirIteratorPrivate;
+ friend class QDirListingPrivate;
void setPath(const QString &path);
QScopedPointer<QAbstractFileEngineIteratorPrivate> d;
};
diff --git a/src/corelib/io/qdir.h b/src/corelib/io/qdir.h
index 92871062c8..53c0900f95 100644
--- a/src/corelib/io/qdir.h
+++ b/src/corelib/io/qdir.h
@@ -243,6 +243,7 @@ private:
friend Q_CORE_EXPORT bool comparesEqual(const QDir &lhs, const QDir &rhs);
Q_DECLARE_EQUALITY_COMPARABLE(QDir)
friend class QDirIterator;
+ friend class QDirListing;
// Q_DECLARE_PRIVATE equivalent for shared data pointers
QDirPrivate *d_func();
const QDirPrivate *d_func() const { return d_ptr.constData(); }
diff --git a/src/corelib/io/qdirentryinfo_p.h b/src/corelib/io/qdirentryinfo_p.h
new file mode 100644
index 0000000000..7ed5391ff0
--- /dev/null
+++ b/src/corelib/io/qdirentryinfo_p.h
@@ -0,0 +1,156 @@
+// Copyright (C) 2024 Ahmad Samir <a.samirh78@gmail.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QDIRENTRYINFO_P_H
+#define QDIRENTRYINFO_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/private/qfileinfo_p.h>
+#include <QtCore/private/qfilesystementry_p.h>
+#include <QtCore/private/qfilesystemmetadata_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDirEntryInfo
+{
+ const QFileSystemMetaData &ensureFilled(QFileSystemMetaData::MetaDataFlags what)
+ {
+ if (!metaData.hasFlags(what))
+ QFileSystemEngine::fillMetaData(entry, metaData, what);
+ return metaData;
+ }
+
+public:
+ const QFileInfo &fileInfo()
+ {
+ if (!fileInfoOpt) {
+ fileInfoOpt.emplace(new QFileInfoPrivate(entry, metaData));
+ metaData.clear();
+ }
+ return *fileInfoOpt;
+ }
+
+ QString fileName()
+ { return fileInfoOpt ? fileInfoOpt->fileName() : entry.fileName(); }
+ QString baseName()
+ { return fileInfoOpt ? fileInfoOpt->baseName() : entry.baseName(); }
+ QString completeBaseName() const
+ { return fileInfoOpt ? fileInfoOpt->completeBaseName() : entry.completeBaseName(); }
+ QString suffix() const
+ { return fileInfoOpt ? fileInfoOpt->suffix() : entry.suffix(); }
+ QString completeSuffix() const
+ { return fileInfoOpt ? fileInfoOpt->completeSuffix() : entry.completeSuffix(); }
+ QString filePath()
+ { return fileInfoOpt ? fileInfoOpt->filePath() : entry.filePath(); }
+
+ QString bundleName() { return fileInfo().bundleName(); }
+
+ QString canonicalFilePath()
+ {
+ // QFileInfo caches these strings
+ return fileInfo().canonicalFilePath();
+ }
+
+ QString absoluteFilePath() {
+ // QFileInfo caches these strings
+ return fileInfo().absoluteFilePath();
+ }
+
+ QString absolutePath() {
+ // QFileInfo caches these strings
+ return fileInfo().absolutePath();
+ }
+
+
+ bool isDir() {
+ if (fileInfoOpt)
+ return fileInfoOpt->isDir();
+
+ return ensureFilled(QFileSystemMetaData::DirectoryType).isDirectory();
+ }
+
+ bool isFile() {
+ if (fileInfoOpt)
+ return fileInfoOpt->isFile();
+
+ return ensureFilled(QFileSystemMetaData::FileType).isFile();
+ }
+
+ bool isSymLink() {
+ if (fileInfoOpt)
+ return fileInfoOpt->isSymLink();
+
+ return ensureFilled(QFileSystemMetaData::LegacyLinkType).isLegacyLink();
+ }
+
+ bool isSymbolicLink() {
+ if (fileInfoOpt)
+ return fileInfoOpt->isSymbolicLink();
+
+ return ensureFilled(QFileSystemMetaData::LinkType).isLink();
+ }
+
+ bool exists() {
+ if (fileInfoOpt)
+ return fileInfoOpt->exists();
+
+ return ensureFilled(QFileSystemMetaData::ExistsAttribute).exists();
+ }
+
+ bool isHidden() {
+ if (fileInfoOpt)
+ return fileInfoOpt->isHidden();
+
+ return ensureFilled(QFileSystemMetaData::HiddenAttribute).isHidden();
+ }
+
+ bool isReadable() {
+ if (fileInfoOpt)
+ return fileInfoOpt->isReadable();
+
+ return ensureFilled(QFileSystemMetaData::UserReadPermission).isReadable();
+ }
+
+ bool isWritable() {
+ if (fileInfoOpt)
+ return fileInfoOpt->isWritable();
+
+ return ensureFilled(QFileSystemMetaData::UserWritePermission).isWritable();
+ }
+
+ bool isExecutable() {
+ if (fileInfoOpt)
+ return fileInfoOpt->isExecutable();
+
+ return ensureFilled(QFileSystemMetaData::UserExecutePermission).isExecutable();
+ }
+
+ qint64 size() { return fileInfo().size(); }
+
+ QDateTime fileTime(QFile::FileTime type, const QTimeZone &tz)
+ {
+ return fileInfo().fileTime(type, tz);
+ }
+
+private:
+ friend class QDirListingPrivate;
+ friend class QDirListing;
+
+ QFileSystemEntry entry;
+ QFileSystemMetaData metaData;
+ std::optional<QFileInfo> fileInfoOpt;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDIRENTRYINFO_P_H
diff --git a/src/corelib/io/qdirlisting.cpp b/src/corelib/io/qdirlisting.cpp
index aa725d03dd..f0eb2c4559 100644
--- a/src/corelib/io/qdirlisting.cpp
+++ b/src/corelib/io/qdirlisting.cpp
@@ -1,65 +1,73 @@
// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2024 Ahmad Samir <a.samirh78@gmail.com>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
/*!
- \since 4.3
- \class QDirIterator
+ \since 6.8
+ \class QDirListing
\inmodule QtCore
- \brief The QDirIterator class provides an iterator for directory entrylists.
+ \brief The QDirListing class provides an STL-style iterator for directory entries.
- You can use QDirIterator to navigate entries of a directory one at a time.
+ You can use QDirListing to navigate entries of a directory one at a time.
It is similar to QDir::entryList() and QDir::entryInfoList(), but because
it lists entries one at a time instead of all at once, it scales better
and is more suitable for large directories. It also supports listing
directory contents recursively, and following symbolic links. Unlike
- QDir::entryList(), QDirIterator does not support sorting.
+ QDir::entryList(), QDirListing does not support sorting.
- The QDirIterator constructor takes a QDir or a directory as
- argument. After construction, the iterator is located before the first
- directory entry. Here's how to iterate over all the entries sequentially:
+ The QDirListing constructor takes a QDir or a directory path as
+ argument. Here's how to iterate over all entries recursively:
- \snippet code/src_corelib_io_qdiriterator.cpp 0
+ \snippet code/src_corelib_io_qdirlisting.cpp 0
Here's how to find and read all files filtered by name, recursively:
- \snippet code/src_corelib_io_qdiriterator.cpp 1
+ \snippet code/src_corelib_io_qdirlisting.cpp 1
- 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.
+ Iterators constructed by QDirListing (QDirListing::const_iterator) are
+ forward-only (you cannot iterate directories in reverse order) and don't
+ allow random access. They can be used in ranged-for loops (or with STL
+ alogrithms that don't require random access iterators). Dereferencing
+ a valid iterator returns a QDirListing::DirEntry object. The (c)end()
+ iterator marks the end of the iteration. Dereferencing the end iterator
+ is undefiend behavior.
- Unlike Qt's container iterators, QDirIterator is uni-directional (i.e.,
- you cannot iterate directories in reverse order) and does not allow random
- access.
+ QDirListing::DirEntry offers a subset of QFileInfo's API (for example,
+ fileName(), filePath(), exists()). Internally, DirEntry only constructs
+ a QFileInfo object if needed, that is, if the info hasn't been already
+ fetched by other system functions. You can use DirEntry::fileInfo()
+ to get a QFileInfo. For example:
+
+ \snippet code/src_corelib_io_qdirlisting.cpp 3
+ \snippet code/src_corelib_io_qdirlisting.cpp 4
\sa QDir, QDir::entryList()
*/
-/*! \enum QDirIterator::IteratorFlag
+/*! \enum QDirListing::IteratorFlag
- This enum describes flags that you can combine to configure the behavior
- of QDirIterator.
+ This enum class describes flags can be used to configure the behavior of
+ QDirListing. These flags can be bitwise OR'ed together.
- \value NoIteratorFlags The default value, representing no flags. The
- iterator will return entries for the assigned path.
+ \value NoFlag The default value, representing no flags. The iterator
+ will return entries for the assigned path.
- \value Subdirectories List entries inside all subdirectories as well.
+ \value FollowSymlinks When combined with Recursive, this flag enables
+ iterating through all subdirectories of the assigned path, following
+ all symbolic links. Symbolic link loops (e.g., link => . or link =>
+ ..) are automatically detected and ignored.
- \value FollowSymlinks When combined with Subdirectories, this flag
- enables iterating through all subdirectories of the assigned path,
- following all symbolic links. Symbolic link loops (e.g., "link" => "." or
- "link" => "..") are automatically detected and ignored.
+ \value Recursive List entries inside all subdirectories as well.
*/
-#include "qdiriterator.h"
+#include "qdirlisting.h"
+#include "qdirentryinfo_p.h"
+
#include "qdir_p.h"
#include "qabstractfileengine_p.h"
#include <QtCore/qset.h>
-#include <QtCore/qstack.h>
-#include <QtCore/qvariant.h>
+
#if QT_CONFIG(regularexpression)
#include <QtCore/qregularexpression.h>
#endif
@@ -79,23 +87,26 @@ QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
-class QDirIteratorPrivate
+class QDirListingPrivate
{
public:
void init(bool resolveEngine);
void advance();
- bool entryMatches(const QString & fileName, const QFileInfo &fileInfo);
- void pushDirectory(const QFileInfo &fileInfo);
- void checkAndPushDirectory(const QFileInfo &);
- bool matchesFilters(const QString &fileName, const QFileInfo &fi) const;
+ bool entryMatches(QDirEntryInfo &info);
+ void pushDirectory(QDirEntryInfo &info);
+ void pushInitialDirectory();
- std::unique_ptr<QAbstractFileEngine> engine;
+ void checkAndPushDirectory(QDirEntryInfo &info);
+ bool matchesFilters(QDirEntryInfo &data) const;
+ bool hasIterators() const;
- QFileSystemEntry dirEntry;
+ std::unique_ptr<QAbstractFileEngine> engine;
+ QDirEntryInfo initialEntryInfo;
QStringList nameFilters;
QDir::Filters filters;
- QDirIterator::IteratorFlags iteratorFlags;
+ QDirListing::IteratorFlags iteratorFlags;
+ QDirEntryInfo currentEntryInfo;
#if QT_CONFIG(regularexpression)
QList<QRegularExpression> nameRegExps;
@@ -108,14 +119,11 @@ public:
std::stack<FsIteratorPtr, std::vector<FsIteratorPtr>> nativeIterators;
#endif
- QFileInfo currentFileInfo;
- QFileInfo nextFileInfo;
-
// Loop protection
QDuplicateTracker<QString> visitedLinks;
};
-void QDirIteratorPrivate::init(bool resolveEngine = true)
+void QDirListingPrivate::init(bool resolveEngine = true)
{
if (nameFilters.contains("*"_L1))
nameFilters.clear();
@@ -131,31 +139,26 @@ void QDirIteratorPrivate::init(bool resolveEngine = true)
nameRegExps.append(re);
}
#endif
- QFileSystemMetaData metaData;
+
if (resolveEngine)
- engine.reset(QFileSystemEngine::resolveEntryAndCreateLegacyEngine(dirEntry, metaData));
- QFileInfo fileInfo(new QFileInfoPrivate(dirEntry, metaData));
+ engine.reset(QFileSystemEngine::resolveEntryAndCreateLegacyEngine(
+ initialEntryInfo.entry, initialEntryInfo.metaData));
- // Populate fields for hasNext() and next()
- pushDirectory(fileInfo);
- advance();
+ pushDirectory(initialEntryInfo);
}
-/*!
- \internal
-*/
-void QDirIteratorPrivate::pushDirectory(const QFileInfo &fileInfo)
+void QDirListingPrivate::pushDirectory(QDirEntryInfo &entryInfo)
{
- QString path = fileInfo.filePath();
+ QString path = entryInfo.filePath();
#ifdef Q_OS_WIN
- if (fileInfo.isSymLink())
- path = fileInfo.canonicalFilePath();
+ if (entryInfo.isSymLink())
+ path = entryInfo.canonicalFilePath();
#endif
- if ((iteratorFlags & QDirIterator::FollowSymlinks)) {
+ if (iteratorFlags.testAnyFlags(QDirListing::IteratorFlag::FollowSymlinks)) {
// Stop link loops
- if (visitedLinks.hasSeen(fileInfo.canonicalFilePath()))
+ if (visitedLinks.hasSeen(entryInfo.canonicalFilePath()))
return;
}
@@ -170,27 +173,22 @@ void QDirIteratorPrivate::pushDirectory(const QFileInfo &fileInfo)
}
} else {
#ifndef QT_NO_FILESYSTEMITERATOR
- nativeIterators.emplace(std::make_unique<QFileSystemIterator>(
- fileInfo.d_ptr->fileEntry, filters));
+ QFileSystemEntry *fentry = nullptr;
+ if (entryInfo.fileInfoOpt)
+ fentry = &entryInfo.fileInfoOpt->d_ptr->fileEntry;
+ else
+ fentry = &entryInfo.entry;
+ nativeIterators.emplace(std::make_unique<QFileSystemIterator>(*fentry, filters));
#else
qWarning("Qt was built with -no-feature-filesystemiterator: no files/plugins will be found!");
#endif
}
}
-inline bool QDirIteratorPrivate::entryMatches(const QString & fileName, const QFileInfo &fileInfo)
+bool QDirListingPrivate::entryMatches(QDirEntryInfo &entryInfo)
{
- checkAndPushDirectory(fileInfo);
-
- if (matchesFilters(fileName, fileInfo)) {
- currentFileInfo = nextFileInfo;
- nextFileInfo = fileInfo;
-
- //We found a matching entry.
- return true;
- }
-
- return false;
+ checkAndPushDirectory(entryInfo);
+ return matchesFilters(entryInfo);
}
/*!
@@ -208,7 +206,7 @@ inline bool QDirIteratorPrivate::entryMatches(const QString & fileName, const QF
- B's iterator is processed (the top() of the stack) first; then loop
goes back to processing A's iterator
*/
-void QDirIteratorPrivate::advance()
+void QDirListingPrivate::advance()
{
// Use get() in both code paths below because the iterator returned by top()
// may be invalidated due to reallocation when appending new iterators in
@@ -220,79 +218,73 @@ void QDirIteratorPrivate::advance()
QAbstractFileEngineIterator *it;
while (it = fileEngineIterators.top().get(), it->hasNext()) {
it->next();
- if (entryMatches(it->currentFileName(), it->currentFileInfo()))
+ QDirEntryInfo entryInfo;
+ entryInfo.fileInfoOpt = it->currentFileInfo();
+ if (entryMatches(entryInfo)) {
+ currentEntryInfo = std::move(entryInfo);
return;
+ }
}
fileEngineIterators.pop();
}
} else {
#ifndef QT_NO_FILESYSTEMITERATOR
- QFileSystemEntry nextEntry;
- QFileSystemMetaData nextMetaData;
-
+ QDirEntryInfo entryInfo;
while (!nativeIterators.empty()) {
// Find the next valid iterator that matches the filters.
QFileSystemIterator *it;
- while (it = nativeIterators.top().get(), it->advance(nextEntry, nextMetaData)) {
- QFileInfo info(new QFileInfoPrivate(nextEntry, nextMetaData));
-
- if (entryMatches(nextEntry.fileName(), info))
+ while (it = nativeIterators.top().get(), it->advance(entryInfo.entry, entryInfo.metaData)) {
+ if (entryMatches(entryInfo)) {
+ currentEntryInfo = std::move(entryInfo);
return;
- nextMetaData = QFileSystemMetaData();
+ }
+ entryInfo = {};
}
nativeIterators.pop();
}
#endif
}
-
- currentFileInfo = nextFileInfo;
- nextFileInfo = QFileInfo();
}
-/*!
- \internal
- */
-void QDirIteratorPrivate::checkAndPushDirectory(const QFileInfo &fileInfo)
+void QDirListingPrivate::checkAndPushDirectory(QDirEntryInfo &entryInfo)
{
+ using F = QDirListing::IteratorFlag;
// If we're doing flat iteration, we're done.
- if (!(iteratorFlags & QDirIterator::Subdirectories))
+ if (!iteratorFlags.testAnyFlags(F::Recursive))
return;
// Never follow non-directory entries
- if (!fileInfo.isDir())
+ if (!entryInfo.isDir())
return;
// Follow symlinks only when asked
- if (!(iteratorFlags & QDirIterator::FollowSymlinks) && fileInfo.isSymLink())
+ if (!iteratorFlags.testAnyFlags(F::FollowSymlinks) && entryInfo.isSymLink())
return;
// Never follow . and ..
- QString fileName = fileInfo.fileName();
+ const QString &fileName = entryInfo.fileName();
if ("."_L1 == fileName || ".."_L1 == fileName)
return;
// No hidden directories unless requested
- if (!(filters & QDir::AllDirs) && !(filters & QDir::Hidden) && fileInfo.isHidden())
+ if (!filters.testAnyFlags(QDir::AllDirs | QDir::Hidden) && entryInfo.isHidden())
return;
- pushDirectory(fileInfo);
+ pushDirectory(entryInfo);
}
/*!
\internal
- This convenience function implements the iterator's filtering logics and
- applies then to the current directory entry.
-
- It returns \c true if the current entry matches the filters (i.e., the
- current entry will be returned as part of the directory iteration);
- otherwise, false is returned.
+ This functions returns \c true if the current entry matches the filters
+ (i.e., the current entry will be returned as part of the directory
+ iteration); otherwise, \c false is returned.
*/
-
-bool QDirIteratorPrivate::matchesFilters(const QString &fileName, const QFileInfo &fi) const
+bool QDirListingPrivate::matchesFilters(QDirEntryInfo &entryInfo) const
{
+ const QString &fileName = entryInfo.fileName();
if (fileName.isEmpty())
return false;
@@ -309,7 +301,7 @@ bool QDirIteratorPrivate::matchesFilters(const QString &fileName, const QFileInf
// name filter
#if QT_CONFIG(regularexpression)
// Pass all entries through name filters, except dirs if the AllDirs
- if (!nameFilters.isEmpty() && !((filters & QDir::AllDirs) && fi.isDir())) {
+ if (!nameFilters.isEmpty() && !(filters.testAnyFlags(QDir::AllDirs) && entryInfo.isDir())) {
bool matched = false;
for (const auto &re : nameRegExps) {
if (re.match(fileName).hasMatch()) {
@@ -324,30 +316,30 @@ bool QDirIteratorPrivate::matchesFilters(const QString &fileName, const QFileInf
// skip symlinks
const bool skipSymlinks = filters.testAnyFlag(QDir::NoSymLinks);
const bool includeSystem = filters.testAnyFlag(QDir::System);
- if (skipSymlinks && fi.isSymLink()) {
+ if (skipSymlinks && entryInfo.isSymLink()) {
// The only reason to save this file is if it is a broken link and we are requesting system files.
- if (!includeSystem || fi.exists())
+ if (!includeSystem || entryInfo.exists())
return false;
}
// filter hidden
const bool includeHidden = filters.testAnyFlag(QDir::Hidden);
- if (!includeHidden && !dotOrDotDot && fi.isHidden())
+ if (!includeHidden && !dotOrDotDot && entryInfo.isHidden())
return false;
// filter system files
- if (!includeSystem && (!(fi.isFile() || fi.isDir() || fi.isSymLink())
- || (!fi.exists() && fi.isSymLink())))
+ if (!includeSystem && (!(entryInfo.isFile() || entryInfo.isDir() || entryInfo.isSymLink())
+ || (!entryInfo.exists() && entryInfo.isSymLink())))
return false;
// skip directories
const bool skipDirs = !(filters & (QDir::Dirs | QDir::AllDirs));
- if (skipDirs && fi.isDir())
+ if (skipDirs && entryInfo.isDir())
return false;
// skip files
const bool skipFiles = !(filters & QDir::Files);
- if (skipFiles && fi.isFile())
+ if (skipFiles && entryInfo.isFile())
// Basically we need a reason not to exclude this file otherwise we just eliminate it.
return false;
@@ -358,35 +350,47 @@ bool QDirIteratorPrivate::matchesFilters(const QString &fileName, const QFileInf
const bool doExecutable = !filterPermissions || (filters & QDir::Executable);
const bool doReadable = !filterPermissions || (filters & QDir::Readable);
if (filterPermissions
- && ((doReadable && !fi.isReadable())
- || (doWritable && !fi.isWritable())
- || (doExecutable && !fi.isExecutable()))) {
+ && ((doReadable && !entryInfo.isReadable())
+ || (doWritable && !entryInfo.isWritable())
+ || (doExecutable && !entryInfo.isExecutable()))) {
return false;
}
return true;
}
+bool QDirListingPrivate::hasIterators() const
+{
+ if (engine)
+ return !fileEngineIterators.empty();
+
+#if !defined(QT_NO_FILESYSTEMITERATOR)
+ return !nativeIterators.empty();
+#endif
+
+ return false;
+}
+
/*!
- Constructs a QDirIterator that can iterate over \a dir's entrylist, using
- \a dir's name filters and regular filters. You can pass options via \a
- flags to decide how the directory should be iterated.
+ Constructs a QDirListing that can iterate over \a dir's entries, using
+ \a dir's name filters and the QDir::Filters set in \a dir. You can pass
+ options via \a flags to decide how the directory should be iterated.
By default, \a flags is NoIteratorFlags, which provides the same behavior
as in QDir::entryList().
The sorting in \a dir is ignored.
- \note To list symlinks that point to non existing files, QDir::System must be
- passed to the flags.
+ \note To list symlinks that point to non existing files, QDir::System
+ must be set in \a dir's QDir::Filters.
\sa hasNext(), next(), IteratorFlags
*/
-QDirIterator::QDirIterator(const QDir &dir, IteratorFlags flags)
- : d(new QDirIteratorPrivate)
+QDirListing::QDirListing(const QDir &dir, IteratorFlags flags)
+ : d(new QDirListingPrivate)
{
const QDirPrivate *other = dir.d_ptr.constData();
- d->dirEntry = other->dirEntry;
+ d->initialEntryInfo.entry = other->dirEntry;
d->nameFilters = other->nameFilters;
d->filters = other->filters;
d->iteratorFlags = flags;
@@ -395,50 +399,47 @@ QDirIterator::QDirIterator(const QDir &dir, IteratorFlags flags)
}
/*!
- Constructs a QDirIterator that can iterate over \a path, with no name
- filtering and \a filters for entry filtering. You can pass options via \a
- flags to decide how the directory should be iterated.
+ Constructs a QDirListing that can iterate over \a path. Entries are
+ filtered according to \a filters. You can pass options via \a flags to
+ decide how the directory should be iterated.
By default, \a filters is QDir::NoFilter, and \a flags is NoIteratorFlags,
which provides the same behavior as in QDir::entryList().
- \note To list symlinks that point to non existing files, QDir::System must be
- passed to the flags.
+ \note To list symlinks that point to non existing files, QDir::System
+ must be set in \a filters.
\sa hasNext(), next(), IteratorFlags
*/
-QDirIterator::QDirIterator(const QString &path, QDir::Filters filters, IteratorFlags flags)
- : d(new QDirIteratorPrivate)
+QDirListing::QDirListing(const QString &path, QDir::Filters filters, IteratorFlags flags)
+ : d(new QDirListingPrivate)
{
- d->dirEntry = QFileSystemEntry(path);
+ d->initialEntryInfo.entry = QFileSystemEntry(path);
d->filters = filters;
d->iteratorFlags = flags;
d->init();
}
/*!
- Constructs a QDirIterator that can iterate over \a path. You can pass
+ Constructs a QDirListing that can iterate over \a path. You can pass
options via \a flags to decide how the directory should be iterated.
By default, \a flags is NoIteratorFlags, which provides the same behavior
as in QDir::entryList().
- \note To list symlinks that point to non existing files, QDir::System must be
- passed to the flags.
-
\sa hasNext(), next(), IteratorFlags
*/
-QDirIterator::QDirIterator(const QString &path, IteratorFlags flags)
- : d(new QDirIteratorPrivate)
+QDirListing::QDirListing(const QString &path, IteratorFlags flags)
+ : d(new QDirListingPrivate)
{
- d->dirEntry = QFileSystemEntry(path);
+ d->initialEntryInfo.entry = QFileSystemEntry(path);
d->filters = QDir::NoFilter;
d->iteratorFlags = flags;
d->init();
}
/*!
- Constructs a QDirIterator that can iterate over \a path, using \a
+ Constructs a QDirListing that can iterate over \a path, using \a
nameFilters and \a filters. You can pass options via \a flags to decide
how the directory should be iterated.
@@ -448,18 +449,18 @@ QDirIterator::QDirIterator(const QString &path, IteratorFlags flags)
For example, the following iterator could be used to iterate over audio
files:
- \snippet code/src_corelib_io_qdiriterator.cpp 2
+ \snippet code/src_corelib_io_qdirlisting.cpp 2
- \note To list symlinks that point to non existing files, QDir::System must be
- passed to the flags.
+ \note To list symlinks that point to non existing files, QDir::System
+ must be set in \a flags.
\sa hasNext(), next(), IteratorFlags, QDir::setNameFilters()
*/
-QDirIterator::QDirIterator(const QString &path, const QStringList &nameFilters,
- QDir::Filters filters, IteratorFlags flags)
- : d(new QDirIteratorPrivate)
+QDirListing::QDirListing(const QString &path, const QStringList &nameFilters, QDir::Filters filters,
+ IteratorFlags flags)
+ : d(new QDirListingPrivate)
{
- d->dirEntry = QFileSystemEntry(path);
+ d->initialEntryInfo.entry = QFileSystemEntry(path);
d->nameFilters = nameFilters;
d->filters = filters;
d->iteratorFlags = flags;
@@ -467,109 +468,207 @@ QDirIterator::QDirIterator(const QString &path, const QStringList &nameFilters,
}
/*!
- Destroys the QDirIterator.
+ Destroys the QDirListing.
*/
-QDirIterator::~QDirIterator()
+QDirListing::~QDirListing() = default;
+
+/*!
+ Returns the directory path used to construct this QDirListing.
+*/
+QString QDirListing::iteratorPath() const
{
+ return d->initialEntryInfo.filePath();
}
/*!
- Advances the iterator to the next entry, and returns the file path of this
- new entry. If hasNext() returns \c false, this function does nothing, and
- returns an empty QString.
+ \fn QDirListing::const_iterator QDirListing::begin() const
+ \fn QDirListing::const_iterator QDirListing::cbegin() const
+ \fn QDirListing::const_iterator QDirListing::end() const
+ \fn QDirListing::const_iterator QDirListing::cend() const
+
+ begin()/cbegin() returns a QDirListing::const_iterator that enables
+ iterating over directory entries using a ranged-for loop; dereferencing
+ this iterator returns a \c{const 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.
+ end()/cend() return a sentinel const_iterator that signals the end of
+ the iteration. Dereferencing this iterator is undefined behavior.
+
+ For example:
+ \snippet code/src_corelib_io_qdirlisting.cpp 0
+
+ Here's how to find and read all files filtered by name, recursively:
+ \snippet code/src_corelib_io_qdirlisting.cpp 1
- Call nextFileInfo() instead of next() if you're interested in the QFileInfo.
+ \note As this is a unidirectional (forward-only) iterator, calling
+ begin()/cbegin() more than once on the same QDirListing object could
+ result in unexpected behavior (for example, some entries being skipped).
- \sa hasNext(), nextFileInfo(), fileName(), filePath(), fileInfo()
+ \sa fileInfo(), fileName(), filePath()
*/
-QString QDirIterator::next()
+QDirListing::const_iterator QDirListing::begin() const
{
- d->advance();
- return filePath();
+ const_iterator it{d.get()};
+ return ++it;
}
/*!
- \since 6.3
+ \fn const QDirListing::DirEntry &QDirListing::const_iterator::operator*() const
- 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.
+ Returns a \c{const QDirListing::DirEntry &} of the directory entry this
+ iterator points to.
+*/
- 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.
+/*!
+ \fn const QDirListing::DirEntry *QDirListing::const_iterator::operator->() const
- Call next() instead of nextFileInfo() when all you need is the filePath().
+ Returns a \c{const QDirListing::DirEntry *} to the directory entry this
+ iterator points to.
+*/
- \sa hasNext(), fileName(), filePath(), fileInfo()
+/*!
+ Advances the iterator and returns a reference to it.
*/
-QFileInfo QDirIterator::nextFileInfo()
+QDirListing::const_iterator &QDirListing::const_iterator::operator++()
{
- d->advance();
- return fileInfo();
+ dirListPtr->advance();
+ if (!dirListPtr->hasIterators())
+ *this = {}; // All done, make `this` the end() iterator
+ return *this;
}
/*!
- Returns \c true if there is at least one more entry in the directory;
- otherwise, false is returned.
-
- \sa next(), nextFileInfo(), fileName(), filePath(), fileInfo()
+ \fn QFileInfo QDirListing::DirEntry::fileInfo() const
+ \fn QString QDirListing::DirEntry::fileName() const
+ \fn QString QDirListing::DirEntry::baseName() const
+ \fn QString QDirListing::DirEntry::completeBaseName() const
+ \fn QString QDirListing::DirEntry::suffix() const
+ \fn QString QDirListing::DirEntry::bundleName() const
+ \fn QString QDirListing::DirEntry::completeSuffix() const
+ \fn QString QDirListing::DirEntry::filePath() const
+ \fn QString QDirListing::DirEntry::canonicalFilePath() const
+ \fn QString QDirListing::DirEntry::absoluteFilePath() const
+ \fn QString QDirListing::DirEntry::absolutePath() const
+ \fn bool QDirListing::DirEntry::isDir() const
+ \fn bool QDirListing::DirEntry::isFile() const
+ \fn bool QDirListing::DirEntry::isSymLink() const
+ \fn bool QDirListing::DirEntry::exists() const
+ \fn bool QDirListing::DirEntry::isHidden() const
+ \fn bool QDirListing::DirEntry::isReadable() const
+ \fn bool QDirListing::DirEntry::isWritable() const
+ \fn bool QDirListing::DirEntry::isExecutable() const
+ \fn qint64 QDirListing::DirEntry::size() const
+ \fn QDateTime QDirListing::DirEntry::fileTime(QFile::FileTime type, const QTimeZone &tz) const
+ \fn QDateTime QDirListing::DirEntry::birthTime(const QTimeZone &tz) const;
+ \fn QDateTime QDirListing::DirEntry::metadataChangeTime(const QTimeZone &tz) const;
+ \fn QDateTime QDirListing::DirEntry::lastModified(const QTimeZone &tz) const;
+ \fn QDateTime QDirListing::DirEntry::lastRead(const QTimeZone &tz) const;
+
+ See the QFileInfo methods with the same names.
*/
-bool QDirIterator::hasNext() const
+
+QFileInfo QDirListing::DirEntry::fileInfo() const
{
- if (d->engine)
- return !d->fileEngineIterators.empty();
- else
-#ifndef QT_NO_FILESYSTEMITERATOR
- return !d->nativeIterators.empty();
-#else
- return false;
-#endif
+ return dirListPtr->currentEntryInfo.fileInfo();
}
-/*!
- Returns the file name for the current directory entry, without the path
- prepended.
+QString QDirListing::DirEntry::fileName() const
+{
+ return dirListPtr->currentEntryInfo.fileName();
+}
- This function is convenient when iterating a single directory. When using
- the QDirIterator::Subdirectories flag, you can use filePath() to get the
- full path.
+QString QDirListing::DirEntry::baseName() const
+{
+ return dirListPtr->currentEntryInfo.baseName();
+}
- \sa filePath(), fileInfo()
-*/
-QString QDirIterator::fileName() const
+QString QDirListing::DirEntry::completeBaseName() const
{
- return d->currentFileInfo.fileName();
+ return dirListPtr->currentEntryInfo.completeBaseName();
}
-/*!
- Returns the full file path for the current directory entry.
+QString QDirListing::DirEntry::suffix() const
+{
+ return dirListPtr->currentEntryInfo.suffix();
+}
- \sa fileInfo(), fileName()
-*/
-QString QDirIterator::filePath() const
+QString QDirListing::DirEntry::bundleName() const
{
- return d->currentFileInfo.filePath();
+ return dirListPtr->currentEntryInfo.bundleName();
}
-/*!
- Returns a QFileInfo for the current directory entry.
+QString QDirListing::DirEntry::completeSuffix() const
+{
+ return dirListPtr->currentEntryInfo.completeSuffix();
+}
- \sa filePath(), fileName()
-*/
-QFileInfo QDirIterator::fileInfo() const
+QString QDirListing::DirEntry::filePath() const
{
- return d->currentFileInfo;
+ return dirListPtr->currentEntryInfo.filePath();
}
-/*!
- Returns the base directory of the iterator.
-*/
-QString QDirIterator::path() const
+QString QDirListing::DirEntry::canonicalFilePath() const
+{
+ return dirListPtr->currentEntryInfo.canonicalFilePath();
+}
+
+QString QDirListing::DirEntry::absoluteFilePath() const
+{
+ return dirListPtr->currentEntryInfo.absoluteFilePath();
+}
+
+QString QDirListing::DirEntry::absolutePath() const
+{
+ return dirListPtr->currentEntryInfo.absolutePath();
+}
+
+bool QDirListing::DirEntry::isDir() const
+{
+ return dirListPtr->currentEntryInfo.isDir();
+}
+
+bool QDirListing::DirEntry::isFile() const
+{
+ return dirListPtr->currentEntryInfo.isFile();
+}
+
+bool QDirListing::DirEntry::isSymLink() const
+{
+ return dirListPtr->currentEntryInfo.isSymLink();
+}
+
+bool QDirListing::DirEntry::exists() const
+{
+ return dirListPtr->currentEntryInfo.exists();
+}
+
+bool QDirListing::DirEntry::isHidden() const
+{
+ return dirListPtr->currentEntryInfo.isHidden();
+}
+
+bool QDirListing::DirEntry::isReadable() const
+{
+ return dirListPtr->currentEntryInfo.isReadable();
+}
+
+bool QDirListing::DirEntry::isWritable() const
+{
+ return dirListPtr->currentEntryInfo.isWritable();
+}
+
+bool QDirListing::DirEntry::isExecutable() const
+{
+ return dirListPtr->currentEntryInfo.isExecutable();
+}
+
+qint64 QDirListing::DirEntry::size() const
+{
+ return dirListPtr->currentEntryInfo.size();
+}
+
+QDateTime QDirListing::DirEntry::fileTime(QFile::FileTime type, const QTimeZone &tz) const
{
- return d->dirEntry.filePath();
+ return dirListPtr->currentEntryInfo.fileTime(type, tz);
}
QT_END_NAMESPACE
diff --git a/src/corelib/io/qdirlisting.h b/src/corelib/io/qdirlisting.h
index 7fa612ebe0..d19fe3c666 100644
--- a/src/corelib/io/qdirlisting.h
+++ b/src/corelib/io/qdirlisting.h
@@ -1,55 +1,119 @@
// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2024 Ahmad Samir <a.samirh78@gmail.com>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#ifndef QDIRITERATOR_H
-#define QDIRITERATOR_H
+#ifndef QDILISTING_H
+#define QDILISTING_H
#include <QtCore/qdir.h>
+#include <iterator>
+#include <memory>
+
QT_BEGIN_NAMESPACE
-class QDirIteratorPrivate;
-class Q_CORE_EXPORT QDirIterator
+class QDirListingPrivate;
+
+class Q_CORE_EXPORT QDirListing
{
public:
- enum IteratorFlag {
- NoIteratorFlags = 0x0,
+ enum class IteratorFlag {
+ NoFlag = 0x0,
FollowSymlinks = 0x1,
- Subdirectories = 0x2
+ Recursive = 0x2
};
Q_DECLARE_FLAGS(IteratorFlags, IteratorFlag)
- QDirIterator(const QDir &dir, IteratorFlags flags = NoIteratorFlags);
- QDirIterator(const QString &path,
- IteratorFlags flags = NoIteratorFlags);
- QDirIterator(const QString &path,
- QDir::Filters filter,
- IteratorFlags flags = NoIteratorFlags);
- QDirIterator(const QString &path,
- const QStringList &nameFilters,
- QDir::Filters filters = QDir::NoFilter,
- IteratorFlags flags = NoIteratorFlags);
+ QDirListing(const QDir &dir, IteratorFlags flags = IteratorFlag::NoFlag);
+ QDirListing(const QString &path, IteratorFlags flags = IteratorFlag::NoFlag);
+ QDirListing(const QString &path, QDir::Filters filter,
+ IteratorFlags flags = IteratorFlag::NoFlag);
+ QDirListing(const QString &path, const QStringList &nameFilters,
+ QDir::Filters filters = QDir::NoFilter,
+ IteratorFlags flags = IteratorFlag::NoFlag);
+
+ ~QDirListing();
+
+ QString iteratorPath() const;
+
+ class Q_CORE_EXPORT DirEntry
+ {
+ friend class QDirListing;
+ QDirListingPrivate *dirListPtr = nullptr;
+ public:
+ QString fileName() const;
+ QString baseName() const;
+ QString completeBaseName() const;
+ QString suffix() const;
+ QString bundleName() const;
+ QString completeSuffix() const;
+ QString filePath() const;
+ bool isDir() const;
+ bool isFile() const;
+ bool isSymLink() const;
+ bool exists() const;
+ bool isHidden() const;
+ bool isReadable() const;
+ bool isWritable() const;
+ bool isExecutable() const;
+ QFileInfo fileInfo() const;
+ QString canonicalFilePath() const;
+ QString absoluteFilePath() const;
+ QString absolutePath() const;
+ qint64 size() const;
- ~QDirIterator();
+ QDateTime birthTime(const QTimeZone &tz) const { return fileTime(QFile::FileBirthTime, tz); }
+ QDateTime metadataChangeTime(const QTimeZone &tz) const { return fileTime(QFile::FileMetadataChangeTime, tz); }
+ QDateTime lastModified(const QTimeZone &tz) const { return fileTime(QFile::FileModificationTime, tz); }
+ QDateTime lastRead(const QTimeZone &tz) const { return fileTime(QFile::FileAccessTime, tz); }
+ QDateTime fileTime(QFile::FileTime type, const QTimeZone &tz) const;
+ };
+
+ class const_iterator
+ {
+ friend class QDirListing;
+ const_iterator(QDirListingPrivate *dp) : dirListPtr(dp) { dirEntry.dirListPtr = dp; }
+ QDirListingPrivate *dirListPtr = nullptr;
+ DirEntry dirEntry;
+ public:
+ using iterator_category = std::input_iterator_tag;
+ using value_type = DirEntry;
+ using difference_type = qint64;
+ using pointer = const value_type *;
+ using reference = const value_type &;
+
+ const_iterator() = default;
+ reference operator*() const { return dirEntry; }
+ pointer operator->() const { return &dirEntry; }
+ Q_CORE_EXPORT const_iterator &operator++();
+ const_iterator operator++(int) { auto tmp = *this; operator++(); return tmp; };
+ friend bool operator==(const const_iterator &lhs, const const_iterator &rhs)
+ {
+ // This is only used for the sentinel end iterator
+ return lhs.dirListPtr == nullptr && rhs.dirListPtr == nullptr;
+ }
+ friend bool operator!=(const const_iterator &lhs, const const_iterator &rhs)
+ { return !(lhs == rhs); }
+ };
- QString next();
- QFileInfo nextFileInfo();
- bool hasNext() const;
+ const_iterator begin() const;
+ const_iterator cbegin() const { return begin(); }
+ const_iterator end() const { return {}; }
+ const_iterator cend() const { return end(); }
- QString fileName() const;
- QString filePath() const;
- QFileInfo fileInfo() const;
- QString path() const;
+ // Qt compatibility
+ const_iterator constBegin() const { return begin(); }
+ const_iterator constEnd() const { return end(); }
private:
- Q_DISABLE_COPY(QDirIterator)
+ Q_DISABLE_COPY(QDirListing)
- QScopedPointer<QDirIteratorPrivate> d;
+ std::unique_ptr<QDirListingPrivate> d;
friend class QDir;
};
-Q_DECLARE_OPERATORS_FOR_FLAGS(QDirIterator::IteratorFlags)
+Q_DECLARE_OPERATORS_FOR_FLAGS(QDirListing::IteratorFlags)
QT_END_NAMESPACE
-#endif
+#endif // QDILISTING_H
diff --git a/src/corelib/io/qfileinfo.h b/src/corelib/io/qfileinfo.h
index cb1ba8807d..72c8519446 100644
--- a/src/corelib/io/qfileinfo.h
+++ b/src/corelib/io/qfileinfo.h
@@ -22,6 +22,7 @@ class QFileInfoPrivate;
class Q_CORE_EXPORT QFileInfo
{
friend class QDirIteratorPrivate;
+ friend class QDirListingPrivate;
public:
explicit QFileInfo(QFileInfoPrivate *d);
diff --git a/tests/auto/corelib/io/CMakeLists.txt b/tests/auto/corelib/io/CMakeLists.txt
index 22eb2148f8..7fdf4b52b0 100644
--- a/tests/auto/corelib/io/CMakeLists.txt
+++ b/tests/auto/corelib/io/CMakeLists.txt
@@ -16,6 +16,7 @@ endif()
add_subdirectory(qbuffer)
add_subdirectory(qdataurl)
add_subdirectory(qdiriterator)
+add_subdirectory(qdirlisting)
add_subdirectory(qfile)
add_subdirectory(largefile)
add_subdirectory(qfileselector)
diff --git a/tests/auto/corelib/io/qdirlisting/.gitignore b/tests/auto/corelib/io/qdirlisting/.gitignore
new file mode 100644
index 0000000000..4965f97d03
--- /dev/null
+++ b/tests/auto/corelib/io/qdirlisting/.gitignore
@@ -0,0 +1 @@
+tst_qdirlisting
diff --git a/tests/auto/corelib/io/qdirlisting/CMakeLists.txt b/tests/auto/corelib/io/qdirlisting/CMakeLists.txt
index 41784546aa..77431776d9 100644
--- a/tests/auto/corelib/io/qdirlisting/CMakeLists.txt
+++ b/tests/auto/corelib/io/qdirlisting/CMakeLists.txt
@@ -2,44 +2,45 @@
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
-## tst_qdiriterator Test:
+## tst_qdirlisting Test:
#####################################################################
if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
cmake_minimum_required(VERSION 3.16)
- project(tst_qdiriterator LANGUAGES CXX)
+ project(tst_qdirlisting LANGUAGES CXX)
find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
endif()
# Collect test data
list(APPEND test_data "entrylist")
-qt_internal_add_test(tst_qdiriterator
+qt_internal_add_test(tst_qdirlisting
SOURCES
- tst_qdiriterator.cpp
+ tst_qdirlisting.cpp
LIBRARIES
+ Qt::Core
Qt::CorePrivate
TESTDATA ${test_data}
)
# Resources:
-set(qdiriterator_resource_files
+set(qdirlisting_resource_files
"entrylist/directory/dummy"
"entrylist/file"
)
-qt_internal_add_resource(tst_qdiriterator "qdiriterator"
+qt_internal_add_resource(tst_qdirlisting "qdirlisting"
PREFIX
"/testdata/"
FILES
- ${qdiriterator_resource_files}
+ ${qdirlisting_resource_files}
)
## Scopes:
#####################################################################
-qt_internal_extend_target(tst_qdiriterator CONDITION CONFIG___contains___builtin_testdata
+qt_internal_extend_target(tst_qdirlisting CONDITION CONFIG___contains___builtin_testdata
DEFINES
BUILTIN_TESTDATA
)
diff --git a/tests/auto/corelib/io/qdirlisting/tst_qdirlisting.cpp b/tests/auto/corelib/io/qdirlisting/tst_qdirlisting.cpp
index ac92b9b692..717da83e17 100644
--- a/tests/auto/corelib/io/qdirlisting/tst_qdirlisting.cpp
+++ b/tests/auto/corelib/io/qdirlisting/tst_qdirlisting.cpp
@@ -5,7 +5,7 @@
#include <qcoreapplication.h>
#include <qdebug.h>
-#include <qdiriterator.h>
+#include <qdirlisting.h>
#include <qfileinfo.h>
#include <qstringlist.h>
#include <QSet>
@@ -25,10 +25,12 @@
using namespace Qt::StringLiterals;
-Q_DECLARE_METATYPE(QDirIterator::IteratorFlags)
+Q_DECLARE_METATYPE(QDirListing::IteratorFlags)
Q_DECLARE_METATYPE(QDir::Filters)
-class tst_QDirIterator : public QObject
+using ItFlag = QDirListing::IteratorFlag;
+
+class tst_QDirListing : public QObject
{
Q_OBJECT
@@ -90,23 +92,21 @@ private:
QTemporaryDir m_dataDir;
};
-void tst_QDirIterator::initTestCase()
+void tst_QDirListing::initTestCase()
{
#ifdef Q_OS_ANDROID
QString testdata_dir = QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
QString resourceSourcePath = QStringLiteral(":/testdata");
- QDirIterator it(resourceSourcePath, QDirIterator::Subdirectories);
- while (it.hasNext()) {
- QFileInfo fileInfo = it.nextFileInfo();
-
- if (!fileInfo.isDir()) {
+ for (const auto &dirEntry : QDirListing(resourceSourcePath, ItFlag::Recursive)) {
+ if (!dirEntry.isDir()) {
+ const QString &filePath = dirEntry.filePath();
QString destination = testdata_dir + QLatin1Char('/')
- + fileInfo.filePath().mid(resourceSourcePath.length());
+ + filePath.sliced(resourceSourcePath.length());
QFileInfo destinationFileInfo(destination);
if (!destinationFileInfo.exists()) {
QDir().mkpath(destinationFileInfo.path());
- if (!QFile::copy(fileInfo.filePath(), destination))
- qWarning("Failed to copy %s", qPrintable(fileInfo.filePath()));
+ if (!QFile::copy(filePath, destination))
+ qWarning("Failed to copy %s", qPrintable(filePath));
}
}
@@ -180,16 +180,16 @@ void tst_QDirIterator::initTestCase()
#endif
}
-void tst_QDirIterator::iterateRelativeDirectory_data()
+void tst_QDirListing::iterateRelativeDirectory_data()
{
QTest::addColumn<QString>("dirName"); // relative from current path or abs
- QTest::addColumn<QDirIterator::IteratorFlags>("flags");
+ QTest::addColumn<QDirListing::IteratorFlags>("flags");
QTest::addColumn<QDir::Filters>("filters");
QTest::addColumn<QStringList>("nameFilters");
QTest::addColumn<QStringList>("entries");
QTest::newRow("no flags")
- << QString("entrylist") << QDirIterator::IteratorFlags{}
+ << QString("entrylist") << QDirListing::IteratorFlags{}
<< QDir::Filters(QDir::NoFilter) << QStringList("*")
<< QString(
"entrylist/.,"
@@ -205,7 +205,7 @@ void tst_QDirIterator::iterateRelativeDirectory_data()
"entrylist/writable").split(',');
QTest::newRow("NoDot")
- << QString("entrylist") << QDirIterator::IteratorFlags{}
+ << QString("entrylist") << QDirListing::IteratorFlags{}
<< QDir::Filters(QDir::AllEntries | QDir::NoDot) << QStringList("*")
<< QString(
"entrylist/..,"
@@ -220,7 +220,7 @@ void tst_QDirIterator::iterateRelativeDirectory_data()
"entrylist/writable").split(',');
QTest::newRow("NoDotDot")
- << QString("entrylist") << QDirIterator::IteratorFlags{}
+ << QString("entrylist") << QDirListing::IteratorFlags{}
<< QDir::Filters(QDir::AllEntries | QDir::NoDotDot) << QStringList("*")
<< QString(
"entrylist/.,"
@@ -235,7 +235,7 @@ void tst_QDirIterator::iterateRelativeDirectory_data()
"entrylist/writable").split(',');
QTest::newRow("NoDotAndDotDot")
- << QString("entrylist") << QDirIterator::IteratorFlags{}
+ << QString("entrylist") << QDirListing::IteratorFlags{}
<< QDir::Filters(QDir::AllEntries | QDir::NoDotAndDotDot) << QStringList("*")
<< QString(
"entrylist/file,"
@@ -249,7 +249,7 @@ void tst_QDirIterator::iterateRelativeDirectory_data()
"entrylist/writable").split(',');
QTest::newRow("QDir::Subdirectories | QDir::FollowSymlinks")
- << QString("entrylist") << QDirIterator::IteratorFlags(QDirIterator::Subdirectories | QDirIterator::FollowSymlinks)
+ << QString("entrylist") << QDirListing::IteratorFlags(ItFlag::Recursive | ItFlag::FollowSymlinks)
<< QDir::Filters(QDir::NoFilter) << QStringList("*")
<< QString(
"entrylist/.,"
@@ -268,7 +268,7 @@ void tst_QDirIterator::iterateRelativeDirectory_data()
"entrylist/writable").split(',');
QTest::newRow("QDir::Subdirectories / QDir::Files")
- << QString("entrylist") << QDirIterator::IteratorFlags(QDirIterator::Subdirectories)
+ << QString("entrylist") << QDirListing::IteratorFlags(ItFlag::Recursive)
<< QDir::Filters(QDir::Files) << QStringList("*")
<< QString("entrylist/directory/dummy,"
"entrylist/file,"
@@ -278,7 +278,7 @@ void tst_QDirIterator::iterateRelativeDirectory_data()
"entrylist/writable").split(',');
QTest::newRow("QDir::Subdirectories | QDir::FollowSymlinks / QDir::Files")
- << QString("entrylist") << QDirIterator::IteratorFlags(QDirIterator::Subdirectories | QDirIterator::FollowSymlinks)
+ << QString("entrylist") << QDirListing::IteratorFlags(ItFlag::Recursive | QDirListing::IteratorFlag::FollowSymlinks)
<< QDir::Filters(QDir::Files) << QStringList("*")
<< QString("entrylist/file,"
#ifndef Q_NO_SYMLINKS
@@ -288,47 +288,31 @@ void tst_QDirIterator::iterateRelativeDirectory_data()
"entrylist/writable").split(',');
QTest::newRow("empty, default")
- << QString("empty") << QDirIterator::IteratorFlags{}
+ << QString("empty") << QDirListing::IteratorFlags{}
<< QDir::Filters(QDir::NoFilter) << QStringList("*")
<< QString("empty/.,empty/..").split(',');
QTest::newRow("empty, QDir::NoDotAndDotDot")
- << QString("empty") << QDirIterator::IteratorFlags{}
+ << QString("empty") << QDirListing::IteratorFlags{}
<< QDir::Filters(QDir::NoDotAndDotDot) << QStringList("*")
<< QStringList();
}
-void tst_QDirIterator::iterateRelativeDirectory()
+void tst_QDirListing::iterateRelativeDirectory()
{
QFETCH(QString, dirName);
- QFETCH(QDirIterator::IteratorFlags, flags);
+ QFETCH(QDirListing::IteratorFlags, flags);
QFETCH(QDir::Filters, filters);
QFETCH(QStringList, nameFilters);
QFETCH(const QStringList, entries);
- QDirIterator it(dirName, nameFilters, filters, flags);
QStringList list;
- while (it.hasNext()) {
- QString next = it.next();
-
- QString fileName = it.fileName();
- QString filePath = it.filePath();
- QString path = it.path();
-
- QFileInfo info = it.fileInfo();
-
- QCOMPARE(path, dirName);
- QCOMPARE(next, filePath);
-
- QCOMPARE(info, QFileInfo(next));
- QCOMPARE(fileName, info.fileName());
- QCOMPARE(filePath, info.filePath());
-
+ for (const auto &dirEntry : QDirListing(dirName, nameFilters, filters, flags)) {
// Using canonical file paths for final comparison
- list << info.canonicalFilePath();
+ list << dirEntry.fileInfo().canonicalFilePath();
}
- // The order of items returned by QDirIterator is not guaranteed.
+ // The order of items returned by QDirListing is not guaranteed.
list.sort();
QStringList sortedEntries;
@@ -344,43 +328,42 @@ void tst_QDirIterator::iterateRelativeDirectory()
QCOMPARE(list, sortedEntries);
}
-void tst_QDirIterator::iterateResource_data()
+void tst_QDirListing::iterateResource_data()
{
QTest::addColumn<QString>("dirName"); // relative from current path or abs
- QTest::addColumn<QDirIterator::IteratorFlags>("flags");
+ QTest::addColumn<QDirListing::IteratorFlags>("flags");
QTest::addColumn<QDir::Filters>("filters");
QTest::addColumn<QStringList>("nameFilters");
QTest::addColumn<QStringList>("entries");
- QTest::newRow("invalid") << QString::fromLatin1(":/testdata/burpaburpa") << QDirIterator::IteratorFlags{}
+ QTest::newRow("invalid") << QString::fromLatin1(":/testdata/burpaburpa") << QDirListing::IteratorFlags{}
<< QDir::Filters(QDir::NoFilter) << QStringList(QLatin1String("*"))
<< QStringList();
- QTest::newRow("qrc:/testdata") << u":/testdata/"_s << QDirIterator::IteratorFlags{}
+ QTest::newRow("qrc:/testdata") << u":/testdata/"_s << QDirListing::IteratorFlags{}
<< QDir::Filters(QDir::NoFilter) << QStringList(QLatin1String("*"))
<< QString::fromLatin1(":/testdata/entrylist").split(QLatin1String(","));
- QTest::newRow("qrc:/testdata/entrylist") << u":/testdata/entrylist"_s << QDirIterator::IteratorFlags{}
+ QTest::newRow("qrc:/testdata/entrylist") << u":/testdata/entrylist"_s << QDirListing::IteratorFlags{}
<< QDir::Filters(QDir::NoFilter) << QStringList(QLatin1String("*"))
<< QString::fromLatin1(":/testdata/entrylist/directory,:/testdata/entrylist/file").split(QLatin1String(","));
QTest::newRow("qrc:/testdata recursive") << u":/testdata"_s
- << QDirIterator::IteratorFlags(QDirIterator::Subdirectories)
+ << QDirListing::IteratorFlags(ItFlag::Recursive)
<< QDir::Filters(QDir::NoFilter) << QStringList(QLatin1String("*"))
<< QString::fromLatin1(":/testdata/entrylist,:/testdata/entrylist/directory,:/testdata/entrylist/directory/dummy,:/testdata/entrylist/file").split(QLatin1String(","));
}
-void tst_QDirIterator::iterateResource()
+void tst_QDirListing::iterateResource()
{
QFETCH(QString, dirName);
- QFETCH(QDirIterator::IteratorFlags, flags);
+ QFETCH(QDirListing::IteratorFlags, flags);
QFETCH(QDir::Filters, filters);
QFETCH(QStringList, nameFilters);
QFETCH(QStringList, entries);
- QDirIterator it(dirName, nameFilters, filters, flags);
QStringList list;
- while (it.hasNext()) {
- const QString dir = it.next();
+ for (const auto &dirEntry : QDirListing(dirName, nameFilters, filters, flags)) {
+ QString dir = dirEntry.fileInfo().filePath();
if (!dir.startsWith(":/qt-project.org"))
- list << dir;
+ list.emplace_back(std::move(dir));
}
list.sort();
@@ -395,7 +378,7 @@ void tst_QDirIterator::iterateResource()
QCOMPARE(list, sortedEntries);
}
-void tst_QDirIterator::stopLinkLoop()
+void tst_QDirListing::stopLinkLoop()
{
#ifdef Q_OS_WIN
// ### Sadly, this is a platform difference right now.
@@ -418,12 +401,14 @@ void tst_QDirIterator::stopLinkLoop()
createLink("..", "entrylist/directory/entrylist4.lnk");
#endif
- QDirIterator it(QLatin1String("entrylist"), QDirIterator::Subdirectories | QDirIterator::FollowSymlinks);
+ constexpr auto flags = ItFlag::Recursive | ItFlag::FollowSymlinks;
+ QDirListing dirIter(u"entrylist"_s, flags);
QStringList list;
int max = 200;
- while (--max && it.hasNext())
- it.nextFileInfo();
- QVERIFY(max);
+ auto it = dirIter.begin();
+ while (--max && it != dirIter.end())
+ ++it;
+ QCOMPARE_GT(max, 0);
// The goal of this test is only to ensure that the test above don't malfunction
}
@@ -451,7 +436,7 @@ public:
#endif
#ifdef QT_BUILD_INTERNAL
-void tst_QDirIterator::engineWithNoIterator()
+void tst_QDirListing::engineWithNoIterator()
{
EngineWithNoIteratorHandler handler;
@@ -464,113 +449,98 @@ class CustomEngineHandler : public QAbstractFileEngineHandler
public:
QAbstractFileEngine *create(const QString &fileName) const override
{
- // We want to test QFSFileEngine specifically, so force QDirIterator to use it
+ // We want to test QFSFileEngine specifically, so force QDirListing to use it
// over the default QFileSystemEngine
return new QFSFileEngine(fileName);
}
};
-void tst_QDirIterator::testQFsFileEngineIterator()
+void tst_QDirListing::testQFsFileEngineIterator()
{
QFETCH(QString, dirName);
QFETCH(QStringList, nameFilters);
QFETCH(QDir::Filters, filters);
- QFETCH(QDirIterator::IteratorFlags, flags);
+ QFETCH(QDirListing::IteratorFlags, flags);
if (dirName == u"empty")
return; // This row isn't useful in this test
CustomEngineHandler handler;
bool isEmpty = true;
- QDirIterator iter(dirName, nameFilters, filters, flags);
- while (iter.hasNext()) {
- const QFileInfo &fi = iter.nextFileInfo();
- if (fi.filePath().contains(u"entrylist"))
+ for (const auto &dirEntry : QDirListing(u"entrylist"_s, nameFilters, filters, flags)) {
+ if (dirEntry.filePath().contains(u"entrylist"))
isEmpty = false; // At least one entry in `entrylist` dir
}
- QVERIFY(!isEmpty);
+ QVERIFY(!isEmpty); // At least one entry
}
#endif
-void tst_QDirIterator::absoluteFilePathsFromRelativeIteratorPath()
+void tst_QDirListing::absoluteFilePathsFromRelativeIteratorPath()
{
- QDirIterator it("entrylist/", QDir::NoDotAndDotDot);
- while (it.hasNext())
- QVERIFY(it.nextFileInfo().absoluteFilePath().contains("entrylist"));
+ for (const auto &dirEntry : QDirListing(u"entrylist/"_s, QDir::NoDotAndDotDot))
+ QVERIFY(dirEntry.absoluteFilePath().contains("entrylist"));
}
-void tst_QDirIterator::recurseWithFilters() const
+void tst_QDirListing::recurseWithFilters() const
{
- QStringList nameFilters;
- nameFilters.append("*.txt");
-
- QDirIterator it("recursiveDirs/", nameFilters, QDir::Files,
- QDirIterator::Subdirectories);
-
QSet<QString> actualEntries;
QSet<QString> expectedEntries;
expectedEntries.insert(QString::fromLatin1("recursiveDirs/dir1/textFileB.txt"));
expectedEntries.insert(QString::fromLatin1("recursiveDirs/textFileA.txt"));
- QVERIFY(it.hasNext());
- actualEntries.insert(it.next());
- QVERIFY(it.hasNext());
- actualEntries.insert(it.next());
- QCOMPARE(actualEntries, expectedEntries);
+ for (const auto &dirEntry : QDirListing(u"recursiveDirs/"_s, QStringList{u"*.txt"_s},
+ QDir::Files, ItFlag::Recursive)) {
+ actualEntries.insert(dirEntry.filePath());
+ }
- QVERIFY(!it.hasNext());
+ QCOMPARE(actualEntries, expectedEntries);
}
-void tst_QDirIterator::longPath()
+void tst_QDirListing::longPath()
{
QDir dir;
dir.mkdir("longpaths");
dir.cd("longpaths");
QString dirName = "x";
- int n = 0;
+ qsizetype n = 0;
while (dir.exists(dirName) || dir.mkdir(dirName)) {
++n;
dirName.append('x');
}
- QDirIterator it(dir.absolutePath(), QDir::NoDotAndDotDot|QDir::Dirs, QDirIterator::Subdirectories);
- int m = 0;
- while (it.hasNext()) {
+ QDirListing dirList(dir.absolutePath(), QDir::NoDotAndDotDot|QDir::Dirs, ItFlag::Recursive);
+ qsizetype m = 0;
+ for (auto it = dirList.begin(); it != dirList.end(); ++it)
++m;
- it.nextFileInfo();
- }
QCOMPARE(n, m);
dirName.chop(1);
- while (dirName.size() > 0 && dir.exists(dirName) && dir.rmdir(dirName)) {
+ while (dirName.size() > 0 && dir.exists(dirName) && dir.rmdir(dirName))
dirName.chop(1);
- }
+
dir.cdUp();
dir.rmdir("longpaths");
}
-void tst_QDirIterator::dirorder()
+void tst_QDirListing::dirorder()
{
- QDirIterator iterator("foo", QDirIterator::Subdirectories);
- while (iterator.hasNext() && iterator.next() != "foo/bar")
- { }
+ QStringList entries;
+ for (const auto &dirEntry : QDirListing(u"foo"_s, ItFlag::Recursive))
+ entries.append(dirEntry.filePath());
- QCOMPARE(iterator.filePath(), QString("foo/bar"));
- QCOMPARE(iterator.fileInfo().filePath(), QString("foo/bar"));
+ QCOMPARE_GT(entries.indexOf(u"foo/bar"_s), entries.indexOf(u"foo"_s));
}
-void tst_QDirIterator::relativePaths()
+void tst_QDirListing::relativePaths()
{
- QDirIterator iterator("*", QDirIterator::Subdirectories);
- while(iterator.hasNext()) {
- QCOMPARE(iterator.filePath(), QDir::cleanPath(iterator.filePath()));
- }
+ for (const auto &dirEntry : QDirListing(u"*"_s, ItFlag::Recursive))
+ QCOMPARE(dirEntry.filePath(), QDir::cleanPath(dirEntry.filePath()));
}
#if defined(Q_OS_WIN)
-void tst_QDirIterator::uncPaths_data()
+void tst_QDirListing::uncPaths_data()
{
QTest::addColumn<QString>("dirName");
QTest::newRow("uncserver")
@@ -580,13 +550,13 @@ void tst_QDirIterator::uncPaths_data()
QTest::newRow("uncserver/testshare/tmp")
<<QString("//" + QTest::uncServerName() + "/testshare/tmp");
}
-void tst_QDirIterator::uncPaths()
+void tst_QDirListing::uncPaths()
{
QFETCH(QString, dirName);
- QDirIterator iterator(dirName, QDir::AllEntries|QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
- while(iterator.hasNext()) {
- iterator.next();
- QCOMPARE(iterator.filePath(), QDir::cleanPath(iterator.filePath()));
+ constexpr auto dirFilters = QDir::AllEntries | QDir::NoDotAndDotDot;
+ for (const auto &dirEntry : QDirListing(dirName, dirFilters, ItFlag::Recursive)) {
+ const QString &filePath = dirEntry.filePath();
+ QCOMPARE(filePath, QDir::cleanPath(filePath));
}
}
#endif
@@ -596,16 +566,17 @@ void tst_QDirIterator::uncPaths()
// a special call since hidden files need to be "marked" while in Unix
// anything starting by a '.' is a hidden file.
// For that reason this test is not run in Windows.
-void tst_QDirIterator::hiddenDirs_hiddenFiles()
+void tst_QDirListing::hiddenDirs_hiddenFiles()
{
// Only files
{
int matches = 0;
int failures = 0;
- QDirIterator di("hiddenDirs_hiddenFiles", QDir::Files | QDir::Hidden | QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
- while (di.hasNext()) {
+ constexpr auto filters = QDir::Files | QDir::Hidden | QDir::NoDotAndDotDot;
+ for (const auto &dirEntry : QDirListing(u"hiddenDirs_hiddenFiles"_s, filters,
+ ItFlag::Recursive)) {
++matches;
- if (di.nextFileInfo().isDir())
+ if (dirEntry.isDir())
++failures; // search was only supposed to find files
}
QCOMPARE(matches, 6);
@@ -615,10 +586,11 @@ void tst_QDirIterator::hiddenDirs_hiddenFiles()
{
int matches = 0;
int failures = 0;
- QDirIterator di("hiddenDirs_hiddenFiles", QDir::Dirs | QDir::Hidden | QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
- while (di.hasNext()) {
+ constexpr auto filters = QDir::Dirs | QDir::Hidden | QDir::NoDotAndDotDot;
+ for (const auto &dirEntry : QDirListing(u"hiddenDirs_hiddenFiles"_s, filters,
+ ItFlag::Recursive)) {
++matches;
- if (!di.nextFileInfo().isDir())
+ if (!dirEntry.isDir())
++failures; // search was only supposed to find files
}
QCOMPARE(matches, 6);
@@ -627,7 +599,7 @@ void tst_QDirIterator::hiddenDirs_hiddenFiles()
}
#endif // Q_OS_WIN
-QTEST_MAIN(tst_QDirIterator)
+QTEST_MAIN(tst_QDirListing)
-#include "tst_qdiriterator.moc"
+#include "tst_qdirlisting.moc"