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;
QTextStream stream;
FileSearchResultList results;
while (files->hasNext()) {
const QString &filePath = files->next();
auto end = files->end();
for (auto it = files->begin(); it != end; ++it) {
const QString &filePath = it->filePath;
if (future.isPaused())
future.waitForResume();
if (future.isCanceled()) {
@@ -267,7 +268,7 @@ void runFileSearch(QFutureInterface<FileSearchResultList> &future,
continue;
needsToCloseFile = true;
stream.setDevice(&file);
stream.setCodec(files->encoding());
stream.setCodec(it->encoding);
}
const FileSearchResultList singleFileResults = searchFunction(filePath, stream);
@@ -420,9 +421,8 @@ QString matchCaseReplacement(const QString &originalText, const QString &replace
return replaceText; // mixed
}
}
}
QString Utils::matchCaseReplacement(const QString &originalText, const QString &replaceText)
QString matchCaseReplacement(const QString &originalText, const QString &replaceText)
{
if (originalText.isEmpty())
return replaceText;
@@ -451,55 +451,83 @@ QString Utils::matchCaseReplacement(const QString &originalText, const QString &
// #pragma mark -- FileIterator
FileIterator::FileIterator()
: m_list(QStringList()),
m_iterator(0),
m_index(-1)
void FileIterator::next(FileIterator::const_iterator *it)
{
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,
const QList<QTextCodec *> encodings)
: m_list(fileList),
m_iterator(new QStringListIterator(m_list)),
FileIterator::const_iterator FileIterator::begin()
{
update(0);
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_index(-1)
m_maxIndex(-1)
{
}
FileIterator::~FileIterator()
void FileListIterator::update(int requestedIndex)
{
if (m_iterator)
delete m_iterator;
if (requestedIndex > m_maxIndex)
m_maxIndex = requestedIndex;
}
bool FileIterator::hasNext() const
int FileListIterator::currentFileCount() const
{
Q_ASSERT(m_iterator);
return m_iterator->hasNext();
return m_files.size();
}
QString FileIterator::next()
QString FileListIterator::fileAt(int index) const
{
Q_ASSERT(m_iterator);
++m_index;
return m_iterator->next();
return m_files.at(index);
}
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_encodings.at(m_index);
return m_maxIndex + 1;
}
QTextCodec *FileListIterator::encodingAt(int index) const
{
if (index >= 0 && index < m_encodings.size())
return m_encodings.at(index);
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())
return true;
while (!m_dirs.isEmpty() && m_currentFiles.isEmpty()) {
if (index < m_files.size())
return;
// 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();
const qreal dirProgressMax = m_progressValues.pop();
const bool processed = m_processedValues.pop();
@@ -543,7 +572,7 @@ bool SubDirFileIterator::hasNext() const
it.toBack();
while (it.hasPrevious()) {
const QString &file = it.previous();
m_currentFiles.append(dir.path()+ QLatin1Char('/') +file);
m_files.append(dir.path()+ QLatin1Char('/') +file);
}
m_progress += dirProgressMax;
} else {
@@ -564,18 +593,24 @@ bool SubDirFileIterator::hasNext() const
m_progress += dirProgressMax;
}
}
if (m_currentFiles.isEmpty()) {
if (index >= m_files.size())
m_progress = MAX_PROGRESS;
return false;
}
return true;
}
QString SubDirFileIterator::next()
int SubDirFileIterator::currentFileCount() const
{
Q_ASSERT(!m_currentFiles.isEmpty());
return m_currentFiles.takeFirst();
return m_files.size();
}
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
@@ -588,7 +623,4 @@ int SubDirFileIterator::currentProgress() const
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
{
public:
explicit FileIterator(const QStringList &fileList,
const QList<QTextCodec *> encodings);
virtual ~FileIterator();
class Item
{
public:
Item(const QString &path, QTextCodec *codec)
: filePath(path), encoding(codec)
{}
QString filePath;
QTextCodec *encoding;
};
virtual bool hasNext() const;
virtual QString next();
virtual QTextCodec *encoding() const;
virtual int maxProgress() const;
virtual int currentProgress() const;
class const_iterator
{
public:
typedef std::forward_iterator_tag iterator_category;
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:
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:
QStringList m_list;
QStringListIterator *m_iterator;
QTextCodec *encodingAt(int index) const;
QStringList m_files;
QList<QTextCodec *> m_encodings;
int m_index;
int m_maxIndex;
};
class QTCREATOR_UTILS_EXPORT SubDirFileIterator : public FileIterator
@@ -72,20 +125,23 @@ public:
SubDirFileIterator(const QStringList &directories, const QStringList &filters,
QTextCodec *encoding = 0);
bool hasNext() const;
QString next();
QTextCodec *encoding() const;
int maxProgress() const;
int currentProgress() const;
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:
QStringList m_filters;
QTextCodec *m_encoding;
mutable QStack<QDir> m_dirs;
mutable QStack<qreal> m_progressValues;
mutable QStack<bool> m_processedValues;
mutable qreal m_progress;
mutable QStringList m_currentFiles;
QStack<QDir> m_dirs;
QStack<qreal> m_progressValues;
QStack<bool> m_processedValues;
qreal m_progress;
QStringList m_files;
};
class QTCREATOR_UTILS_EXPORT FileSearchResult

View File

@@ -190,14 +190,17 @@ void DirectoryFilter::refresh(QFutureInterface<void> &future)
}
directories = m_directories;
}
Utils::SubDirFileIterator it(directories, m_filters);
future.setProgressRange(0, it.maxProgress());
Utils::SubDirFileIterator subDirIterator(directories, m_filters);
future.setProgressRange(0, subDirIterator.maxProgress());
QStringList filesFound;
while (!future.isCanceled() && it.hasNext()) {
filesFound << it.next();
auto end = subDirIterator.end();
for (auto it = subDirIterator.begin(); it != end; ++it) {
if (future.isCanceled())
break;
filesFound << (*it).filePath;
if (future.isProgressUpdateNeeded()
|| 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()));
}
}
@@ -206,8 +209,8 @@ void DirectoryFilter::refresh(QFutureInterface<void> &future)
QMutexLocker locker(&m_lock);
m_files = filesFound;
QTimer::singleShot(0, this, SLOT(updateFileIterator()));
future.setProgressValue(it.maxProgress());
future.setProgressValue(subDirIterator.maxProgress());
} 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);
}
}
return new Utils::FileIterator(encodings.keys(), encodings.values());
return new Utils::FileListIterator(encodings.keys(), encodings.values());
}
QVariant AllProjectsFind::additionalParameters() const

View File

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

View File

@@ -70,7 +70,7 @@ Utils::FileIterator *FindInCurrentFile::files(const QStringList &nameFilters,
QTextCodec *codec = openEditorEncodings.value(fileName);
if (!codec)
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

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

View File

@@ -67,7 +67,7 @@ namespace {
const QString &term,
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;
QSignalSpy ready(&watcher, SIGNAL(resultsReadyAt(int,int)));
if (regexp == tst_FileSearch::NoRegExp)