QDirIterator: manage fs/file iterators with unique_ptr

Use std::stack/std::vector, since QList doesn't work with move only
types.

Change-Id: If0009c8127d56f85bb6b4b7bd40251cdc6b7950d
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Ahmad Samir 2023-12-14 18:48:17 +02:00
parent 1a3753fc78
commit 3d3eb7e402

View File

@ -72,21 +72,13 @@
#include <QtCore/private/qduplicatetracker_p.h> #include <QtCore/private/qduplicatetracker_p.h>
#include <memory> #include <memory>
#include <stack>
#include <vector>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals; using namespace Qt::StringLiterals;
template <class Iterator>
class QDirIteratorPrivateIteratorStack : public QStack<Iterator *>
{
public:
~QDirIteratorPrivateIteratorStack()
{
qDeleteAll(*this);
}
};
class QDirIteratorPrivate class QDirIteratorPrivate
{ {
public: public:
@ -109,9 +101,11 @@ public:
QList<QRegularExpression> nameRegExps; QList<QRegularExpression> nameRegExps;
#endif #endif
QDirIteratorPrivateIteratorStack<QAbstractFileEngineIterator> fileEngineIterators; using FEngineIteratorPtr = std::unique_ptr<QAbstractFileEngineIterator>;
std::stack<FEngineIteratorPtr, std::vector<FEngineIteratorPtr>> fileEngineIterators;
#ifndef QT_NO_FILESYSTEMITERATOR #ifndef QT_NO_FILESYSTEMITERATOR
QDirIteratorPrivateIteratorStack<QFileSystemIterator> nativeIterators; using FsIteratorPtr = std::unique_ptr<QFileSystemIterator>;
std::stack<FsIteratorPtr, std::vector<FsIteratorPtr>> nativeIterators;
#endif #endif
QFileInfo currentFileInfo; QFileInfo currentFileInfo;
@ -170,15 +164,14 @@ void QDirIteratorPrivate::pushDirectory(const QFileInfo &fileInfo)
QAbstractFileEngineIterator *it = engine->beginEntryList(filters, nameFilters); QAbstractFileEngineIterator *it = engine->beginEntryList(filters, nameFilters);
if (it) { if (it) {
it->setPath(path); it->setPath(path);
fileEngineIterators << it; fileEngineIterators.emplace(FEngineIteratorPtr(it));
} else { } else {
// No iterator; no entry list. // No iterator; no entry list.
} }
} else { } else {
#ifndef QT_NO_FILESYSTEMITERATOR #ifndef QT_NO_FILESYSTEMITERATOR
QFileSystemIterator *it = new QFileSystemIterator(fileInfo.d_ptr->fileEntry, nativeIterators.emplace(std::make_unique<QFileSystemIterator>(
filters, nameFilters, iteratorFlags); fileInfo.d_ptr->fileEntry, filters, nameFilters, iteratorFlags));
nativeIterators << it;
#else #else
qWarning("Qt was built with -no-feature-filesystemiterator: no files/plugins will be found!"); qWarning("Qt was built with -no-feature-filesystemiterator: no files/plugins will be found!");
#endif #endif
@ -202,31 +195,46 @@ inline bool QDirIteratorPrivate::entryMatches(const QString & fileName, const QF
/*! /*!
\internal \internal
Advances the internal iterator, either a QAbstractFileEngineIterator (e.g.
QResourceFileEngineIterator) or a QFileSystemIterator (which uses low-level
system methods, e.g. readdir() on Unix).
An iterator stack is used for holding the iterators.
A typical example of doing recursive iteration:
- while iterating directory A we find a sub-dir B
- an iterator for B is added to the iterator stack
- B's iterator is processed (the top() of the stack) first; then loop
goes back to processing A's iterator
*/ */
void QDirIteratorPrivate::advance() void QDirIteratorPrivate::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
// pushDirectory().
if (engine) { if (engine) {
while (!fileEngineIterators.isEmpty()) { while (!fileEngineIterators.empty()) {
// Find the next valid iterator that matches the filters. // Find the next valid iterator that matches the filters.
QAbstractFileEngineIterator *it; QAbstractFileEngineIterator *it;
while (it = fileEngineIterators.top(), it->hasNext()) { while (it = fileEngineIterators.top().get(), it->hasNext()) {
it->next(); it->next();
if (entryMatches(it->currentFileName(), it->currentFileInfo())) if (entryMatches(it->currentFileName(), it->currentFileInfo()))
return; return;
} }
fileEngineIterators.pop(); fileEngineIterators.pop();
delete it;
} }
} else { } else {
#ifndef QT_NO_FILESYSTEMITERATOR #ifndef QT_NO_FILESYSTEMITERATOR
QFileSystemEntry nextEntry; QFileSystemEntry nextEntry;
QFileSystemMetaData nextMetaData; QFileSystemMetaData nextMetaData;
while (!nativeIterators.isEmpty()) { while (!nativeIterators.empty()) {
// Find the next valid iterator that matches the filters. // Find the next valid iterator that matches the filters.
QFileSystemIterator *it; QFileSystemIterator *it;
while (it = nativeIterators.top(), it->advance(nextEntry, nextMetaData)) { while (it = nativeIterators.top().get(), it->advance(nextEntry, nextMetaData)) {
QFileInfo info(new QFileInfoPrivate(nextEntry, nextMetaData)); QFileInfo info(new QFileInfoPrivate(nextEntry, nextMetaData));
if (entryMatches(nextEntry.fileName(), info)) if (entryMatches(nextEntry.fileName(), info))
@ -235,7 +243,6 @@ void QDirIteratorPrivate::advance()
} }
nativeIterators.pop(); nativeIterators.pop();
delete it;
} }
#endif #endif
} }
@ -513,10 +520,10 @@ QFileInfo QDirIterator::nextFileInfo()
bool QDirIterator::hasNext() const bool QDirIterator::hasNext() const
{ {
if (d->engine) if (d->engine)
return !d->fileEngineIterators.isEmpty(); return !d->fileEngineIterators.empty();
else else
#ifndef QT_NO_FILESYSTEMITERATOR #ifndef QT_NO_FILESYSTEMITERATOR
return !d->nativeIterators.isEmpty(); return !d->nativeIterators.empty();
#else #else
return false; return false;
#endif #endif