From e777ad57c547abe31b457a95a9dc0b5e39891a79 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Wed, 19 Jun 2019 15:34:24 +0200 Subject: Clang: Add reset to ModifiedTimeChecker We can reset some file once to flag a file dirty if the included file has changed. Change-Id: I8763bb80f65882fba4e70057f569234e77097927 Reviewed-by: Tim Jenssen --- src/libs/clangsupport/clangsupport-lib.pri | 1 + src/libs/clangsupport/filestatuscache.cpp | 54 ++------ src/libs/clangsupport/modifiedtimechecker.h | 183 +++++++++------------------- src/libs/clangsupport/set_algorithm.h | 101 +++++++++++++++ src/libs/clangsupport/sourceentry.h | 4 + 5 files changed, 176 insertions(+), 167 deletions(-) create mode 100644 src/libs/clangsupport/set_algorithm.h (limited to 'src/libs') diff --git a/src/libs/clangsupport/clangsupport-lib.pri b/src/libs/clangsupport/clangsupport-lib.pri index 9b6bbdf3ee..dc66408e58 100644 --- a/src/libs/clangsupport/clangsupport-lib.pri +++ b/src/libs/clangsupport/clangsupport-lib.pri @@ -157,6 +157,7 @@ HEADERS += \ $$PWD/refactoringserverinterface.h \ $$PWD/refactoringserverproxy.h \ $$PWD/referencesmessage.h \ + $$PWD/set_algorithm.h \ $$PWD/unsavedfilesupdatedmessage.h \ $$PWD/removeprojectpartsmessage.h \ $$PWD/requestannotationsmessage.h \ diff --git a/src/libs/clangsupport/filestatuscache.cpp b/src/libs/clangsupport/filestatuscache.cpp index 480b745525..e8ed50a833 100644 --- a/src/libs/clangsupport/filestatuscache.cpp +++ b/src/libs/clangsupport/filestatuscache.cpp @@ -26,6 +26,8 @@ #include "filestatuscache.h" #include "filesystem.h" +#include + #include #include @@ -51,49 +53,15 @@ void FileStatusCache::update(FilePathId filePathId) found->lastModified = m_fileSystem.lastModified(filePathId); } -namespace { -template -void set_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)) - callable(*first1++); - ++first2; - } - } -} - -template -void set_difference_call(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, Callable callable) -{ - while (first1 != last1) { - if (first2 == last2) { - std::for_each(first1, last1, callable); - return; - } - if (*first1 < *first2) { - callable(*first1++); - } else { - if (!(*first2 < *first1)) - ++first1; - ++first2; - } - } -} -} // namespace - void FileStatusCache::update(FilePathIds filePathIds) { - set_intersection_call(m_cacheEntries.begin(), + std::set_intersection(m_cacheEntries.begin(), m_cacheEntries.end(), filePathIds.begin(), filePathIds.end(), - [&](auto &entry) { + make_iterator([&](auto &entry) { entry.lastModified = m_fileSystem.lastModified(entry.filePathId); - }); + })); } FilePathIds FileStatusCache::modified(FilePathIds filePathIds) const @@ -101,30 +69,30 @@ FilePathIds FileStatusCache::modified(FilePathIds filePathIds) const FilePathIds modifiedFilePathIds; modifiedFilePathIds.reserve(filePathIds.size()); - set_intersection_call(m_cacheEntries.begin(), + std::set_intersection(m_cacheEntries.begin(), m_cacheEntries.end(), filePathIds.begin(), filePathIds.end(), - [&](auto &entry) { + make_iterator([&](auto &entry) { auto newLastModified = m_fileSystem.lastModified(entry.filePathId); if (newLastModified > entry.lastModified) { modifiedFilePathIds.push_back(entry.filePathId); entry.lastModified = newLastModified; } - }); + })); Internal::FileStatusCacheEntries newEntries; newEntries.reserve(filePathIds.size()); - set_difference_call(filePathIds.begin(), + std::set_difference(filePathIds.begin(), filePathIds.end(), m_cacheEntries.begin(), m_cacheEntries.end(), - [&](FilePathId newFilePathId) { + make_iterator([&](FilePathId newFilePathId) { newEntries.emplace_back(newFilePathId, m_fileSystem.lastModified(newFilePathId)); modifiedFilePathIds.push_back(newFilePathId); - }); + })); if (newEntries.size()) { Internal::FileStatusCacheEntries mergedEntries; diff --git a/src/libs/clangsupport/modifiedtimechecker.h b/src/libs/clangsupport/modifiedtimechecker.h index 9247933b18..00e8e3ebac 100644 --- a/src/libs/clangsupport/modifiedtimechecker.h +++ b/src/libs/clangsupport/modifiedtimechecker.h @@ -25,24 +25,23 @@ #pragma once -#include "clangpathwatcher.h" -#include "filepathcachinginterface.h" +#include "filesysteminterface.h" #include "modifiedtimecheckerinterface.h" +#include "set_algorithm.h" #include #include namespace ClangBackEnd { + template class ModifiedTimeChecker final : public ModifiedTimeCheckerInterface { using SourceEntry = typename SourceEntries::value_type; public: - using GetModifiedTime = std::function; - ModifiedTimeChecker(GetModifiedTime &getModifiedTime, FilePathCachingInterface &filePathCache) - : m_getModifiedTime(getModifiedTime) - , m_filePathCache(filePathCache) + ModifiedTimeChecker(FileSystemInterface &fileSystem) + : m_fileSystem(fileSystem) {} bool isUpToDate(const SourceEntries &sourceEntries) const @@ -52,165 +51,101 @@ public: updateCurrentSourceTimeStamps(sourceEntries); - return compareEntries(sourceEntries); + return compareEntries(sourceEntries) && notReseted(sourceEntries); } void pathsChanged(const FilePathIds &filePathIds) override { - using SourceTimeStampReferences = std::vector>; - - SourceTimeStampReferences timeStampsToUpdate; - timeStampsToUpdate.reserve(filePathIds.size()); - std::set_intersection(m_currentSourceTimeStamps.begin(), m_currentSourceTimeStamps.end(), filePathIds.begin(), filePathIds.end(), - std::back_inserter(timeStampsToUpdate)); + make_iterator([&](SourceTimeStamp &sourceTimeStamp) { + sourceTimeStamp.timeStamp = m_fileSystem.lastModified( + sourceTimeStamp.sourceId); + })); + } + + void reset(const FilePathIds &filePathIds) + { + FilePathIds newResetFilePathIds; + newResetFilePathIds.reserve(newResetFilePathIds.size() + m_resetFilePathIds.size()); + + std::set_union(m_resetFilePathIds.begin(), + m_resetFilePathIds.end(), + filePathIds.begin(), + filePathIds.end(), + std::back_inserter(newResetFilePathIds)); - for (SourceTimeStamp &sourceTimeStamp : timeStampsToUpdate) { - sourceTimeStamp.timeStamp = m_getModifiedTime( - m_filePathCache.filePath(sourceTimeStamp.sourceId)); - } + m_resetFilePathIds = std::move(newResetFilePathIds); } private: bool compareEntries(const SourceEntries &sourceEntries) const { - class CompareSourceId - { - public: - bool operator()(SourceTimeStamp first, SourceTimeStamp second) - { - return first.sourceId < second.sourceId; - } - - bool operator()(::ClangBackEnd::SourceEntry first, ::ClangBackEnd::SourceEntry second) - { - return first.sourceId < second.sourceId; - } - - bool operator()(SourceTimeStamp first, ::ClangBackEnd::SourceEntry second) - { - return first.sourceId < second.sourceId; - } - - bool operator()(::ClangBackEnd::SourceEntry first, SourceTimeStamp second) - { - return first.sourceId < second.sourceId; - } - }; - - SourceTimeStamps currentSourceTimeStamp; - currentSourceTimeStamp.reserve(sourceEntries.size()); - std::set_intersection(m_currentSourceTimeStamps.begin(), - m_currentSourceTimeStamps.end(), - sourceEntries.begin(), - sourceEntries.end(), - std::back_inserter(currentSourceTimeStamp), - CompareSourceId{}); - - class CompareTime - { - public: - bool operator()(SourceTimeStamp first, SourceTimeStamp second) - { - return first.timeStamp <= second.timeStamp; - } - - bool operator()(::ClangBackEnd::SourceEntry first, ::ClangBackEnd::SourceEntry second) - { - return first.timeStamp <= second.timeStamp; - } - - bool operator()(SourceTimeStamp first, ::ClangBackEnd::SourceEntry second) - { - return first.timeStamp <= second.timeStamp; - } - - bool operator()(::ClangBackEnd::SourceEntry first, SourceTimeStamp second) - { - return first.timeStamp <= second.timeStamp; - } - }; - - return std::lexicographical_compare(currentSourceTimeStamp.begin(), - currentSourceTimeStamp.end(), - sourceEntries.begin(), - sourceEntries.end(), - CompareTime{}); + return set_intersection_compare( + m_currentSourceTimeStamps.begin(), + m_currentSourceTimeStamps.end(), + sourceEntries.begin(), + sourceEntries.end(), + [](auto first, auto second) { return second.timeStamp > first.timeStamp; }, + [](auto first, auto second) { return first.sourceId < second.sourceId; }); } void updateCurrentSourceTimeStamps(const SourceEntries &sourceEntries) const { SourceTimeStamps sourceTimeStamps = newSourceTimeStamps(sourceEntries); - for (SourceTimeStamp &newSourceTimeStamp : sourceTimeStamps) { - newSourceTimeStamp.timeStamp = m_getModifiedTime( - m_filePathCache.filePath(newSourceTimeStamp.sourceId)); - } - auto split = sourceTimeStamps.insert(sourceTimeStamps.end(), m_currentSourceTimeStamps.begin(), m_currentSourceTimeStamps.end()); std::inplace_merge(sourceTimeStamps.begin(), split, sourceTimeStamps.end()); - m_currentSourceTimeStamps = sourceTimeStamps; + m_currentSourceTimeStamps = std::move(sourceTimeStamps); } SourceTimeStamps newSourceTimeStamps(const SourceEntries &sourceEntries) const { - SourceEntries newSourceEntries; - newSourceEntries.reserve(sourceEntries.size()); - - class CompareSourceId - { - public: - bool operator()(SourceTimeStamp first, SourceTimeStamp second) - { - return first.sourceId < second.sourceId; - } - - bool operator()(::ClangBackEnd::SourceEntry first, ::ClangBackEnd::SourceEntry second) - { - return first.sourceId < second.sourceId; - } - - bool operator()(SourceTimeStamp first, ::ClangBackEnd::SourceEntry second) - { - return first.sourceId < second.sourceId; - } - - bool operator()(::ClangBackEnd::SourceEntry first, SourceTimeStamp second) - { - return first.sourceId < second.sourceId; - } - }; + SourceTimeStamps newTimeStamps; + newTimeStamps.reserve(sourceEntries.size()); std::set_difference(sourceEntries.begin(), sourceEntries.end(), m_currentSourceTimeStamps.begin(), m_currentSourceTimeStamps.end(), - std::back_inserter(newSourceEntries), - CompareSourceId{}); + make_iterator([&](const SourceEntry &sourceEntry) { + newTimeStamps.emplace_back(sourceEntry.sourceId, + m_fileSystem.lastModified( + sourceEntry.sourceId)); + }), + [](auto first, auto second) { + return first.sourceId < second.sourceId && first.timeStamp > 0; + }); - SourceTimeStamps newTimeStamps; - newTimeStamps.reserve(newSourceEntries.size()); + return newTimeStamps; + } - std::transform(newSourceEntries.begin(), - newSourceEntries.end(), - std::back_inserter(newTimeStamps), - [](SourceEntry entry) { - return SourceTimeStamp{entry.sourceId, {}}; - }); + bool notReseted(const SourceEntries &sourceEntries) const + { + auto oldSize = m_resetFilePathIds.size(); + FilePathIds newResetFilePathIds; + newResetFilePathIds.reserve(newResetFilePathIds.size()); - return newTimeStamps; + std::set_difference(m_resetFilePathIds.begin(), + m_resetFilePathIds.end(), + sourceEntries.begin(), + sourceEntries.end(), + std::back_inserter(newResetFilePathIds)); + + m_resetFilePathIds = std::move(newResetFilePathIds); + + return oldSize == m_resetFilePathIds.size(); } private: mutable SourceTimeStamps m_currentSourceTimeStamps; - GetModifiedTime &m_getModifiedTime; - FilePathCachingInterface &m_filePathCache; + mutable FilePathIds m_resetFilePathIds; + FileSystemInterface &m_fileSystem; }; } // namespace ClangBackEnd diff --git a/src/libs/clangsupport/set_algorithm.h b/src/libs/clangsupport/set_algorithm.h new file mode 100644 index 0000000000..39bd3a2055 --- /dev/null +++ b/src/libs/clangsupport/set_algorithm.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include + +namespace ClangBackEnd { + +template +class function_output_iterator +{ +public: + typedef std::output_iterator_tag iterator_category; + typedef void value_type; + typedef void difference_type; + typedef void pointer; + typedef void reference; + + explicit function_output_iterator() {} + + explicit function_output_iterator(const Callable &callable) + : m_callable(&callable) + {} + + function_output_iterator &operator=(const function_output_iterator &iterator) + { + m_callable = iterator.m_callable; + + return *this; + } + + struct helper + { + helper(const Callable *callable) + : m_callable(callable) + {} + template + helper &operator=(T &&value) + { + (*m_callable)(std::forward(value)); + return *this; + } + const Callable *m_callable; + }; + + helper operator*() { return helper(m_callable); } + function_output_iterator &operator++() { return *this; } + function_output_iterator &operator++(int) { return *this; } + +private: + const Callable *m_callable; +}; + +template +function_output_iterator make_iterator(const Callable &callable) +{ + return function_output_iterator(callable); +} + +template +bool set_intersection_compare( + InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, Callable call, Compare comp) +{ + while (first1 != last1 && first2 != last2) { + if (comp(*first1, *first2)) { + ++first1; + } else { + if (!comp(*first2, *first1)) { + if (call(*first2, *first1++)) + return false; + } + ++first2; + } + } + + return true; +} +} // namespace ClangBackEnd diff --git a/src/libs/clangsupport/sourceentry.h b/src/libs/clangsupport/sourceentry.h index c593f1fcd3..5e8769d14f 100644 --- a/src/libs/clangsupport/sourceentry.h +++ b/src/libs/clangsupport/sourceentry.h @@ -131,6 +131,10 @@ public: return first.sourceId < second.sourceId; } + friend bool operator<(SourceEntry first, FilePathId second) { return first.sourceId < second; } + + friend bool operator<(FilePathId first, SourceEntry second) { return first < second.sourceId; } + friend bool operator==(SourceEntry first, SourceEntry second) { return first.sourceId == second.sourceId && first.sourceType == second.sourceType -- cgit v1.2.3