QmlDesigner: Modernize project storage watcher and file status cache

Change-Id: Ia46d87803a74ebec7b7cc078115dd0bbbd02ec4d
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Marco Bubke
2025-03-22 14:50:10 +01:00
parent 0a7cc8e06e
commit 6a11b1bc58
5 changed files with 105 additions and 182 deletions

View File

@@ -24,9 +24,7 @@ public:
void addSourceContextId(SourceContextId sourceContextId) void addSourceContextId(SourceContextId sourceContextId)
{ {
auto found = std::lower_bound(m_sourceContextIds.begin(), auto found = std::ranges::lower_bound(m_sourceContextIds, sourceContextId);
m_sourceContextIds.end(),
sourceContextId);
if (found == m_sourceContextIds.end() || *found != sourceContextId) if (found == m_sourceContextIds.end() || *found != sourceContextId)
m_sourceContextIds.insert(found, sourceContextId); m_sourceContextIds.insert(found, sourceContextId);

View File

@@ -25,24 +25,9 @@ public:
&& first.lastModified == second.lastModified; && first.lastModified == second.lastModified;
} }
friend bool operator!=(const FileStatus &first, const FileStatus &second) friend auto operator<=>(const FileStatus &first, const FileStatus &second)
{ {
return !(first == second); return first.sourceId <=> second.sourceId;
}
friend bool operator<(const FileStatus &first, const FileStatus &second)
{
return first.sourceId < second.sourceId;
}
friend bool operator<(SourceId first, const FileStatus &second)
{
return first < second.sourceId;
}
friend bool operator<(const FileStatus &first, SourceId second)
{
return first.sourceId < second;
} }
bool isExisting() const { return sourceId && size >= 0 && lastModified >= 0; } bool isExisting() const { return sourceId && size >= 0 && lastModified >= 0; }

View File

@@ -24,12 +24,7 @@ long long FileStatusCache::fileSize(SourceId sourceId) const
void FileStatusCache::update(SourceId sourceId) void FileStatusCache::update(SourceId sourceId)
{ {
auto found = std::lower_bound(m_cacheEntries.begin(), auto found = std::ranges::lower_bound(m_cacheEntries, sourceId, {}, &FileStatus::sourceId);
m_cacheEntries.end(),
sourceId,
[](const auto &first, const auto &second) {
return first < second;
});
if (found != m_cacheEntries.end() && found->sourceId == sourceId) if (found != m_cacheEntries.end() && found->sourceId == sourceId)
*found = m_fileSystem.fileStatus(sourceId); *found = m_fileSystem.fileStatus(sourceId);
@@ -37,13 +32,12 @@ void FileStatusCache::update(SourceId sourceId)
void FileStatusCache::update(SourceIds sourceIds) void FileStatusCache::update(SourceIds sourceIds)
{ {
std::set_intersection(m_cacheEntries.begin(), Utils::set_greedy_intersection(
m_cacheEntries.end(), m_cacheEntries,
sourceIds.begin(), sourceIds,
sourceIds.end(), [&](auto &entry) { entry = m_fileSystem.fileStatus(entry.sourceId); },
Utils::make_iterator([&](auto &entry) { {},
entry = m_fileSystem.fileStatus(entry.sourceId); &FileStatus::sourceId);
}));
} }
SourceIds FileStatusCache::modified(SourceIds sourceIds) const SourceIds FileStatusCache::modified(SourceIds sourceIds) const
@@ -51,44 +45,43 @@ SourceIds FileStatusCache::modified(SourceIds sourceIds) const
SourceIds modifiedSourceIds; SourceIds modifiedSourceIds;
modifiedSourceIds.reserve(sourceIds.size()); modifiedSourceIds.reserve(sourceIds.size());
std::set_intersection(m_cacheEntries.begin(), Utils::set_greedy_intersection(
m_cacheEntries.end(), m_cacheEntries,
sourceIds.begin(), sourceIds,
sourceIds.end(), [&](auto &entry) {
Utils::make_iterator([&](auto &entry) { auto fileStatus = m_fileSystem.fileStatus(entry.sourceId);
auto fileStatus = m_fileSystem.fileStatus(entry.sourceId); if (fileStatus != entry) {
if (fileStatus != entry) { modifiedSourceIds.push_back(entry.sourceId);
modifiedSourceIds.push_back(entry.sourceId); entry = fileStatus;
entry = fileStatus; }
} },
})); {},
&FileStatus::sourceId);
FileStatuses newEntries; FileStatuses newEntries;
newEntries.reserve(sourceIds.size()); newEntries.reserve(sourceIds.size());
std::set_difference(sourceIds.begin(), Utils::set_greedy_difference(
sourceIds.end(), sourceIds,
m_cacheEntries.begin(), m_cacheEntries,
m_cacheEntries.end(), [&](SourceId newSourceId) {
Utils::make_iterator([&](SourceId newSourceId) { newEntries.push_back(m_fileSystem.fileStatus(newSourceId));
newEntries.push_back(m_fileSystem.fileStatus(newSourceId)); modifiedSourceIds.push_back(newSourceId);
modifiedSourceIds.push_back(newSourceId); },
})); {},
{},
&FileStatus::sourceId);
if (newEntries.size()) { if (newEntries.size()) {
FileStatuses mergedEntries; FileStatuses mergedEntries;
mergedEntries.reserve(m_cacheEntries.size() + newEntries.size()); mergedEntries.reserve(m_cacheEntries.size() + newEntries.size());
std::set_union(newEntries.begin(), std::ranges::set_union(newEntries, m_cacheEntries, std::back_inserter(mergedEntries));
newEntries.end(),
m_cacheEntries.begin(),
m_cacheEntries.end(),
std::back_inserter(mergedEntries));
m_cacheEntries = std::move(mergedEntries); m_cacheEntries = std::move(mergedEntries);
} }
std::sort(modifiedSourceIds.begin(), modifiedSourceIds.end()); std::ranges::sort(modifiedSourceIds);
return modifiedSourceIds; return modifiedSourceIds;
} }
@@ -100,12 +93,7 @@ FileStatusCache::size_type FileStatusCache::size() const
const FileStatus &FileStatusCache::find(SourceId sourceId) const const FileStatus &FileStatusCache::find(SourceId sourceId) const
{ {
auto found = std::lower_bound(m_cacheEntries.begin(), auto found = std::ranges::lower_bound(m_cacheEntries, sourceId, {}, &FileStatus::sourceId);
m_cacheEntries.end(),
sourceId,
[](const auto &first, const auto &second) {
return first < second;
});
if (found != m_cacheEntries.end() && found->sourceId == sourceId) if (found != m_cacheEntries.end() && found->sourceId == sourceId)
return *found; return *found;

View File

@@ -13,27 +13,12 @@
#include <sourcepathstorage/storagecache.h> #include <sourcepathstorage/storagecache.h>
#include <utils/algorithm.h> #include <utils/algorithm.h>
#include <utils/set_algorithm.h>
#include <QTimer> #include <QTimer>
namespace QmlDesigner { namespace QmlDesigner {
template<class InputIt1, class InputIt2, class Callable>
void set_greedy_intersection_call(
InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, Callable callable)
{
while (first1 != last1 && first2 != last2) {
if (*first1 < *first2) {
++first1;
} else {
if (*first2 < *first1)
++first2;
else
callable(*first1++);
}
}
}
template<typename FileSystemWatcher, typename Timer, class SourcePathCache> template<typename FileSystemWatcher, typename Timer, class SourcePathCache>
class ProjectStoragePathWatcher : public ProjectStoragePathWatcherInterface, class ProjectStoragePathWatcher : public ProjectStoragePathWatcherInterface,
public ProjectStorageTriggerUpdateInterface public ProjectStorageTriggerUpdateInterface
@@ -63,7 +48,7 @@ public:
addEntries(entires); addEntries(entires);
auto notContainsdId = [&, &ids = ids](WatcherEntry entry) { auto notContainsdId = [&, &ids = ids](WatcherEntry entry) {
return !std::binary_search(ids.begin(), ids.end(), entry.id); return !std::ranges::binary_search(ids, entry.id);
}; };
removeUnusedEntries(entires, notContainsdId); removeUnusedEntries(entires, notContainsdId);
} }
@@ -76,10 +61,8 @@ public:
addEntries(entires); addEntries(entires);
auto notContainsId = [&, &ids = ids](WatcherEntry entry) { auto notContainsId = [&, &ids = ids](WatcherEntry entry) {
return !std::binary_search(ids.begin(), ids.end(), entry.id) return !std::ranges::binary_search(ids, entry.id)
|| !std::binary_search(sourceContextIds.begin(), || !std::ranges::binary_search(sourceContextIds, entry.sourceContextId);
sourceContextIds.end(),
entry.sourceContextId);
}; };
removeUnusedEntries(entires, notContainsId); removeUnusedEntries(entires, notContainsId);
@@ -126,28 +109,22 @@ public:
ProjectChunkIds ids; ProjectChunkIds ids;
ids.reserve(ids.size()); ids.reserve(ids.size());
auto outputIterator = std::back_inserter(entries);
for (const IdPaths &idPath : idPaths) for (const IdPaths &idPath : idPaths)
{ {
ProjectChunkId id = idPath.id; ProjectChunkId id = idPath.id;
ids.push_back(id); ids.push_back(id);
outputIterator = std::transform(idPath.sourceIds.begin(), std::ranges::transform(idPath.sourceIds, std::back_inserter(entries), [&](SourceId sourceId) {
idPath.sourceIds.end(), return WatcherEntry{id,
outputIterator, sourceId.contextId(),
[&](SourceId sourceId) { sourceId,
return WatcherEntry{id, m_fileStatusCache.lastModifiedTime(sourceId)};
sourceId.contextId(), });
sourceId,
m_fileStatusCache.lastModifiedTime(
sourceId)};
});
} }
std::sort(entries.begin(), entries.end()); std::ranges::sort(entries);
std::sort(ids.begin(), ids.end()); std::ranges::sort(ids);
return {entries, ids}; return {entries, ids};
} }
@@ -191,9 +168,9 @@ public:
SourceContextIds sourceContextIds = Utils::transform<SourceContextIds>( SourceContextIds sourceContextIds = Utils::transform<SourceContextIds>(
watcherEntries, &WatcherEntry::sourceContextId); watcherEntries, &WatcherEntry::sourceContextId);
std::sort(sourceContextIds.begin(), sourceContextIds.end()); std::ranges::sort(sourceContextIds);
sourceContextIds.erase(std::unique(sourceContextIds.begin(), sourceContextIds.end()), auto removed = std::ranges::unique(sourceContextIds);
sourceContextIds.end()); sourceContextIds.erase(removed.begin(), removed.end());
return convertWatcherEntriesToDirectoryPathList(sourceContextIds); return convertWatcherEntriesToDirectoryPathList(sourceContextIds);
} }
@@ -203,11 +180,7 @@ public:
WatcherEntries notWatchedEntries; WatcherEntries notWatchedEntries;
notWatchedEntries.reserve(entries.size()); notWatchedEntries.reserve(entries.size());
std::set_difference(entries.begin(), std::ranges::set_difference(entries, m_watchedEntries, std::back_inserter(notWatchedEntries));
entries.end(),
m_watchedEntries.cbegin(),
m_watchedEntries.cend(),
std::back_inserter(notWatchedEntries));
return notWatchedEntries; return notWatchedEntries;
} }
@@ -217,11 +190,7 @@ public:
SourceContextIds notWatchedDirectoryIds; SourceContextIds notWatchedDirectoryIds;
notWatchedDirectoryIds.reserve(ids.size()); notWatchedDirectoryIds.reserve(ids.size());
std::set_difference(ids.begin(), std::ranges::set_difference(ids, m_watchedEntries, std::back_inserter(notWatchedDirectoryIds));
ids.end(),
m_watchedEntries.cbegin(),
m_watchedEntries.cend(),
std::back_inserter(notWatchedDirectoryIds));
return notWatchedDirectoryIds; return notWatchedDirectoryIds;
} }
@@ -232,12 +201,10 @@ public:
WatcherEntries notAnymoreWatchedEntries; WatcherEntries notAnymoreWatchedEntries;
notAnymoreWatchedEntries.reserve(m_watchedEntries.size()); notAnymoreWatchedEntries.reserve(m_watchedEntries.size());
std::set_difference(m_watchedEntries.cbegin(), std::ranges::set_difference(m_watchedEntries,
m_watchedEntries.cend(), newEntries,
newEntries.begin(), std::back_inserter(notAnymoreWatchedEntries),
newEntries.end(), compare);
std::back_inserter(notAnymoreWatchedEntries),
compare);
return notAnymoreWatchedEntries; return notAnymoreWatchedEntries;
} }
@@ -245,11 +212,9 @@ public:
template<typename Filter> template<typename Filter>
WatcherEntries notAnymoreWatchedEntriesWithIds(const WatcherEntries &newEntries, Filter filter) const WatcherEntries notAnymoreWatchedEntriesWithIds(const WatcherEntries &newEntries, Filter filter) const
{ {
auto oldEntries = notAnymoreWatchedEntries(newEntries, std::less<WatcherEntry>()); auto oldEntries = notAnymoreWatchedEntries(newEntries, std::ranges::less{});
auto newEnd = std::remove_if(oldEntries.begin(), oldEntries.end(), filter); std::erase_if(oldEntries, filter);
oldEntries.erase(newEnd, oldEntries.end());
return oldEntries; return oldEntries;
} }
@@ -259,11 +224,7 @@ public:
WatcherEntries newWatchedEntries; WatcherEntries newWatchedEntries;
newWatchedEntries.reserve(m_watchedEntries.size() + newEntries.size()); newWatchedEntries.reserve(m_watchedEntries.size() + newEntries.size());
std::merge(m_watchedEntries.cbegin(), std::ranges::merge(m_watchedEntries, newEntries, std::back_inserter(newWatchedEntries));
m_watchedEntries.cend(),
newEntries.begin(),
newEntries.end(),
std::back_inserter(newWatchedEntries));
m_watchedEntries = std::move(newWatchedEntries); m_watchedEntries = std::move(newWatchedEntries);
} }
@@ -273,14 +234,10 @@ public:
SourceContextIds uniqueDirectoryIds; SourceContextIds uniqueDirectoryIds;
uniqueDirectoryIds.reserve(pathEntries.size()); uniqueDirectoryIds.reserve(pathEntries.size());
auto compare = [](WatcherEntry first, WatcherEntry second) { std::ranges::unique_copy(pathEntries,
return first.sourceContextId == second.sourceContextId; std::back_inserter(uniqueDirectoryIds),
}; {},
&WatcherEntry::sourceContextId);
std::unique_copy(pathEntries.begin(),
pathEntries.end(),
std::back_inserter(uniqueDirectoryIds),
compare);
return uniqueDirectoryIds; return uniqueDirectoryIds;
} }
@@ -294,15 +251,13 @@ public:
WatcherEntries removeIdsFromWatchedEntries(const ProjectPartIds &ids) WatcherEntries removeIdsFromWatchedEntries(const ProjectPartIds &ids)
{ {
auto keep = [&](WatcherEntry entry) { auto keep = [&](WatcherEntry entry) { return !std::ranges::binary_search(ids, entry.id.id); };
return !std::binary_search(ids.begin(), ids.end(), entry.id);
};
auto found = std::stable_partition(m_watchedEntries.begin(), m_watchedEntries.end(), keep); auto removed = std::ranges::stable_partition(m_watchedEntries, keep);
WatcherEntries removedEntries(found, m_watchedEntries.end()); WatcherEntries removedEntries(removed.begin(), removed.end());
m_watchedEntries.erase(found, m_watchedEntries.end()); m_watchedEntries.erase(removed.begin(), removed.end());
return removedEntries; return removedEntries;
} }
@@ -312,11 +267,9 @@ public:
WatcherEntries newWatchedEntries; WatcherEntries newWatchedEntries;
newWatchedEntries.reserve(m_watchedEntries.size() - oldEntries.size()); newWatchedEntries.reserve(m_watchedEntries.size() - oldEntries.size());
std::set_difference(m_watchedEntries.cbegin(), std::ranges::set_difference(m_watchedEntries,
m_watchedEntries.cend(), oldEntries,
oldEntries.begin(), std::back_inserter(newWatchedEntries));
oldEntries.end(),
std::back_inserter(newWatchedEntries));
m_watchedEntries = std::move(newWatchedEntries); m_watchedEntries = std::move(newWatchedEntries);
} }
@@ -332,19 +285,19 @@ public:
WatcherEntries foundEntries; WatcherEntries foundEntries;
foundEntries.reserve(m_watchedEntries.size()); foundEntries.reserve(m_watchedEntries.size());
set_greedy_intersection_call(m_watchedEntries.begin(), Utils::set_greedy_intersection(
m_watchedEntries.end(), m_watchedEntries,
sourceContextIds.begin(), sourceContextIds,
sourceContextIds.end(), [&](WatcherEntry &entry) {
[&](WatcherEntry &entry) { m_fileStatusCache.update(entry.sourceId);
m_fileStatusCache.update(entry.sourceId); auto currentLastModified = m_fileStatusCache.lastModifiedTime(entry.sourceId);
auto currentLastModified = m_fileStatusCache.lastModifiedTime( if (entry.lastModified < currentLastModified) {
entry.sourceId); foundEntries.push_back(entry);
if (entry.lastModified < currentLastModified) { entry.lastModified = currentLastModified;
foundEntries.push_back(entry); }
entry.lastModified = currentLastModified; },
} {},
}); &WatcherEntry::sourceContextId);
return foundEntries; return foundEntries;
} }
@@ -353,26 +306,31 @@ public:
{ {
auto sourceIds = Utils::transform<SourceIds>(entries, &WatcherEntry::sourceId); auto sourceIds = Utils::transform<SourceIds>(entries, &WatcherEntry::sourceId);
std::sort(sourceIds.begin(), sourceIds.end()); std::ranges::sort(sourceIds);
auto removed = std::ranges::unique(sourceIds);
sourceIds.erase(std::unique(sourceIds.begin(), sourceIds.end()), sourceIds.end()); sourceIds.erase(removed.begin(), removed.end());
return sourceIds; return sourceIds;
} }
std::vector<IdPaths> idPathsForWatcherEntries(WatcherEntries &&foundEntries) std::vector<IdPaths> idPathsForWatcherEntries(WatcherEntries &&foundEntries)
{ {
std::sort(foundEntries.begin(), foundEntries.end(), [](WatcherEntry first, WatcherEntry second) { std::ranges::sort(foundEntries, {}, [](const WatcherEntry &entry) {
return std::tie(first.id, first.sourceId) < std::tie(second.id, second.sourceId); return std::tie(entry.id, entry.sourceId);
}); });
std::vector<IdPaths> idPaths; std::vector<IdPaths> idPaths;
idPaths.reserve(foundEntries.size()); idPaths.reserve(foundEntries.size());
for (WatcherEntry entry : foundEntries) { if (foundEntries.size()) {
if (idPaths.empty() || idPaths.back().id != entry.id) idPaths.emplace_back(foundEntries.front().id, SourceIds{});
idPaths.emplace_back(entry.id, SourceIds{});
idPaths.back().sourceIds.push_back(entry.sourceId); for (WatcherEntry entry : foundEntries) {
if (idPaths.back().id != entry.id)
idPaths.emplace_back(entry.id, SourceIds{});
idPaths.back().sourceIds.push_back(entry.sourceId);
}
} }
return idPaths; return idPaths;

View File

@@ -40,11 +40,15 @@ public:
ProjectPartId id; ProjectPartId id;
SourceType sourceType; SourceType sourceType;
auto operator<=>(const ProjectChunkId &) const = default; auto operator==(const ProjectChunkId &other) const
{
return std::tie(id, sourceType) == std::tie(other.id, other.sourceType);
}
friend bool operator<(ProjectChunkId first, ProjectPartId second) { return first.id < second; } auto operator<=>(const ProjectChunkId &other) const
{
friend bool operator<(ProjectPartId first, ProjectChunkId second) { return first < second.id; } return std::tie(id, sourceType) <=> std::tie(other.id, other.sourceType);
}
template<typename String> template<typename String>
friend void convertToString(String &string, const ProjectChunkId &id) friend void convertToString(String &string, const ProjectChunkId &id)
@@ -112,16 +116,6 @@ public:
<=> std::tie(second.sourceContextId, second.sourceId, second.id); <=> std::tie(second.sourceContextId, second.sourceId, second.id);
} }
friend auto operator<=>(SourceContextId sourceContextId, WatcherEntry entry)
{
return sourceContextId <=> entry.sourceContextId;
}
friend auto operator<=>(WatcherEntry entry, SourceContextId sourceContextId)
{
return entry.sourceContextId <=> sourceContextId;
}
operator SourceId() const { return sourceId; } operator SourceId() const { return sourceId; }
operator SourceContextId() const { return sourceContextId; } operator SourceContextId() const { return sourceContextId; }