QDirListing: begin() should start iteration from square 0
The old behavior was that calling begin() calls QDirListingPrivate::advance(), if you call begin() again, it would call advance() a second time. Not the most intuitive of APIs, but it wasn't any worse/different from QDirIterator Java-style hasNext()/next() (if you call next() twice, you advance twice). Now (c)begin() always starts iterating from the very beginning. Amends c39a0d1e8956e042139ce3065681e4c5d07412f3 pushDirectory(initialEntryInfo) is now called from beginIterating(), so don't call it in init(). Not using a std::stack because beginIterating() needs to clear the iterator containers; for some reason on INTEGRITY something like this won't work (std::stack doesn't have clear()), complaining about the constructor being explicit: nativeIterators = {}; The above works just fine on Linux, so instead of having to spell out the type... just use std::vector directly (back(), pop_back() and clear()); this is private API so we have full constrol on how the vectors are used. Change-Id: Iaaa849f989b2724bf070730f6273263289dd4d9c Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
56568fdee6
commit
28fd273080
@ -80,7 +80,6 @@
|
||||
#include <QtCore/private/qduplicatetracker_p.h>
|
||||
|
||||
#include <memory>
|
||||
#include <stack>
|
||||
#include <vector>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
@ -92,6 +91,7 @@ class QDirListingPrivate
|
||||
public:
|
||||
void init(bool resolveEngine);
|
||||
void advance();
|
||||
void beginIterating();
|
||||
|
||||
bool entryMatches(QDirEntryInfo &info);
|
||||
void pushDirectory(QDirEntryInfo &info);
|
||||
@ -113,10 +113,10 @@ public:
|
||||
#endif
|
||||
|
||||
using FEngineIteratorPtr = std::unique_ptr<QAbstractFileEngineIterator>;
|
||||
std::stack<FEngineIteratorPtr, std::vector<FEngineIteratorPtr>> fileEngineIterators;
|
||||
std::vector<FEngineIteratorPtr> fileEngineIterators;
|
||||
#ifndef QT_NO_FILESYSTEMITERATOR
|
||||
using FsIteratorPtr = std::unique_ptr<QFileSystemIterator>;
|
||||
std::stack<FsIteratorPtr, std::vector<FsIteratorPtr>> nativeIterators;
|
||||
std::vector<FsIteratorPtr> nativeIterators;
|
||||
#endif
|
||||
|
||||
// Loop protection
|
||||
@ -143,7 +143,21 @@ void QDirListingPrivate::init(bool resolveEngine = true)
|
||||
engine = QFileSystemEngine::createLegacyEngine(initialEntryInfo.entry,
|
||||
initialEntryInfo.metaData);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
|
||||
Resets the iteration state (if any), so that calling begin()/cbegin()
|
||||
always starts iterating anew.
|
||||
*/
|
||||
void QDirListingPrivate::beginIterating()
|
||||
{
|
||||
#ifndef QT_NO_FILESYSTEMITERATOR
|
||||
nativeIterators.clear();
|
||||
#endif
|
||||
fileEngineIterators.clear();
|
||||
visitedLinks.clear();
|
||||
pushDirectory(initialEntryInfo);
|
||||
}
|
||||
|
||||
@ -167,7 +181,7 @@ void QDirListingPrivate::pushDirectory(QDirEntryInfo &entryInfo)
|
||||
if (engine) {
|
||||
engine->setFileName(path);
|
||||
if (auto it = engine->beginEntryList(path, filters, nameFilters)) {
|
||||
fileEngineIterators.emplace(std::move(it));
|
||||
fileEngineIterators.emplace_back(std::move(it));
|
||||
} else {
|
||||
// No iterator; no entry list.
|
||||
}
|
||||
@ -178,7 +192,7 @@ void QDirListingPrivate::pushDirectory(QDirEntryInfo &entryInfo)
|
||||
fentry = &entryInfo.fileInfoOpt->d_ptr->fileEntry;
|
||||
else
|
||||
fentry = &entryInfo.entry;
|
||||
nativeIterators.emplace(std::make_unique<QFileSystemIterator>(*fentry, filters));
|
||||
nativeIterators.emplace_back(std::make_unique<QFileSystemIterator>(*fentry, filters));
|
||||
#else
|
||||
qWarning("Qt was built with -no-feature-filesystemiterator: no files/plugins will be found!");
|
||||
#endif
|
||||
@ -196,19 +210,18 @@ bool QDirListingPrivate::entryMatches(QDirEntryInfo &entryInfo)
|
||||
|
||||
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.
|
||||
system methods, e.g. readdir() on Unix). The iterators are stored in a
|
||||
vector.
|
||||
|
||||
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
|
||||
- an iterator for B is added to the vector
|
||||
- B's iterator is processed (vector.back()) first; then the loop
|
||||
goes back to processing A's iterator
|
||||
*/
|
||||
void QDirListingPrivate::advance()
|
||||
{
|
||||
// Use get() in both code paths below because the iterator returned by top()
|
||||
// Use get() in both code paths below because the iterator returned by back()
|
||||
// may be invalidated due to reallocation when appending new iterators in
|
||||
// pushDirectory().
|
||||
|
||||
@ -216,7 +229,7 @@ void QDirListingPrivate::advance()
|
||||
while (!fileEngineIterators.empty()) {
|
||||
// Find the next valid iterator that matches the filters.
|
||||
QAbstractFileEngineIterator *it;
|
||||
while (it = fileEngineIterators.top().get(), it->advance()) {
|
||||
while (it = fileEngineIterators.back().get(), it->advance()) {
|
||||
QDirEntryInfo entryInfo;
|
||||
entryInfo.fileInfoOpt = it->currentFileInfo();
|
||||
if (entryMatches(entryInfo)) {
|
||||
@ -225,7 +238,7 @@ void QDirListingPrivate::advance()
|
||||
}
|
||||
}
|
||||
|
||||
fileEngineIterators.pop();
|
||||
fileEngineIterators.pop_back();
|
||||
}
|
||||
} else {
|
||||
#ifndef QT_NO_FILESYSTEMITERATOR
|
||||
@ -233,7 +246,8 @@ void QDirListingPrivate::advance()
|
||||
while (!nativeIterators.empty()) {
|
||||
// Find the next valid iterator that matches the filters.
|
||||
QFileSystemIterator *it;
|
||||
while (it = nativeIterators.top().get(), it->advance(entryInfo.entry, entryInfo.metaData)) {
|
||||
while (it = nativeIterators.back().get(),
|
||||
it->advance(entryInfo.entry, entryInfo.metaData)) {
|
||||
if (entryMatches(entryInfo)) {
|
||||
currentEntryInfo = std::move(entryInfo);
|
||||
return;
|
||||
@ -241,7 +255,7 @@ void QDirListingPrivate::advance()
|
||||
entryInfo = {};
|
||||
}
|
||||
|
||||
nativeIterators.pop();
|
||||
nativeIterators.pop_back();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -498,14 +512,15 @@ QString QDirListing::iteratorPath() const
|
||||
Here's how to find and read all files filtered by name, recursively:
|
||||
\snippet code/src_corelib_io_qdirlisting.cpp 1
|
||||
|
||||
\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).
|
||||
\note This is a forward-only iterator, every time begin()/cbegin() is
|
||||
called (on the same QDirListing object), the internal state is reset and
|
||||
the iteration starts anew.
|
||||
|
||||
\sa fileInfo(), fileName(), filePath()
|
||||
*/
|
||||
QDirListing::const_iterator QDirListing::begin() const
|
||||
{
|
||||
d->beginIterating();
|
||||
const_iterator it{d.get()};
|
||||
return ++it;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user