FileSearch: Move FileIterator to std iterator semantics.

We need this when we want to use QtConcurrent::mappedReduced.

Change-Id: I4a6a31f4a0cc9a739a263cc148a1d51d7aa5d418
Reviewed-by: David Schulz <david.schulz@theqtcompany.com>
This commit is contained in:
Eike Ziller
2015-03-23 15:19:42 +01:00
parent 50fe3585a8
commit 37fb296e72
8 changed files with 173 additions and 82 deletions

View File

@@ -246,8 +246,9 @@ void runFileSearch(QFutureInterface<FileSearchResultList> &future,
QString str; QString str;
QTextStream stream; QTextStream stream;
FileSearchResultList results; FileSearchResultList results;
while (files->hasNext()) { auto end = files->end();
const QString &filePath = files->next(); for (auto it = files->begin(); it != end; ++it) {
const QString &filePath = it->filePath;
if (future.isPaused()) if (future.isPaused())
future.waitForResume(); future.waitForResume();
if (future.isCanceled()) { if (future.isCanceled()) {
@@ -267,7 +268,7 @@ void runFileSearch(QFutureInterface<FileSearchResultList> &future,
continue; continue;
needsToCloseFile = true; needsToCloseFile = true;
stream.setDevice(&file); stream.setDevice(&file);
stream.setCodec(files->encoding()); stream.setCodec(it->encoding);
} }
const FileSearchResultList singleFileResults = searchFunction(filePath, stream); const FileSearchResultList singleFileResults = searchFunction(filePath, stream);
@@ -420,9 +421,8 @@ QString matchCaseReplacement(const QString &originalText, const QString &replace
return replaceText; // mixed return replaceText; // mixed
} }
} }
}
QString Utils::matchCaseReplacement(const QString &originalText, const QString &replaceText) QString matchCaseReplacement(const QString &originalText, const QString &replaceText)
{ {
if (originalText.isEmpty()) if (originalText.isEmpty())
return replaceText; return replaceText;
@@ -451,55 +451,83 @@ QString Utils::matchCaseReplacement(const QString &originalText, const QString &
// #pragma mark -- FileIterator // #pragma mark -- FileIterator
FileIterator::FileIterator() void FileIterator::next(FileIterator::const_iterator *it)
: m_list(QStringList()),
m_iterator(0),
m_index(-1)
{ {
if (it->m_index < 0) // == end
return;
++it->m_index;
update(it->m_index);
if (it->m_index < currentFileCount()) {
it->m_item.filePath = fileAt(it->m_index);
it->m_item.encoding = codecAt(it->m_index);
} else {
it->m_index = -1; // == end
it->m_item.filePath.clear();
it->m_item.encoding = 0;
}
} }
FileIterator::FileIterator(const QStringList &fileList, FileIterator::const_iterator FileIterator::begin()
const QList<QTextCodec *> encodings) {
: m_list(fileList), update(0);
m_iterator(new QStringListIterator(m_list)), if (currentFileCount() == 0)
return end();
return FileIterator::const_iterator(this,
FileIterator::Item(fileAt(0), codecAt(0)),
0/*index*/);
}
FileIterator::const_iterator FileIterator::end()
{
return FileIterator::const_iterator(this, FileIterator::Item(QString(), 0),
-1/*end*/);
}
// #pragma mark -- FileListIterator
FileListIterator::FileListIterator(const QStringList &fileList,
const QList<QTextCodec *> encodings)
: m_files(fileList),
m_encodings(encodings), m_encodings(encodings),
m_index(-1) m_maxIndex(-1)
{ {
} }
FileIterator::~FileIterator() void FileListIterator::update(int requestedIndex)
{ {
if (m_iterator) if (requestedIndex > m_maxIndex)
delete m_iterator; m_maxIndex = requestedIndex;
} }
bool FileIterator::hasNext() const int FileListIterator::currentFileCount() const
{ {
Q_ASSERT(m_iterator); return m_files.size();
return m_iterator->hasNext();
} }
QString FileIterator::next() QString FileListIterator::fileAt(int index) const
{ {
Q_ASSERT(m_iterator); return m_files.at(index);
++m_index;
return m_iterator->next();
} }
int FileIterator::maxProgress() const QTextCodec *FileListIterator::codecAt(int index) const
{ {
return m_list.size(); return m_encodings.at(index);
} }
int FileIterator::currentProgress() const int FileListIterator::maxProgress() const
{ {
return m_index + 1; return m_files.size();
} }
QTextCodec * FileIterator::encoding() const int FileListIterator::currentProgress() const
{ {
if (m_index >= 0 && m_index < m_encodings.size()) return m_maxIndex + 1;
return m_encodings.at(m_index); }
QTextCodec *FileListIterator::encodingAt(int index) const
{
if (index >= 0 && index < m_encodings.size())
return m_encodings.at(index);
return QTextCodec::codecForLocale(); return QTextCodec::codecForLocale();
} }
@@ -524,11 +552,12 @@ SubDirFileIterator::SubDirFileIterator(const QStringList &directories, const QSt
} }
} }
bool SubDirFileIterator::hasNext() const void SubDirFileIterator::update(int index)
{ {
if (!m_currentFiles.isEmpty()) if (index < m_files.size())
return true; return;
while (!m_dirs.isEmpty() && m_currentFiles.isEmpty()) { // collect files from the directories until we have enough for the given index
while (!m_dirs.isEmpty() && index >= m_files.size()) {
QDir dir = m_dirs.pop(); QDir dir = m_dirs.pop();
const qreal dirProgressMax = m_progressValues.pop(); const qreal dirProgressMax = m_progressValues.pop();
const bool processed = m_processedValues.pop(); const bool processed = m_processedValues.pop();
@@ -543,7 +572,7 @@ bool SubDirFileIterator::hasNext() const
it.toBack(); it.toBack();
while (it.hasPrevious()) { while (it.hasPrevious()) {
const QString &file = it.previous(); const QString &file = it.previous();
m_currentFiles.append(dir.path()+ QLatin1Char('/') +file); m_files.append(dir.path()+ QLatin1Char('/') +file);
} }
m_progress += dirProgressMax; m_progress += dirProgressMax;
} else { } else {
@@ -564,18 +593,24 @@ bool SubDirFileIterator::hasNext() const
m_progress += dirProgressMax; m_progress += dirProgressMax;
} }
} }
if (m_currentFiles.isEmpty()) { if (index >= m_files.size())
m_progress = MAX_PROGRESS; m_progress = MAX_PROGRESS;
return false;
}
return true;
} }
QString SubDirFileIterator::next() int SubDirFileIterator::currentFileCount() const
{ {
Q_ASSERT(!m_currentFiles.isEmpty()); return m_files.size();
return m_currentFiles.takeFirst(); }
QString SubDirFileIterator::fileAt(int index) const
{
return m_files.at(index);
}
QTextCodec *SubDirFileIterator::codecAt(int index) const
{
Q_UNUSED(index)
return m_encoding;
} }
int SubDirFileIterator::maxProgress() const int SubDirFileIterator::maxProgress() const
@@ -588,7 +623,4 @@ int SubDirFileIterator::currentProgress() const
return qMin(qRound(m_progress), MAX_PROGRESS); return qMin(qRound(m_progress), MAX_PROGRESS);
} }
QTextCodec * SubDirFileIterator::encoding() const
{
return m_encoding;
} }

View File

@@ -46,24 +46,77 @@ namespace Utils {
class QTCREATOR_UTILS_EXPORT FileIterator class QTCREATOR_UTILS_EXPORT FileIterator
{ {
public: public:
explicit FileIterator(const QStringList &fileList, class Item
const QList<QTextCodec *> encodings); {
virtual ~FileIterator(); public:
Item(const QString &path, QTextCodec *codec)
: filePath(path), encoding(codec)
{}
QString filePath;
QTextCodec *encoding;
};
virtual bool hasNext() const; class const_iterator
virtual QString next(); {
virtual QTextCodec *encoding() const; public:
virtual int maxProgress() const; typedef std::forward_iterator_tag iterator_category;
virtual int currentProgress() const; typedef Item value_type;
typedef std::ptrdiff_t difference_type;
typedef const value_type *pointer;
typedef const value_type &reference;
const_iterator(FileIterator *parent, Item item, int id)
: m_parent(parent), m_item(item), m_index(id)
{}
const Item operator*() const { return m_item; }
const Item *operator->() const { return &m_item; }
void operator++() { m_parent->next(this); }
bool operator==(const const_iterator &other) const
{
return m_parent == other.m_parent && m_index == other.m_index;
}
bool operator!=(const const_iterator &other) const { return !operator==(other); }
FileIterator *m_parent;
Item m_item;
int m_index; // -1 == end
};
virtual ~FileIterator() {}
void next(const_iterator *it);
const_iterator begin();
const_iterator end();
virtual int maxProgress() const = 0;
virtual int currentProgress() const = 0;
protected: protected:
FileIterator(); virtual void update(int requestedIndex) = 0;
virtual int currentFileCount() const = 0;
virtual QString fileAt(int index) const = 0;
virtual QTextCodec *codecAt(int index) const = 0;
};
class QTCREATOR_UTILS_EXPORT FileListIterator : public FileIterator
{
public:
explicit FileListIterator(const QStringList &fileList,
const QList<QTextCodec *> encodings);
int maxProgress() const override;
int currentProgress() const override;
protected:
void update(int requestedIndex) override;
int currentFileCount() const override;
QString fileAt(int index) const override;
QTextCodec *codecAt(int index) const override;
private: private:
QStringList m_list; QTextCodec *encodingAt(int index) const;
QStringListIterator *m_iterator; QStringList m_files;
QList<QTextCodec *> m_encodings; QList<QTextCodec *> m_encodings;
int m_index; int m_maxIndex;
}; };
class QTCREATOR_UTILS_EXPORT SubDirFileIterator : public FileIterator class QTCREATOR_UTILS_EXPORT SubDirFileIterator : public FileIterator
@@ -72,20 +125,23 @@ public:
SubDirFileIterator(const QStringList &directories, const QStringList &filters, SubDirFileIterator(const QStringList &directories, const QStringList &filters,
QTextCodec *encoding = 0); QTextCodec *encoding = 0);
bool hasNext() const; int maxProgress() const override;
QString next(); int currentProgress() const override;
QTextCodec *encoding() const;
int maxProgress() const; protected:
int currentProgress() const; void update(int requestedIndex) override;
int currentFileCount() const override;
QString fileAt(int index) const override;
QTextCodec *codecAt(int index) const override;
private: private:
QStringList m_filters; QStringList m_filters;
QTextCodec *m_encoding; QTextCodec *m_encoding;
mutable QStack<QDir> m_dirs; QStack<QDir> m_dirs;
mutable QStack<qreal> m_progressValues; QStack<qreal> m_progressValues;
mutable QStack<bool> m_processedValues; QStack<bool> m_processedValues;
mutable qreal m_progress; qreal m_progress;
mutable QStringList m_currentFiles; QStringList m_files;
}; };
class QTCREATOR_UTILS_EXPORT FileSearchResult class QTCREATOR_UTILS_EXPORT FileSearchResult

View File

@@ -190,14 +190,17 @@ void DirectoryFilter::refresh(QFutureInterface<void> &future)
} }
directories = m_directories; directories = m_directories;
} }
Utils::SubDirFileIterator it(directories, m_filters); Utils::SubDirFileIterator subDirIterator(directories, m_filters);
future.setProgressRange(0, it.maxProgress()); future.setProgressRange(0, subDirIterator.maxProgress());
QStringList filesFound; QStringList filesFound;
while (!future.isCanceled() && it.hasNext()) { auto end = subDirIterator.end();
filesFound << it.next(); for (auto it = subDirIterator.begin(); it != end; ++it) {
if (future.isCanceled())
break;
filesFound << (*it).filePath;
if (future.isProgressUpdateNeeded() if (future.isProgressUpdateNeeded()
|| future.progressValue() == 0 /*workaround for regression in Qt*/) { || future.progressValue() == 0 /*workaround for regression in Qt*/) {
future.setProgressValueAndText(it.currentProgress(), future.setProgressValueAndText(subDirIterator.currentProgress(),
tr("%1 filter update: %n files", 0, filesFound.size()).arg(displayName())); tr("%1 filter update: %n files", 0, filesFound.size()).arg(displayName()));
} }
} }
@@ -206,8 +209,8 @@ void DirectoryFilter::refresh(QFutureInterface<void> &future)
QMutexLocker locker(&m_lock); QMutexLocker locker(&m_lock);
m_files = filesFound; m_files = filesFound;
QTimer::singleShot(0, this, SLOT(updateFileIterator())); QTimer::singleShot(0, this, SLOT(updateFileIterator()));
future.setProgressValue(it.maxProgress()); future.setProgressValue(subDirIterator.maxProgress());
} else { } else {
future.setProgressValueAndText(it.currentProgress(), tr("%1 filter update: canceled").arg(displayName())); future.setProgressValueAndText(subDirIterator.currentProgress(), tr("%1 filter update: canceled").arg(displayName()));
} }
} }

View File

@@ -114,7 +114,7 @@ Utils::FileIterator *AllProjectsFind::filesForProjects(const QStringList &nameFi
encodings.insert(fileName, codec); encodings.insert(fileName, codec);
} }
} }
return new Utils::FileIterator(encodings.keys(), encodings.values()); return new Utils::FileListIterator(encodings.keys(), encodings.values());
} }
QVariant AllProjectsFind::additionalParameters() const QVariant AllProjectsFind::additionalParameters() const

View File

@@ -91,13 +91,13 @@ Utils::FileIterator *CurrentProjectFind::files(const QStringList &nameFilters,
const QVariant &additionalParameters) const const QVariant &additionalParameters) const
{ {
QTC_ASSERT(additionalParameters.isValid(), QTC_ASSERT(additionalParameters.isValid(),
return new Utils::FileIterator(QStringList(), QList<QTextCodec *>())); return new Utils::FileListIterator(QStringList(), QList<QTextCodec *>()));
QString projectFile = additionalParameters.toString(); QString projectFile = additionalParameters.toString();
foreach (Project *project, SessionManager::projects()) { foreach (Project *project, SessionManager::projects()) {
if (project->document() && projectFile == project->projectFilePath().toString()) if (project->document() && projectFile == project->projectFilePath().toString())
return filesForProjects(nameFilters, QList<Project *>() << project); return filesForProjects(nameFilters, QList<Project *>() << project);
} }
return new Utils::FileIterator(QStringList(), QList<QTextCodec *>()); return new Utils::FileListIterator(QStringList(), QList<QTextCodec *>());
} }
QString CurrentProjectFind::label() const QString CurrentProjectFind::label() const

View File

@@ -70,7 +70,7 @@ Utils::FileIterator *FindInCurrentFile::files(const QStringList &nameFilters,
QTextCodec *codec = openEditorEncodings.value(fileName); QTextCodec *codec = openEditorEncodings.value(fileName);
if (!codec) if (!codec)
codec = Core::EditorManager::defaultTextCodec(); codec = Core::EditorManager::defaultTextCodec();
return new Utils::FileIterator(QStringList() << fileName, QList<QTextCodec *>() << codec); return new Utils::FileListIterator(QStringList(fileName), QList<QTextCodec *>() << codec);
} }
QVariant FindInCurrentFile::additionalParameters() const QVariant FindInCurrentFile::additionalParameters() const

View File

@@ -81,7 +81,7 @@ Utils::FileIterator *FindInOpenFiles::files(const QStringList &nameFilters,
} }
} }
return new Utils::FileIterator(fileNames, codecs); return new Utils::FileListIterator(fileNames, codecs);
} }
QVariant FindInOpenFiles::additionalParameters() const QVariant FindInOpenFiles::additionalParameters() const

View File

@@ -67,7 +67,7 @@ namespace {
const QString &term, const QString &term,
QTextDocument::FindFlags flags, tst_FileSearch::RegExpFlag regexp = tst_FileSearch::NoRegExp) QTextDocument::FindFlags flags, tst_FileSearch::RegExpFlag regexp = tst_FileSearch::NoRegExp)
{ {
Utils::FileIterator *it = new Utils::FileIterator(QStringList() << QLatin1String(FILENAME), QList<QTextCodec *>() << QTextCodec::codecForLocale()); Utils::FileIterator *it = new Utils::FileListIterator(QStringList(QLatin1String(FILENAME)), QList<QTextCodec *>() << QTextCodec::codecForLocale());
QFutureWatcher<Utils::FileSearchResultList> watcher; QFutureWatcher<Utils::FileSearchResultList> watcher;
QSignalSpy ready(&watcher, SIGNAL(resultsReadyAt(int,int))); QSignalSpy ready(&watcher, SIGNAL(resultsReadyAt(int,int)));
if (regexp == tst_FileSearch::NoRegExp) if (regexp == tst_FileSearch::NoRegExp)