TreeScanner: Inline scanForFiles() method

Make scanForFiles() a non-template method and hide it
in treescanner.cpp. Inline scanForFilesRecursively().

Change-Id: I10e07f190e1a4a65cd7045c625a364350964afb9
Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
Jarek Kobus
2024-06-19 13:17:11 +02:00
parent 38fc03cc3b
commit 7ffcbe541b
5 changed files with 107 additions and 149 deletions

View File

@@ -140,7 +140,6 @@ add_qtc_plugin(ProjectExplorer
projectmanager.cpp projectmanager.h
projectmodels.cpp projectmodels.h
projectnodes.cpp projectnodes.h
projectnodeshelper.h
projectpanelfactory.cpp projectpanelfactory.h
projectsettingswidget.cpp projectsettingswidget.h
projecttree.cpp projecttree.h

View File

@@ -115,7 +115,6 @@ QtcPlugin {
"projectmanager.cpp", "projectmanager.h",
"projectmodels.cpp", "projectmodels.h",
"projectnodes.cpp", "projectnodes.h",
"projectnodeshelper.h",
"projectpanelfactory.cpp", "projectpanelfactory.h",
"projectsettingswidget.cpp", "projectsettingswidget.h",
"projecttree.cpp",

View File

@@ -1,141 +0,0 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#pragma once
#include "projectnodes.h"
#include <coreplugin/iversioncontrol.h>
#include <coreplugin/vcsmanager.h>
#include <solutions/tasking/tasktreerunner.h>
#include <utils/algorithm.h>
#include <utils/async.h>
#include <utils/filepath.h>
#include <utils/hostosinfo.h>
#include <QPromise>
namespace ProjectExplorer {
namespace Internal {
struct DirectoryScanResult
{
QList<FileNode *> nodes;
Utils::FilePaths subDirectories;
};
static DirectoryScanResult scanForFiles(
const QFuture<void> &future,
const Utils::FilePath &directory,
QDir::Filters filter,
const std::function<FileNode *(const Utils::FilePath &)> &factory,
const QList<Core::IVersionControl *> &versionControls)
{
DirectoryScanResult result;
const Utils::FilePaths entries = directory.dirEntries(filter);
for (const Utils::FilePath &entry : entries) {
if (future.isCanceled())
return result;
if (Utils::anyOf(versionControls, [entry](const Core::IVersionControl *vc) {
return vc->isVcsFileOrDirectory(entry);
})) {
continue;
}
if (entry.isDir())
result.subDirectories.append(entry);
else if (FileNode *node = factory(entry))
result.nodes.append(node);
}
return result;
}
template<typename Result>
QList<FileNode *> scanForFilesRecursively(
QPromise<Result> &promise,
int progressRange,
const Utils::FilePath &directory,
QDir::Filters filter,
const std::function<FileNode *(const Utils::FilePath &)> &factory,
const QList<Core::IVersionControl *> &versionControls)
{
const QFuture<void> future(promise.future());
QSet<Utils::FilePath> visited;
const DirectoryScanResult result
= scanForFiles(future, directory, filter, factory, versionControls);
QList<FileNode *> fileNodes = result.nodes;
const int progressIncrement = int(
progressRange / static_cast<double>(fileNodes.count() + result.subDirectories.count()));
promise.setProgressValue(int(fileNodes.count() * progressIncrement));
QList<QPair<Utils::FilePath, int>> subDirectories;
auto addSubDirectories = [&](const Utils::FilePaths &subdirs, int progressIncrement) {
for (const Utils::FilePath &subdir : subdirs) {
if (Utils::insert(visited, subdir.canonicalPath()))
subDirectories.append(qMakePair(subdir, progressIncrement));
else
promise.setProgressValue(promise.future().progressValue() + progressIncrement);
}
};
addSubDirectories(result.subDirectories, progressIncrement);
while (!subDirectories.isEmpty()) {
using namespace Tasking;
const LoopList iterator(subDirectories);
subDirectories.clear();
auto onSetup = [&, iterator](Utils::Async<DirectoryScanResult> &task) {
task.setConcurrentCallData(
scanForFiles, future, iterator->first, filter, factory, versionControls);
};
auto onDone = [&, iterator](const Utils::Async<DirectoryScanResult> &task) {
const int progressRange = iterator->second;
const DirectoryScanResult result = task.result();
fileNodes.append(result.nodes);
const qsizetype subDirCount = result.subDirectories.count();
if (subDirCount == 0) {
promise.setProgressValue(promise.future().progressValue() + progressRange);
} else {
const qsizetype fileCount = result.nodes.count();
const int increment = int(
progressRange / static_cast<double>(fileCount + subDirCount));
promise.setProgressValue(
promise.future().progressValue() + increment * fileCount);
addSubDirectories(result.subDirectories, increment);
}
};
const Group group{
Utils::HostOsInfo::isLinuxHost() ? parallelLimit(2) : parallelIdealThreadCountLimit,
iterator,
Utils::AsyncTask<DirectoryScanResult>(onSetup, onDone)
};
TaskTree::runBlocking(group);
}
return fileNodes;
}
} // namespace Internal
template<typename Result>
QList<FileNode *> scanForFiles(
QPromise<Result> &promise,
const Utils::FilePath &directory,
QDir::Filters filter,
const std::function<FileNode *(const Utils::FilePath &)> &factory)
{
promise.setProgressRange(0, 1000000);
return Internal::scanForFilesRecursively(promise,
1000000,
directory,
filter,
factory,
Core::VcsManager::versionControls());
}
} // namespace ProjectExplorer

View File

@@ -3,15 +3,17 @@
#include "treescanner.h"
#include "projectnodeshelper.h"
#include "projecttree.h"
#include <coreplugin/iversioncontrol.h>
#include <coreplugin/vcsmanager.h>
#include <utils/async.h>
#include <utils/qtcassert.h>
#include <solutions/tasking/tasktreerunner.h>
#include <utils/algorithm.h>
#include <utils/async.h>
#include <utils/hostosinfo.h>
#include <utils/qtcassert.h>
#include <memory>
@@ -146,14 +148,113 @@ static std::unique_ptr<FolderNode> createFolderNode(const Utils::FilePath &direc
return fileSystemNode;
}
struct DirectoryScanResult
{
QList<FileNode *> nodes;
Utils::FilePaths subDirectories;
};
static DirectoryScanResult scanForFilesImpl(
const QFuture<void> &future,
const Utils::FilePath &directory,
QDir::Filters filter,
const std::function<FileNode *(const Utils::FilePath &)> &factory,
const QList<Core::IVersionControl *> &versionControls)
{
DirectoryScanResult result;
const Utils::FilePaths entries = directory.dirEntries(filter);
for (const Utils::FilePath &entry : entries) {
if (future.isCanceled())
return result;
if (Utils::anyOf(versionControls, [entry](const Core::IVersionControl *vc) {
return vc->isVcsFileOrDirectory(entry);
})) {
continue;
}
if (entry.isDir())
result.subDirectories.append(entry);
else if (FileNode *node = factory(entry))
result.nodes.append(node);
}
return result;
}
static QList<FileNode *> scanForFilesHelper(
TreeScanner::Promise &promise,
const Utils::FilePath &directory,
QDir::Filters filter,
const std::function<FileNode *(const Utils::FilePath &)> &factory)
{
const QFuture<void> future(promise.future());
const int progressRange = 1000000;
const QList<Core::IVersionControl *> &versionControls = Core::VcsManager::versionControls();
promise.setProgressRange(0, progressRange);
QSet<Utils::FilePath> visited;
const DirectoryScanResult result = scanForFilesImpl(future, directory, filter, factory, versionControls);
QList<FileNode *> fileNodes = result.nodes;
const int progressIncrement = int(
progressRange / static_cast<double>(fileNodes.count() + result.subDirectories.count()));
promise.setProgressValue(int(fileNodes.count() * progressIncrement));
QList<QPair<Utils::FilePath, int>> subDirectories;
auto addSubDirectories = [&](const Utils::FilePaths &subdirs, int progressIncrement) {
for (const Utils::FilePath &subdir : subdirs) {
if (Utils::insert(visited, subdir.canonicalPath()))
subDirectories.append(qMakePair(subdir, progressIncrement));
else
promise.setProgressValue(future.progressValue() + progressIncrement);
}
};
addSubDirectories(result.subDirectories, progressIncrement);
while (!subDirectories.isEmpty()) {
using namespace Tasking;
const LoopList iterator(subDirectories);
subDirectories.clear();
auto onSetup = [&, iterator](Utils::Async<DirectoryScanResult> &task) {
task.setConcurrentCallData(
scanForFilesImpl, future, iterator->first, filter, factory, versionControls);
};
auto onDone = [&, iterator](const Utils::Async<DirectoryScanResult> &task) {
const int progressRange = iterator->second;
const DirectoryScanResult result = task.result();
fileNodes.append(result.nodes);
const qsizetype subDirCount = result.subDirectories.count();
if (subDirCount == 0) {
promise.setProgressValue(future.progressValue() + progressRange);
} else {
const qsizetype fileCount = result.nodes.count();
const int increment = int(
progressRange / static_cast<double>(fileCount + subDirCount));
promise.setProgressValue(future.progressValue() + increment * fileCount);
addSubDirectories(result.subDirectories, increment);
}
};
const Group group{
Utils::HostOsInfo::isLinuxHost() ? parallelLimit(2) : parallelIdealThreadCountLimit,
iterator,
Utils::AsyncTask<DirectoryScanResult>(onSetup, onDone)
};
TaskTree::runBlocking(group);
}
return fileNodes;
}
void TreeScanner::scanForFiles(
Promise &promise,
const Utils::FilePath &directory,
const FileFilter &filter,
const QDir::Filters &dirFilter,
QDir::Filters dirFilter,
const FileTypeFactory &factory)
{
QList<FileNode *> nodes = ProjectExplorer::scanForFiles(
QList<FileNode *> nodes = scanForFilesHelper(
promise, directory, dirFilter, [&filter, &factory](const Utils::FilePath &fn) -> FileNode * {
const Utils::MimeType mimeType = Utils::mimeTypesForFileName(fn.path()).value(0);

View File

@@ -75,7 +75,7 @@ private:
static void scanForFiles(Promise &fi,
const Utils::FilePath &directory,
const FileFilter &filter,
const QDir::Filters &dirFilter,
QDir::Filters dirFilter,
const FileTypeFactory &factory);
private: