diff options
Diffstat (limited to 'src/libs/clangsupport/clangpathwatcher.h')
-rw-r--r-- | src/libs/clangsupport/clangpathwatcher.h | 214 |
1 files changed, 124 insertions, 90 deletions
diff --git a/src/libs/clangsupport/clangpathwatcher.h b/src/libs/clangsupport/clangpathwatcher.h index dab52996c2..7a7d6ccfcf 100644 --- a/src/libs/clangsupport/clangpathwatcher.h +++ b/src/libs/clangsupport/clangpathwatcher.h @@ -1,4 +1,4 @@ -/**************************************************************************** +; /**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ @@ -27,71 +27,94 @@ #include "clangpathwatcherinterface.h" #include "clangpathwatchernotifier.h" -#include "changedfilepathcompressor.h" +#include "directorypathcompressor.h" #include "filepathcachinginterface.h" +#include "filesystem.h" #include "stringcache.h" +#include <utils/algorithm.h> + #include <QTimer> namespace ClangBackEnd { +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++); + } + } +} + class WatcherEntry { public: ProjectPartId id; - FilePathId pathId; + DirectoryPathId directoryPathId; + FilePathId filePathId; + long long lastModified = -1; friend bool operator==(WatcherEntry first, WatcherEntry second) { - return first.id == second.id && first.pathId == second.pathId; + return first.id == second.id && first.directoryPathId == second.directoryPathId + && first.filePathId == second.filePathId; } friend bool operator<(WatcherEntry first, WatcherEntry second) { - return std::tie(first.pathId, first.id) < std::tie(second.pathId, second.id); + return std::tie(first.directoryPathId, first.filePathId, first.id) + < std::tie(second.directoryPathId, second.filePathId, second.id); } - friend bool operator<(WatcherEntry entry, FilePathId pathId) + friend bool operator<(DirectoryPathId directoryPathId, WatcherEntry entry) { - return entry.pathId < pathId; + return directoryPathId < entry.directoryPathId; } - friend bool operator<(FilePathId pathId, WatcherEntry entry) + friend bool operator<(WatcherEntry entry, DirectoryPathId directoryPathId) { - return pathId < entry.pathId; + return entry.directoryPathId < directoryPathId; } - operator FilePathId() const - { - return pathId; - } + operator FilePathId() const { return filePathId; } + + operator DirectoryPathId() const { return directoryPathId; } }; using WatcherEntries = std::vector<WatcherEntry>; -template <typename FileSystemWatcher, - typename Timer> +template<typename FileSystemWatcher, typename Timer> class CLANGSUPPORT_GCCEXPORT ClangPathWatcher : public ClangPathWatcherInterface { public: ClangPathWatcher(FilePathCachingInterface &pathCache, - ClangPathWatcherNotifier *notifier=nullptr) - : m_changedFilePathCompressor(pathCache), - m_pathCache(pathCache), - m_notifier(notifier) + FileSystemInterface &fileSystem, + ClangPathWatcherNotifier *notifier = nullptr) + : m_pathCache(pathCache) + , m_fileStatusCache(fileSystem) + , m_fileSystem(fileSystem) + , m_notifier(notifier) { QObject::connect(&m_fileSystemWatcher, - &FileSystemWatcher::fileChanged, - [&] (const QString &filePath) { compressChangedFilePath(filePath); }); + &FileSystemWatcher::directoryChanged, + [&](const QString &path) { compressChangedDirectoryPath(path); }); - m_changedFilePathCompressor.setCallback([&] (ClangBackEnd::FilePathIds &&filePathIds) { - addChangedPathForFilePath(std::move(filePathIds)); + m_directoryPathCompressor.setCallback([&](ClangBackEnd::DirectoryPathIds &&directoryPathIds) { + addChangedPathForFilePath(std::move(directoryPathIds)); }); } ~ClangPathWatcher() { - m_changedFilePathCompressor.setCallback([&] (FilePathIds &&) {}); + m_directoryPathCompressor.setCallback([&](DirectoryPathIds &&) {}); } void updateIdPaths(const std::vector<IdPaths> &idPaths) override @@ -109,7 +132,7 @@ public: auto filteredPaths = filterNotWatchedPaths(removedEntries); if (!filteredPaths.empty()) - m_fileSystemWatcher.removePaths(convertWatcherEntriesToQStringList(filteredPaths)); + m_fileSystemWatcher.removePaths(convertWatcherEntriesToDirectoryPathList(filteredPaths)); } void setNotifier(ClangPathWatcherNotifier *notifier) override @@ -164,7 +187,13 @@ public: outputIterator = std::transform(idPath.filePathIds.begin(), idPath.filePathIds.end(), outputIterator, - [&] (FilePathId pathId) { return WatcherEntry{id, pathId}; }); + [&](FilePathId filePathId) { + return WatcherEntry{ + id, + m_pathCache.directoryPathId(filePathId), + filePathId, + m_fileStatusCache.lastModifiedTime(filePathId)}; + }); } std::sort(entries.begin(), entries.end()); @@ -182,7 +211,7 @@ public: mergeToWatchedEntries(newEntries); if (!filteredPaths.empty()) - m_fileSystemWatcher.addPaths(convertWatcherEntriesToQStringList(filteredPaths)); + m_fileSystemWatcher.addPaths(convertWatcherEntriesToDirectoryPathList(filteredPaths)); } void removeUnusedEntries(const WatcherEntries &entries, const ProjectPartIds &ids) @@ -194,33 +223,31 @@ public: auto filteredPaths = filterNotWatchedPaths(oldEntries); if (!filteredPaths.empty()) - m_fileSystemWatcher.removePaths(convertWatcherEntriesToQStringList(filteredPaths)); + m_fileSystemWatcher.removePaths(convertWatcherEntriesToDirectoryPathList(filteredPaths)); } - FileSystemWatcher &fileSystemWatcher() + FileSystemWatcher &fileSystemWatcher() { return m_fileSystemWatcher; } + + QStringList convertWatcherEntriesToDirectoryPathList(const DirectoryPathIds &directoryPathIds) const { - return m_fileSystemWatcher; + return Utils::transform<QStringList>(directoryPathIds, [&](DirectoryPathId id) { + return QString(m_pathCache.directoryPath(id)); + }); } - QStringList convertWatcherEntriesToQStringList( - const WatcherEntries &watcherEntries) + QStringList convertWatcherEntriesToDirectoryPathList(const WatcherEntries &watcherEntries) const { - QStringList paths; - paths.reserve(int(watcherEntries.size())); + DirectoryPathIds directoryPathIds = Utils::transform<DirectoryPathIds>( + watcherEntries, [&](WatcherEntry entry) { return entry.directoryPathId; }); - std::transform(watcherEntries.begin(), - watcherEntries.end(), - std::back_inserter(paths), - [&] (WatcherEntry entry) { - return QString(m_pathCache.filePath(entry.pathId).path()); - }); + std::sort(directoryPathIds.begin(), directoryPathIds.end()); + directoryPathIds.erase(std::unique(directoryPathIds.begin(), directoryPathIds.end()), + directoryPathIds.end()); - return paths; + return convertWatcherEntriesToDirectoryPathList(directoryPathIds); } - template <typename Compare> - WatcherEntries notWatchedEntries(const WatcherEntries &entries, - Compare compare) const + WatcherEntries notWatchedEntries(const WatcherEntries &entries) const { WatcherEntries notWatchedEntries; notWatchedEntries.reserve(entries.size()); @@ -229,24 +256,23 @@ public: entries.end(), m_watchedEntries.cbegin(), m_watchedEntries.cend(), - std::back_inserter(notWatchedEntries), - compare); + std::back_inserter(notWatchedEntries)); return notWatchedEntries; } - WatcherEntries notWatchedEntries(const WatcherEntries &entries) const + DirectoryPathIds notWatchedPaths(const DirectoryPathIds &ids) const { - return notWatchedEntries(entries, std::less<WatcherEntry>()); - } + DirectoryPathIds notWatchedDirectoryIds; + notWatchedDirectoryIds.reserve(ids.size()); - WatcherEntries notWatchedPaths(const WatcherEntries &entries) const - { - auto compare = [] (WatcherEntry first, WatcherEntry second) { - return first.pathId < second.pathId; - }; + std::set_difference(ids.begin(), + ids.end(), + m_watchedEntries.cbegin(), + m_watchedEntries.cend(), + std::back_inserter(notWatchedDirectoryIds)); - return notWatchedEntries(entries, compare); + return notWatchedDirectoryIds; } template <typename Compare> @@ -297,25 +323,24 @@ public: m_watchedEntries = std::move(newWatchedEntries); } - static - WatcherEntries uniquePaths(const WatcherEntries &pathEntries) + static DirectoryPathIds uniquePaths(const WatcherEntries &pathEntries) { - WatcherEntries uniqueEntries; - uniqueEntries.reserve(pathEntries.size()); + DirectoryPathIds uniqueDirectoryIds; + uniqueDirectoryIds.reserve(pathEntries.size()); - auto compare = [] (WatcherEntry first, WatcherEntry second) { - return first.pathId == second.pathId; + auto compare = [](WatcherEntry first, WatcherEntry second) { + return first.directoryPathId == second.directoryPathId; }; std::unique_copy(pathEntries.begin(), pathEntries.end(), - std::back_inserter(uniqueEntries), + std::back_inserter(uniqueDirectoryIds), compare); - return uniqueEntries; + return uniqueDirectoryIds; } - WatcherEntries filterNotWatchedPaths(const WatcherEntries &entries) + DirectoryPathIds filterNotWatchedPaths(const WatcherEntries &entries) const { return notWatchedPaths(uniquePaths(entries)); } @@ -351,40 +376,48 @@ public: oldEntries.end(), std::back_inserter(newWatchedEntries)); - - m_watchedEntries = newWatchedEntries; + m_watchedEntries = std::move(newWatchedEntries); } - void compressChangedFilePath(const QString &filePath) + void compressChangedDirectoryPath(const QString &path) { - m_changedFilePathCompressor.addFilePath(filePath); + m_directoryPathCompressor.addDirectoryPathId( + m_pathCache.directoryPathId(Utils::PathString{path})); } - WatcherEntries watchedEntriesForPaths(ClangBackEnd::FilePathIds &&filePathIds) + WatcherEntries watchedEntriesForPaths(ClangBackEnd::DirectoryPathIds &&directoryPathIds) { WatcherEntries foundEntries; - foundEntries.reserve(filePathIds.size()); - - for (FilePathId pathId : filePathIds) { - auto range = std::equal_range(m_watchedEntries.begin(), m_watchedEntries.end(), pathId); - foundEntries.insert(foundEntries.end(), range.first, range.second); - } + foundEntries.reserve(m_watchedEntries.size()); + + set_greedy_intersection_call(m_watchedEntries.begin(), + m_watchedEntries.end(), + directoryPathIds.begin(), + directoryPathIds.end(), + [&](WatcherEntry &entry) { + m_fileStatusCache.update(entry.filePathId); + auto currentLastModified = m_fileStatusCache.lastModifiedTime( + entry.filePathId); + if (entry.lastModified < currentLastModified) { + foundEntries.push_back(entry); + entry.lastModified = currentLastModified; + } + }); return foundEntries; } - FilePathIds watchedPaths(const FilePathIds &filePathIds) const + FilePathIds watchedPaths(const WatcherEntries &entries) const { - FilePathIds watchedFilePathIds; - watchedFilePathIds.reserve(filePathIds.size()); + auto filePathIds = Utils::transform<FilePathIds>(entries, [](WatcherEntry entry) { + return entry.filePathId; + }); + + std::sort(filePathIds.begin(), filePathIds.end()); - std::set_intersection(m_watchedEntries.begin(), - m_watchedEntries.end(), - filePathIds.begin(), - filePathIds.end(), - std::back_inserter(watchedFilePathIds)); + filePathIds.erase(std::unique(filePathIds.begin(), filePathIds.end()), filePathIds.end()); - return watchedFilePathIds; + return filePathIds; } ProjectPartIds idsForWatcherEntries(const WatcherEntries &foundEntries) @@ -403,21 +436,20 @@ public: ProjectPartIds uniqueIds(ProjectPartIds &&ids) { std::sort(ids.begin(), ids.end()); - auto newEnd = std::unique(ids.begin(), ids.end()); - ids.erase(newEnd, ids.end()); + ids.erase(std::unique(ids.begin(), ids.end()), ids.end()); return std::move(ids); } - void addChangedPathForFilePath(FilePathIds &&filePathIds) + void addChangedPathForFilePath(DirectoryPathIds &&directoryPathIds) { if (m_notifier) { - WatcherEntries foundEntries = watchedEntriesForPaths(std::move(filePathIds)); + WatcherEntries foundEntries = watchedEntriesForPaths(std::move(directoryPathIds)); ProjectPartIds changedIds = idsForWatcherEntries(foundEntries); m_notifier->pathsWithIdsChanged(uniqueIds(std::move(changedIds))); - m_notifier->pathsChanged(watchedPaths(filePathIds)); + m_notifier->pathsChanged(watchedPaths(foundEntries)); } } @@ -428,10 +460,12 @@ public: private: WatcherEntries m_watchedEntries; - ChangedFilePathCompressor<Timer> m_changedFilePathCompressor; FileSystemWatcher m_fileSystemWatcher; + FileStatusCache m_fileStatusCache; + FileSystemInterface &m_fileSystem; FilePathCachingInterface &m_pathCache; ClangPathWatcherNotifier *m_notifier; + DirectoryPathCompressor<Timer> m_directoryPathCompressor; }; } // namespace ClangBackEnd |