diff --git a/src/libs/utils/filesearch.cpp b/src/libs/utils/filesearch.cpp index 0219f73d101..a6faf567be6 100644 --- a/src/libs/utils/filesearch.cpp +++ b/src/libs/utils/filesearch.cpp @@ -246,8 +246,9 @@ void runFileSearch(QFutureInterface &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 &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 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 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; } diff --git a/src/libs/utils/filesearch.h b/src/libs/utils/filesearch.h index e77c4887fde..bf827d0c274 100644 --- a/src/libs/utils/filesearch.h +++ b/src/libs/utils/filesearch.h @@ -46,24 +46,77 @@ namespace Utils { class QTCREATOR_UTILS_EXPORT FileIterator { public: - explicit FileIterator(const QStringList &fileList, - const QList 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 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 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 m_dirs; - mutable QStack m_progressValues; - mutable QStack m_processedValues; - mutable qreal m_progress; - mutable QStringList m_currentFiles; + QStack m_dirs; + QStack m_progressValues; + QStack m_processedValues; + qreal m_progress; + QStringList m_files; }; class QTCREATOR_UTILS_EXPORT FileSearchResult diff --git a/src/plugins/coreplugin/locator/directoryfilter.cpp b/src/plugins/coreplugin/locator/directoryfilter.cpp index 019c99033bf..a9b2accfdd7 100644 --- a/src/plugins/coreplugin/locator/directoryfilter.cpp +++ b/src/plugins/coreplugin/locator/directoryfilter.cpp @@ -190,14 +190,17 @@ void DirectoryFilter::refresh(QFutureInterface &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 &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())); } } diff --git a/src/plugins/projectexplorer/allprojectsfind.cpp b/src/plugins/projectexplorer/allprojectsfind.cpp index 5a01c34f028..c038137f7fd 100644 --- a/src/plugins/projectexplorer/allprojectsfind.cpp +++ b/src/plugins/projectexplorer/allprojectsfind.cpp @@ -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 diff --git a/src/plugins/projectexplorer/currentprojectfind.cpp b/src/plugins/projectexplorer/currentprojectfind.cpp index 876ab96d005..352ef755305 100644 --- a/src/plugins/projectexplorer/currentprojectfind.cpp +++ b/src/plugins/projectexplorer/currentprojectfind.cpp @@ -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())); + return new Utils::FileListIterator(QStringList(), QList())); QString projectFile = additionalParameters.toString(); foreach (Project *project, SessionManager::projects()) { if (project->document() && projectFile == project->projectFilePath().toString()) return filesForProjects(nameFilters, QList() << project); } - return new Utils::FileIterator(QStringList(), QList()); + return new Utils::FileListIterator(QStringList(), QList()); } QString CurrentProjectFind::label() const diff --git a/src/plugins/texteditor/findincurrentfile.cpp b/src/plugins/texteditor/findincurrentfile.cpp index c68b459c0cc..da18ab7b441 100644 --- a/src/plugins/texteditor/findincurrentfile.cpp +++ b/src/plugins/texteditor/findincurrentfile.cpp @@ -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() << codec); + return new Utils::FileListIterator(QStringList(fileName), QList() << codec); } QVariant FindInCurrentFile::additionalParameters() const diff --git a/src/plugins/texteditor/findinopenfiles.cpp b/src/plugins/texteditor/findinopenfiles.cpp index 200dd192346..3e2a63c6fe3 100644 --- a/src/plugins/texteditor/findinopenfiles.cpp +++ b/src/plugins/texteditor/findinopenfiles.cpp @@ -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 diff --git a/tests/auto/filesearch/tst_filesearch.cpp b/tests/auto/filesearch/tst_filesearch.cpp index 9e17923db33..908cbb97231 100644 --- a/tests/auto/filesearch/tst_filesearch.cpp +++ b/tests/auto/filesearch/tst_filesearch.cpp @@ -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::codecForLocale()); + Utils::FileIterator *it = new Utils::FileListIterator(QStringList(QLatin1String(FILENAME)), QList() << QTextCodec::codecForLocale()); QFutureWatcher watcher; QSignalSpy ready(&watcher, SIGNAL(resultsReadyAt(int,int))); if (regexp == tst_FileSearch::NoRegExp)